1 package SL::BackgroundJob::ShopPartMassCreate;
5 use parent qw(SL::BackgroundJob::Base);
7 use List::Util qw(first);
8 use File::MimeInfo::Magic; # for mimetype
9 use File::Slurp; # for read_file
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);
28 my ($part_id, $shop_id) = @_;
29 my $exists = SL::DB::Manager::ShopPart->find_by( part_id => $part_id, shop_id => $shop_id );
33 return SL::DB::ShopPart->new( part_id => $part_id, shop_id => $shop_id );
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);
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},
51 return \@shop_categories;
54 sub sanitize_filename {
56 $filename =~ s/\W/_/g;
61 my ($messages, $message) = @_;
62 $main::lxdebug->message(LXDebug::WARN(), $message);
63 push @$messages, $message;
67 my ($self, $db_obj) = @_;
68 my $data = $db_obj->data_as_hash;
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';
78 my $shop_config = SL::DB::Manager::Shop->get_first( query => [ id => $shop_id ] );
79 my $shop = SL::Shop->new( config => $shop_config );
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';
86 my $categories_shopdata = $shop->connector->get_categories();
87 if (!$categories_shopdata) {
88 return 'Error: could not get categories from shop';
91 # generate a hash of the category names and their ids
92 my %categories_by_names;
93 recurse_categories($categories_shopdata, \%categories_by_names);
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 ]);
99 for my $part (@{ $parts }) {
101 # check if shop part already exists
102 my $shop_part = get_shop_part($part->id, $shop_id);
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 };
109 my $shop_categories = get_shop_categories($cvar_categories->{value}, \%categories_by_names);
111 $shop_part->assign_attributes(
112 shop_description => '',
115 shop_category => $shop_categories,
116 active_price_source => 'master_data/sellprice',
117 metatag_keywords => '',
118 metatag_description => '',
123 $main::lxdebug->message(LXDebug->DEBUG1(), 'Shop part saved: ' . $shop_part->id);
125 if (!$shop_part->id) {
126 _warn(\@messages, 'Warning: shop part not saved, part id: ' . $part->id . ' part number: ' . $part->partnumber);
131 # the file names are under part->image
134 # go to next part if no images are found
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' ] );
141 my %images_by_names = map { $_->{file_name} => $_ } @{ $image_files };
143 for my $image_name (split '\|', $part->image) {
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)
153 my $image_path = $images_import_path . $image_name;
155 # uses File::MimeInfo::Magic
156 my $mime_type = mimetype($image_path);
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);
163 # read file data into memory
164 my $file_data = File::Slurp::read_file($image_path);
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)),
175 file_contents => $file_data,
176 file_path => $image_path,
179 _warn(\@messages, 'Warning: file not saved for part: ' . $part->id . ' file: ' . $image_name);
185 return join("\n", @messages);
187 return 'Shop parts created successfully';
198 SL::BackgroundJob::ShopPartMassCreate - Background job to create shop
199 parts for all parts in the database that are marked as shop parts.
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.
206 It can also import images from a directory and assign them to the respective
207 shop parts. See configuration below.
209 It also assigns categories to the shop parts based on a custom variable of the
212 The script may need individual adjustments to fit your specific use case.
216 Accepts the following parameters:
222 The id of the shop to create the shop parts in, defaults to 1
224 =item C<images_import_path>
226 The path to the images to import, defaults to 'shopimages/product/'
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
232 The images themselves should be present in the images_import_path.
234 =item C<cvar_categories>
236 The name of the custom variable that contains the categories, defaults to 'vm_product_categories'
238 Expects the Categories to be set in the custom variable of the part in the following format:
239 Category1|Category2|Category3
241 Categories should be present in the shop under the same names.
247 Cem Aydin E<lt>cem.aydin@revamp-it.chE<gt>