Revision 4c50d0e0
Von Cem Aydin vor 4 Monaten hinzugefügt
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 _warn { |
|
55 |
my ($messages, $message) = @_; |
|
56 |
$main::lxdebug->message(LXDebug::WARN(), $message); |
|
57 |
push @$messages, $message; |
|
58 |
} |
|
59 |
|
|
60 |
sub run { |
|
61 |
my ($self, $db_obj) = @_; |
|
62 |
my $data = $db_obj->data_as_hash; |
|
63 |
|
|
64 |
# get parameters |
|
65 |
my $shop_id = $data->{shop_id} || 1; |
|
66 |
my $images_import_path = $data->{images_import_path} || 'shopimages/product/'; |
|
67 |
my $cvar_categories = $data->{cvar_categories} || 'vm_product_categories'; |
|
68 |
|
|
69 |
my @messages; |
|
70 |
|
|
71 |
# initialize shop |
|
72 |
my $shop_config = SL::DB::Manager::Shop->get_first( query => [ id => $shop_id ] ); |
|
73 |
my $shop = SL::Shop->new( config => $shop_config ); |
|
74 |
|
|
75 |
# get the categories from the shop |
|
76 |
my $connect = $shop->check_connectivity; |
|
77 |
if (!$connect->{success}) { |
|
78 |
return 'Error: could not connect to shop'; |
|
79 |
} |
|
80 |
my $categories_shopdata = $shop->connector->get_categories(); |
|
81 |
if (!$categories_shopdata) { |
|
82 |
return 'Error: could not get categories from shop'; |
|
83 |
} |
|
84 |
|
|
85 |
# generate a hash of the category names and their ids |
|
86 |
my %categories_by_names; |
|
87 |
recurse_categories($categories_shopdata, \%categories_by_names); |
|
88 |
|
|
89 |
# get all the parts from the database, that are marked as shop parts |
|
90 |
my $parts = SL::DB::Manager::Part->get_all(query => [ shop => 1 ]); |
|
91 |
|
|
92 |
# for every part |
|
93 |
for my $part (@{ $parts }) { |
|
94 |
|
|
95 |
# check if shop part already exists |
|
96 |
my $shop_part = get_shop_part($part->id, $shop_id); |
|
97 |
|
|
98 |
# get the custom variables from the part |
|
99 |
my $cvars = CVar->get_custom_variables(module => 'IC', trans_id => $part->id); |
|
100 |
my $cvar_categories = first { $_->{name} eq $cvar_categories } @{ $cvars }; |
|
101 |
|
|
102 |
# assign categories |
|
103 |
my $shop_categories = get_shop_categories($cvar_categories->{value}, \%categories_by_names); |
|
104 |
|
|
105 |
$shop_part->assign_attributes( |
|
106 |
shop_description => '', |
|
107 |
front_page => '', |
|
108 |
active => 1, |
|
109 |
shop_category => $shop_categories, |
|
110 |
active_price_source => 'master_data/sellprice', |
|
111 |
metatag_keywords => '', |
|
112 |
metatag_description => '', |
|
113 |
metatag_title => '', |
|
114 |
); |
|
115 |
|
|
116 |
$shop_part->save; |
|
117 |
$main::lxdebug->message(LXDebug->DEBUG1(), 'Shop part saved: ' . $shop_part->id); |
|
118 |
|
|
119 |
if (!$shop_part->id) { |
|
120 |
_warn(\@messages, 'Warning: shop part not saved, part id: ' . $part->id . ' part number: ' . $part->partnumber); |
|
121 |
next; |
|
122 |
} |
|
123 |
|
|
124 |
# handle the images, |
|
125 |
# the file names are under part->image |
|
126 |
|
|
127 |
if (!$part->image) { |
|
128 |
# go to next part if no images are found |
|
129 |
next; |
|
130 |
} |
|
131 |
|
|
132 |
# get existing images from shop part |
|
133 |
my $image_files = SL::DB::Manager::File->get_all( where => [ object_id => $part->id, object_type => 'shop_image' ] ); |
|
134 |
|
|
135 |
my %images_by_names = map { $_->{file_name} => $_ } @{ $image_files }; |
|
136 |
|
|
137 |
for my $image_name (split '\|', $part->image) { |
|
138 |
|
|
139 |
my $fileobj; |
|
140 |
if (exists $images_by_names{$image_name}) { |
|
141 |
# I tried updating the file, but it didn't work right away |
|
142 |
# so instead I delete the file and create a new one |
|
143 |
# (this is also the way it is done in the UI, there's only a delete button, |
|
144 |
# no update button) |
|
145 |
$images_by_names{$image_name}->delete; |
|
146 |
} |
|
147 |
|
|
148 |
my $image_path = $images_import_path . $image_name; |
|
149 |
|
|
150 |
# uses File::MimeInfo::Magic |
|
151 |
my $mime_type = mimetype($image_path); |
|
152 |
|
|
153 |
# check if the file exists |
|
154 |
if (! -e $image_path) { |
|
155 |
_warn(\@messages, 'Warning: image file not found for part: ' . $part->id . ' file: ' . $image_name); |
|
156 |
next; |
|
157 |
} |
|
158 |
# read file data into memory |
|
159 |
my $file_data = File::Slurp::read_file($image_path); |
|
160 |
|
|
161 |
$fileobj = SL::File->save( |
|
162 |
object_id => $part->id, |
|
163 |
object_type => 'shop_image', |
|
164 |
mime_type => $mime_type, |
|
165 |
source => 'uploaded', |
|
166 |
file_type => 'image', |
|
167 |
file_name => $image_name, |
|
168 |
title => substr($part->description, 0, 45), |
|
169 |
description => '', |
|
170 |
file_contents => $file_data, |
|
171 |
file_path => $image_path, |
|
172 |
); |
|
173 |
if (!$fileobj) { |
|
174 |
_warn(\@messages, 'Warning: file not saved for part: ' . $part->id . ' file: ' . $image_name); |
|
175 |
} |
|
176 |
} |
|
177 |
} |
|
178 |
|
|
179 |
if (@messages) { |
|
180 |
return join("\n", @messages); |
|
181 |
} |
|
182 |
return 'Shop parts created successfully'; |
|
183 |
} |
|
184 |
|
|
185 |
1; |
|
186 |
|
|
187 |
__END__ |
|
188 |
|
|
189 |
=encoding utf8 |
|
190 |
|
|
191 |
=head1 NAME |
|
192 |
|
|
193 |
SL::BackgroundJob::ShopPartMassCreate - Background job to create shop |
|
194 |
parts for all parts in the database that are marked as shop parts. |
|
195 |
|
|
196 |
=head1 SYNOPSIS |
|
197 |
|
|
198 |
This background job provides the basic functionality to create shop parts for |
|
199 |
all parts in the database that are marked as shop parts. |
|
200 |
|
|
201 |
It can also import images from a directory and assign them to the respective |
|
202 |
shop parts. See configuration below. |
|
203 |
|
|
204 |
It also assigns categories to the shop parts based on a custom variable of the |
|
205 |
part. |
|
206 |
|
|
207 |
The script may need individual adjustments to fit your specific use case. |
|
208 |
|
|
209 |
=head1 CONFIGURATION |
|
210 |
|
|
211 |
Accepts the following parameters: |
|
212 |
|
|
213 |
=over 4 |
|
214 |
|
|
215 |
=item C<shop_id> |
|
216 |
|
|
217 |
The id of the shop to create the shop parts in, defaults to 1 |
|
218 |
|
|
219 |
=item C<images_import_path> |
|
220 |
|
|
221 |
The path to the images to import, defaults to 'shopimages/product/' |
|
222 |
|
|
223 |
The file names of the images should be present in the 'image' field of the part, |
|
224 |
in the following format: |
|
225 |
image1.jpg|image2.png|image3.gif |
|
226 |
|
|
227 |
The images themselves should be present in the images_import_path. |
|
228 |
|
|
229 |
=item C<cvar_categories> |
|
230 |
|
|
231 |
The name of the custom variable that contains the categories, defaults to 'vm_product_categories' |
|
232 |
|
|
233 |
Expects the Categories to be set in the custom variable of the part in the following format: |
|
234 |
Category1|Category2|Category3 |
|
235 |
|
|
236 |
Categories should be present in the shop under the same names. |
|
237 |
|
|
238 |
=back |
|
239 |
|
|
240 |
=head1 AUTHOR |
|
241 |
|
|
242 |
Cem Aydin E<lt>cem.aydin@revamp-it.chE<gt> |
|
243 |
|
|
244 |
=cut |
Auch abrufbar als: Unified diff
Neuer Backgroundjob zum Massen-generieren von Shop Artikeln aus Artikeln