]> wagnertech.de Git - mfinanz.git/blob - SL/BackgroundJob/ShopPartMassCreate.pm
date error in mapping
[mfinanz.git] / SL / BackgroundJob / ShopPartMassCreate.pm
1 package SL::BackgroundJob::ShopPartMassCreate;
2
3 use strict;
4
5 use parent qw(SL::BackgroundJob::Base);
6
7 use List::Util qw(first);
8 use File::MimeInfo::Magic; # for mimetype
9 use File::Slurp; # for read_file
10
11 use SL::Shop;
12 use SL::DB::Part;
13 use SL::DB::ShopPart;
14 use SL::DB::File;
15 use SL::CVar;
16 use SL::File;
17 use SL::LXDebug;
18
19 sub recurse_categories {
20   my ($categories, $categories_by_names) = @_;
21   foreach my $category (@{ $categories }) {
22     ${ $categories_by_names }{$category->{name}} = $category->{id};
23     recurse_categories($category->{children}, $categories_by_names);
24   }
25 }
26
27 sub get_shop_part {
28   my ($part_id, $shop_id) = @_;
29   my $exists = SL::DB::Manager::ShopPart->find_by( part_id => $part_id, shop_id => $shop_id );
30   if ($exists) {
31     return $exists;
32   }
33   return SL::DB::ShopPart->new( part_id => $part_id, shop_id => $shop_id );
34 }
35
36 sub get_shop_categories {
37   my ($cvar_categories, $categories_by_names) = @_;
38   # split on the pipe character
39   my @categories_names = split(/\|/, $cvar_categories);
40
41   my @shop_categories;
42   foreach my $category_name (@categories_names) {
43     # if the category exists in the shop
44     if (exists $categories_by_names->{$category_name}) {
45       push @shop_categories, [
46         $categories_by_names->{$category_name},
47         $category_name
48       ];
49     }
50   }
51   return \@shop_categories;
52 }
53
54 sub sanitize_filename {
55     my ($filename) = @_;
56     $filename =~ s/\W/_/g;
57     return $filename;
58 }
59
60 sub _warn {
61   my ($messages, $message) = @_;
62   $main::lxdebug->message(LXDebug::WARN(), $message);
63   push @$messages, $message;
64 }
65
66 sub run {
67   my ($self, $db_obj)     = @_;
68   my $data       = $db_obj->data_as_hash;
69
70   # get parameters
71   my $shop_id = $data->{shop_id} || 1;
72   my $images_import_path = $data->{images_import_path} || 'shopimages/product/';
73   my $cvar_categories = $data->{cvar_categories} || 'vm_product_categories';
74
75   my @messages;
76
77   # initialize shop
78   my $shop_config = SL::DB::Manager::Shop->get_first( query => [ id => $shop_id ] );
79   my $shop = SL::Shop->new( config => $shop_config );
80
81   # get the categories from the shop
82   my $connect = $shop->check_connectivity;
83   if (!$connect->{success}) {
84     return 'Error: could not connect to shop';
85   }
86   my $categories_shopdata = $shop->connector->get_categories();
87   if (!$categories_shopdata) {
88     return 'Error: could not get categories from shop';
89   }
90
91   # generate a hash of the category names and their ids
92   my %categories_by_names;
93   recurse_categories($categories_shopdata, \%categories_by_names);
94
95   # get all the parts from the database, that are marked as shop parts
96   my $parts = SL::DB::Manager::Part->get_all(query => [ shop => 1 ]);
97
98   # for every part
99   for my $part (@{ $parts }) {
100
101     # check if shop part already exists
102     my $shop_part = get_shop_part($part->id, $shop_id);
103
104     # get the custom variables from the part
105     my $cvars = CVar->get_custom_variables(module => 'IC', trans_id => $part->id);
106     my $cvar_categories = first { $_->{name} eq $cvar_categories } @{ $cvars };
107
108     # assign categories
109     my $shop_categories = get_shop_categories($cvar_categories->{value}, \%categories_by_names);
110
111     $shop_part->assign_attributes(
112       shop_description => '',
113       front_page       => '',
114       active           => 1,
115       shop_category    => $shop_categories,
116       active_price_source => 'master_data/sellprice',
117       metatag_keywords => '',
118       metatag_description => '',
119       metatag_title => '',
120     );
121
122     $shop_part->save;
123     $main::lxdebug->message(LXDebug->DEBUG1(), 'Shop part saved: ' . $shop_part->id);
124
125     if (!$shop_part->id) {
126       _warn(\@messages, 'Warning: shop part not saved, part id: ' . $part->id . ' part number: ' . $part->partnumber);
127       next;
128     }
129
130     # handle the images,
131     # the file names are under part->image
132
133     if (!$part->image) {
134       # go to next part if no images are found
135       next;
136     }
137
138     # get existing images from shop part
139     my $image_files = SL::DB::Manager::File->get_all( where => [ object_id => $part->id, object_type => 'shop_image' ] );
140
141     my %images_by_names = map { $_->{file_name} => $_ } @{ $image_files };
142
143     for my $image_name (split '\|', $part->image) {
144
145       my $fileobj;
146       if (exists $images_by_names{$image_name}) {
147         # I tried updating or deleting the file, but that didn't work
148         # so for now we'll just skip the image if an image with the same name already exists
149         # (atm there doesn't seem to be a mechanism in place to update or delete the files properly)
150         next;
151       }
152
153       my $image_path = $images_import_path . $image_name;
154
155       # uses File::MimeInfo::Magic
156       my $mime_type = mimetype($image_path);
157
158       # check if the file exists
159       if (! -e $image_path) {
160         _warn(\@messages, 'Warning: image file not found for part: ' . $part->id . ' file: ' . $image_name);
161         next;
162       }
163       # read file data into memory
164       my $file_data = File::Slurp::read_file($image_path);
165
166       $fileobj = SL::File->save(
167         object_id        => $part->id,
168         object_type      => 'shop_image',
169         mime_type        => $mime_type,
170         source           => 'uploaded',
171         file_type        => 'image',
172         file_name        => $image_name,
173         title            => sanitize_filename(substr($part->description, 0, 45)),
174         description      => '',
175         file_contents    => $file_data,
176         file_path        => $image_path,
177       );
178       if (!$fileobj) {
179         _warn(\@messages, 'Warning: file not saved for part: ' . $part->id . ' file: ' . $image_name);
180       }
181     }
182   }
183
184   if (@messages) {
185     return join("\n", @messages);
186   }
187   return 'Shop parts created successfully';
188 }
189
190 1;
191
192 __END__
193
194 =encoding utf8
195
196 =head1 NAME
197
198 SL::BackgroundJob::ShopPartMassCreate - Background job to create shop
199 parts for all parts in the database that are marked as shop parts.
200
201 =head1 SYNOPSIS
202
203 This background job provides the basic functionality to create shop parts for
204 all parts in the database that are marked as shop parts.
205
206 It can also import images from a directory and assign them to the respective
207 shop parts. See configuration below.
208
209 It also assigns categories to the shop parts based on a custom variable of the
210 part.
211
212 The script may need individual adjustments to fit your specific use case.
213
214 =head1 CONFIGURATION
215
216 Accepts the following parameters:
217
218 =over 4
219
220 =item C<shop_id>
221
222 The id of the shop to create the shop parts in, defaults to 1
223
224 =item C<images_import_path>
225
226 The path to the images to import, defaults to 'shopimages/product/'
227
228 The file names of the images should be present in the 'image' field of the part,
229 in the following format:
230   image1.jpg|image2.png|image3.gif
231
232 The images themselves should be present in the images_import_path.
233
234 =item C<cvar_categories>
235
236 The name of the custom variable that contains the categories, defaults to 'vm_product_categories'
237
238 Expects the Categories to be set in the custom variable of the part in the following format:
239   Category1|Category2|Category3
240
241 Categories should be present in the shop under the same names.
242
243 =back
244
245 =head1 AUTHOR
246
247 Cem Aydin E<lt>cem.aydin@revamp-it.chE<gt>
248
249 =cut