Revision a1c5130b
Von Tamino Steinert vor 10 Monaten hinzugefügt
scripts/import_variant_csv.pl | ||
---|---|---|
13 | 13 |
|
14 | 14 |
use Data::Dumper; |
15 | 15 |
use List::Util qw(first); |
16 |
use List::MoreUtils qw(any); |
|
16 | 17 |
use File::Basename; |
17 | 18 |
|
18 | 19 |
use SL::DBUtils; |
... | ... | |
93 | 94 |
VK => 'sellprice', |
94 | 95 |
EANNR => 'ean', |
95 | 96 |
EIGENEARTIKELNR => 'description', |
96 |
WAR_KURZBEZEICHNUNG => 'warengruppe', |
|
97 |
WARENGRUPPE => 'warengruppe_nummer', |
|
98 |
WAR_KURZBEZEICHNUNG => 'warengruppe_name', |
|
97 | 99 |
GROESSE => 'varianten_groesse', |
98 | 100 |
LAENGE => 'varianten_laenge', |
99 | 101 |
FARBNR => 'varianten_farbnummer', |
100 | 102 |
INFO1 => 'varianten_farbname', |
101 | 103 |
ARTIKELNR => 'makemodel_model', |
102 |
LIEFERANT => 'vendor_name',
|
|
104 |
LST_ID => 'vendor_number',
|
|
103 | 105 |
FIL_KURZBEZEICHNUNG => 'warehouse_description', |
104 | 106 |
STUECK => 'part_qty', |
105 | 107 |
); |
... | ... | |
152 | 154 |
my $part_hrefs = $part_csv->get_data; |
153 | 155 |
|
154 | 156 |
my %parent_variants_to_variants; |
157 |
my $row = 0; |
|
155 | 158 |
foreach my $part_row (@$part_hrefs) { |
156 | 159 |
my %part = |
157 | 160 |
map {$parts_mapping{$_} => $part_row->{$_}} |
158 | 161 |
grep {$part_row->{$_}} |
159 | 162 |
keys %parts_mapping; |
163 |
$part{csv_row} = $row++; |
|
160 | 164 |
|
161 | 165 |
if ($part{varianten_farbnummer} || $part{varianten_farbname}) { |
162 | 166 |
$part{varianten_farbnummer} ||= ''; |
... | ... | |
164 | 168 |
$part{varianten_farbe} = (delete $part{varianten_farbnummer}) . '-' . (delete $part{varianten_farbname}); |
165 | 169 |
} |
166 | 170 |
|
171 |
if ($part{varianten_groesse}) { |
|
172 |
# map to valid sizes |
|
173 |
unless ($part{warengruppe_nummer} eq '114310' || $part{warengruppe_nummer} eq '124310') { # nicht für gürtel |
|
174 |
$part{varianten_groesse} =~ s/^([0-9][0-9])5$/$1,5/; # 345 -> 34,5 |
|
175 |
} |
|
176 |
$part{varianten_groesse} =~ s/^([0-9][0-9])\.5$/$1,5/; # 34.5 -> 34,5 |
|
177 |
$part{varianten_groesse} =~ s/^2XL$/XXL/; |
|
178 |
$part{varianten_groesse} =~ s/^XXXL$/3XL/; |
|
179 |
$part{varianten_groesse} =~ s/^([0-9]*)½$/$1 ½/; |
|
180 |
$part{varianten_groesse} =~ s/^([0-9]*)\/½$/$1 ½/; |
|
181 |
$part{varianten_groesse} =~ s/^([0-9]*) 1\/2$/$1 ½/; |
|
182 |
$part{varianten_groesse} =~ s/\/U//; # 34/U -> 34 |
|
183 |
$part{varianten_groesse} =~ s/\/I//; # 34/I -> 34 |
|
184 |
$part{varianten_groesse} =~ s/\/M//; # 34/M -> 34 |
|
185 |
$part{varianten_groesse} =~ s/\/L//; # 34/L -> 34 |
|
186 |
$part{varianten_groesse} =~ s/\/XL//; # 34/XL -> 34 |
|
187 |
$part{varianten_groesse} =~ s/\/XX//; # 34/XX -> 34 |
|
188 |
|
|
189 |
if (any {$part{varianten_groesse} eq $_} ('.', '_', 'ONE', 'ONE S', 'ONES', 'OSFA', 'ONESI', 'O/S', 'OSO')) { |
|
190 |
delete $part{varianten_groesse}; |
|
191 |
} |
|
192 |
if ($part{warengruppe_nummer} eq '114415') { # Hosenträger haben keine Größe |
|
193 |
delete $part{varianten_groesse}; |
|
194 |
} |
|
195 |
} |
|
196 |
if ($part{varianten_groesse} && $part{varianten_groesse} =~ m/^([0-9][0-9])([0-9][0-9])$/) { |
|
197 |
my $weite = $1; |
|
198 |
my $laenge = $2; |
|
199 |
$part{varianten_groesse} = $weite; |
|
200 |
$part{varianten_laenge} = $laenge; |
|
201 |
} |
|
202 |
if ($part{varianten_laenge}) { |
|
203 |
if (any {$part{varianten_laenge} eq $_} ('.', 'U')) { |
|
204 |
delete $part{varianten_laenge}; |
|
205 |
} |
|
206 |
} |
|
207 |
|
|
167 | 208 |
push @{$parent_variants_to_variants{$part_row->{LIEFERANT}}->{$part_row->{ARTIKELNR}}}, \%part; |
168 | 209 |
} |
169 | 210 |
|
... | ... | |
193 | 234 |
) or die "Could no find transfer_type"; |
194 | 235 |
|
195 | 236 |
SL::DB->client->with_transaction(sub { |
237 |
my @errors; |
|
196 | 238 |
|
197 | 239 |
# create farben listen |
198 | 240 |
foreach my $farb_csv_file (glob( $opt_farben_folder . '/*' )) { |
... | ... | |
203 | 245 |
quote_char => '"', # default '"' |
204 | 246 |
escape_char => '"', # default '"' |
205 | 247 |
); |
206 |
$farb_csv->parse or die "Could not parse csv"; |
|
248 |
unless ($farb_csv->parse) { |
|
249 |
push @errors, "Could not parse csv '$farb_csv_file'"; |
|
250 |
next; |
|
251 |
} |
|
207 | 252 |
my $farb_hrefs = $farb_csv->get_data; |
208 | 253 |
|
209 | 254 |
my $vendor_name = basename($farb_csv_file); |
... | ... | |
215 | 260 |
abbreviation => "fa", |
216 | 261 |
)->save; |
217 | 262 |
|
263 |
my $pos = 1; |
|
264 |
SL::DB::VariantPropertyValue->new( |
|
265 |
variant_property => $variant_property, |
|
266 |
value => $_->{Joined}, |
|
267 |
abbreviation => $_->{Joined}, |
|
268 |
sortkey => $pos++, |
|
269 |
)->save for @$farb_hrefs; |
|
270 |
} |
|
271 |
|
|
272 |
# create groessen staffeln |
|
273 |
foreach my $groessen_staffel_row (@$groessen_staffel_hrefs) { |
|
274 |
my $name = delete $groessen_staffel_row->{BEZEICHNUNG}; |
|
275 |
my $variant_property = SL::DB::VariantProperty->new( |
|
276 |
name => $name, |
|
277 |
unique_name => $name, |
|
278 |
abbreviation => "gr", |
|
279 |
)->save; |
|
280 |
|
|
218 | 281 |
my $pos = 1; |
219 | 282 |
SL::DB::VariantPropertyValue->new( |
220 | 283 |
variant_property => $variant_property, |
... | ... | |
222 | 285 |
abbreviation => $_, |
223 | 286 |
sortkey => $pos++, |
224 | 287 |
)->save for |
225 |
map {$_->{Joined}} |
|
226 |
@$farb_hrefs; |
|
288 |
map {$groessen_staffel_row->{$_}} |
|
289 |
sort |
|
290 |
grep {defined $groessen_staffel_row->{$_}} |
|
291 |
keys %$groessen_staffel_row; |
|
227 | 292 |
} |
228 | 293 |
|
229 | 294 |
# create partsgroups |
295 |
my %partsgroup_id_to_groessen_staffeln; |
|
230 | 296 |
my @hierachy_descrioptions = qw( |
231 | 297 |
Bereich Hauptabteilung Abteilung Hauptwarengruppe Warengruppe |
232 | 298 |
); |
233 | 299 |
my %current_partsgroup_hierachy; |
234 | 300 |
foreach my $partsgroup_row (@$warengruppen_hrefs) { |
235 |
# TODO: store valid groessen staffeln |
|
236 | 301 |
my $valid_groessen_staffen = delete $partsgroup_row->{Größenstaffeln}; |
237 | 302 |
my $last_hierachy_key; |
238 | 303 |
foreach my $hierachy_key (@hierachy_descrioptions) { |
... | ... | |
240 | 305 |
my ($number, @rest) = split(' ', $partsgroup_row->{$hierachy_key}); |
241 | 306 |
my $name = join(' ', @rest); |
242 | 307 |
unless ($number && $name) { |
243 |
die "Could not find number and name for $hierachy_key partsgroup '".$partsgroup_row->{$hierachy_key}."' in the row:'\n". |
|
244 |
join(';', map {$partsgroup_row->{$_}} @hierachy_descrioptions); |
|
308 |
push @errors, "Could not find number and name for $hierachy_key partsgroup '".$partsgroup_row->{$hierachy_key}."' in the row:'\n". |
|
309 |
join(';', map {$partsgroup_row->{$_}} @hierachy_descrioptions); |
|
310 |
next; |
|
245 | 311 |
} |
246 | 312 |
my $partsgroup = SL::DB::PartsGroup->new( |
247 | 313 |
partsgroup => $name, |
... | ... | |
251 | 317 |
)->save; |
252 | 318 |
$current_partsgroup_hierachy{$hierachy_key} = $partsgroup; |
253 | 319 |
} |
254 |
my $last_hierachy_key = $hierachy_key;
|
|
320 |
$last_hierachy_key = $hierachy_key; |
|
255 | 321 |
} |
322 |
my $last_partsgroup = $current_partsgroup_hierachy{$last_hierachy_key}; |
|
323 |
my @valid_groessen_staffen = |
|
324 |
grep { $_ } |
|
325 |
map { |
|
326 |
my $variant = SL::DB::Manager::VariantProperty->find_by(unique_name => $_); |
|
327 |
push @errors, "Could not find Variant Property '$_' while importing partsgroups." unless $variant; |
|
328 |
$variant; |
|
329 |
} |
|
330 |
grep { $_ ne 'ohne'} |
|
331 |
split(', ', $valid_groessen_staffen); |
|
332 |
$partsgroup_id_to_groessen_staffeln{$last_partsgroup->id} = \@valid_groessen_staffen; |
|
256 | 333 |
} |
257 | 334 |
|
258 |
# create groessen staffeln |
|
259 |
foreach my $groessen_staffel_row (@$groessen_staffel_hrefs) { |
|
260 |
my $name = delete $groessen_staffel_row->{BEZEICHNUNG}; |
|
261 |
my $variant_property = SL::DB::VariantProperty->new( |
|
262 |
name => $name, |
|
263 |
unique_name => $name, |
|
264 |
abbreviation => "gr", |
|
265 |
)->save; |
|
266 |
|
|
267 |
my $pos = 1; |
|
268 |
SL::DB::VariantPropertyValue->new( |
|
269 |
variant_property => $variant_property, |
|
270 |
value => $_, |
|
271 |
abbreviation => $_, |
|
272 |
sortkey => $pos++, |
|
273 |
)->save for |
|
274 |
map {$groessen_staffel_row->{$_}} |
|
275 |
sort |
|
276 |
grep {defined $groessen_staffel_row->{$_}} |
|
277 |
keys %$groessen_staffel_row; |
|
278 |
} |
|
279 |
|
|
280 |
my %partsgroup_name_to_partsgroup = map {lc($_->partsgroup) => $_} @{SL::DB::Manager::PartsGroup->get_all()}; |
|
281 |
my %vendor_name_to_vendor = map {lc($_->name) => $_} @{SL::DB::Manager::Vendor->get_all()}; |
|
335 |
my %partsgroup_number_to_partsgroup = map {my ($number) = split(' ', $_->description); $number => $_} @{SL::DB::Manager::PartsGroup->get_all()}; |
|
336 |
my %vendor_number_to_vendor = map {$_->vendornumber => $_} @{SL::DB::Manager::Vendor->get_all()}; |
|
282 | 337 |
my %warehouse_description_to_warehouse = map {lc($_->description) => $_} @{SL::DB::Manager::Warehouse->get_all()}; |
283 | 338 |
|
284 |
my @all_variant_properties = @{SL::DB::Manager::VariantProperty->get_all()}; |
|
285 | 339 |
# create parts |
286 |
foreach my $vendor (keys %parent_variants_to_variants) { |
|
287 |
foreach my $partnumber (keys %{$parent_variants_to_variants{$vendor}}) { |
|
288 |
my $grouped_variant_values = $parent_variants_to_variants{$vendor}->{$partnumber}; |
|
340 |
foreach my $vendor_kurz_name (keys %parent_variants_to_variants) { |
|
341 |
foreach my $partnumber (keys %{$parent_variants_to_variants{$vendor_kurz_name}}) { |
|
342 |
my $count_errors_at_start = scalar @errors; |
|
343 |
# TODO: logic for |
|
344 |
# bestand anpasen |
|
345 |
# stammartikel da neue variante |
|
346 |
# alles neu |
|
347 |
my $grouped_variant_values = $parent_variants_to_variants{$vendor_kurz_name}->{$partnumber}; |
|
289 | 348 |
|
290 | 349 |
#get data for parent_variant |
291 | 350 |
my $first_part = $grouped_variant_values->[0]; |
292 |
my $description = $first_part->{description}; |
|
293 |
my $partsgroup_name = $first_part->{warengruppe};
|
|
351 |
my $description = $first_part->{description} || '';
|
|
352 |
my $partsgroup_number = $first_part->{warengruppe_nummer};
|
|
294 | 353 |
my $warehouse_description = $first_part->{warehouse_description}; |
295 |
my $vendor_name = $first_part->{vendor_name};
|
|
354 |
my $vendor_number = $first_part->{vendor_number};
|
|
296 | 355 |
my $makemodel_model = $first_part->{makemodel_model}; |
297 | 356 |
my $best_sellprice = first {$_} sort map {$_->{sellprice}} @$grouped_variant_values; |
298 | 357 |
$best_sellprice =~ s/,/./; |
299 |
my $partsgroup = $partsgroup_name_to_partsgroup{lc($partsgroup_name)} or die
|
|
300 |
die "Could not find partsgroup '$partsgroup_name' for part '$makemodel_model $description'";
|
|
301 |
my $vendor = $vendor_name_to_vendor{lc($vendor_name)} or
|
|
302 |
die "Could not find vendor: '$vendor_name' for part '$makemodel_model $description'";
|
|
358 |
my $partsgroup = $partsgroup_number_to_partsgroup{$partsgroup_number} or
|
|
359 |
push @errors, "Could not find partsgroup '$partsgroup_number' for part '$makemodel_model $description' in row " . $first_part->{csv_row};
|
|
360 |
my $vendor = $vendor_number_to_vendor{$vendor_number} or
|
|
361 |
push @errors, "Could not find vendor: '$vendor_number' for part '$makemodel_model $description' in row " . $first_part->{csv_row};
|
|
303 | 362 |
my $warehouse = $warehouse_description_to_warehouse{lc($warehouse_description)} or |
304 |
die "Could not find warehouse '$warehouse_description' for part '$makemodel_model $description'"; |
|
363 |
push @errors, "Could not find warehouse '$warehouse_description' for part '$makemodel_model $description' in row " . $first_part->{csv_row}; |
|
364 |
next if $count_errors_at_start != scalar @errors; |
|
305 | 365 |
my $parent_variant = SL::DB::Part->new_parent_variant( |
366 |
partnumber => $vendor_number . '-' . $makemodel_model, |
|
306 | 367 |
description => $description, |
307 | 368 |
sellprice => $best_sellprice, |
308 | 369 |
partsgroup => $partsgroup, |
... | ... | |
334 | 395 |
# find variant_properties |
335 | 396 |
my %property_name_to_variant_property; |
336 | 397 |
foreach my $property_name (keys %group_variant_property_vales) { |
337 |
# TODO find valid properties for partsgroup |
|
338 | 398 |
my $needed_property_values = $group_variant_property_vales{$property_name}; |
399 |
|
|
400 |
my @valid_variant_properties; |
|
401 |
if ($property_name eq 'varianten_groesse') { |
|
402 |
@valid_variant_properties = @{$partsgroup_id_to_groessen_staffeln{$partsgroup->id}}; |
|
403 |
unless (scalar @valid_variant_properties) { |
|
404 |
push @errors, "NO variant property for key '$property_name' and partsgroup '${\$partsgroup->partsgroup}'. values '@$needed_property_values' in part '$makemodel_model $description' in row " . $first_part->{csv_row}; |
|
405 |
next; |
|
406 |
} |
|
407 |
} elsif ($property_name eq 'varianten_farbe') { |
|
408 |
my $color = SL::DB::Manager::VariantProperty->find_by( |
|
409 |
name => { ilike => "Farbliste $vendor_kurz_name" }, |
|
410 |
); |
|
411 |
unless ($color) { |
|
412 |
push @errors, "Could not find variant property 'Farbliste $vendor_kurz_name'"; |
|
413 |
next; |
|
414 |
} |
|
415 |
@valid_variant_properties = ($color); |
|
416 |
} elsif ($property_name eq 'varianten_laenge') { |
|
417 |
# Only 'Jeanslängen' is vaild |
|
418 |
my $laenge = SL::DB::Manager::VariantProperty->find_by( |
|
419 |
name => { ilike => "Jeanslängen" }, |
|
420 |
); |
|
421 |
unless ($laenge) { |
|
422 |
push @errors, "Could not find variant property 'Jenaslänge'"; |
|
423 |
next; |
|
424 |
} |
|
425 |
@valid_variant_properties = ($laenge); |
|
426 |
} else { |
|
427 |
push @errors, "Not implemented for property '$property_name'"; |
|
428 |
next; |
|
429 |
} |
|
430 |
|
|
339 | 431 |
my ($best_match) = |
340 | 432 |
sort {scalar @{$a->{missing}} <=> scalar @{$b->{missing}}} |
341 | 433 |
map { |
... | ... | |
346 | 438 |
} |
347 | 439 |
{property => $_, missing => \@missing}; |
348 | 440 |
} |
349 |
@all_variant_properties;
|
|
441 |
@valid_variant_properties;
|
|
350 | 442 |
|
351 | 443 |
if (scalar @{$best_match->{missing}}) { |
352 |
die "Could not find variant property with values for $property_name '@{$needed_property_values}' of part '$makemodel_model $description'.\n" . |
|
353 |
"Best match is ${\$best_match->{property}->name} with missing values '@{$best_match->{missing}}'"; |
|
444 |
push @errors, "Could not find variant property with values for $property_name '@{$needed_property_values}' of part '$makemodel_model $description' in row " . $first_part->{csv_row} . "\n" . |
|
445 |
"Best match is '${\$best_match->{property}->name}' with missing values '@{$best_match->{missing}}'.\n" . |
|
446 |
"Valid properties are: " . join(', ', map {$_->name} @valid_variant_properties) . "\n" |
|
447 |
; |
|
448 |
next; |
|
354 | 449 |
} |
355 | 450 |
$property_name_to_variant_property{$property_name} = $best_match->{property}; |
356 | 451 |
} |
357 | 452 |
my @variant_properties = values %property_name_to_variant_property; |
358 | 453 |
$parent_variant->variant_properties(@variant_properties); |
359 | 454 |
|
455 |
next if $count_errors_at_start != scalar @errors; |
|
360 | 456 |
$parent_variant->save(); |
361 | 457 |
|
362 | 458 |
foreach my $variant_values (@$grouped_variant_values) { |
... | ... | |
367 | 463 |
grep { $_ =~ m/^variant/ } |
368 | 464 |
keys %$variant_values; |
369 | 465 |
|
370 |
my $variant = $parent_variant->create_new_variant(\@property_values); |
|
466 |
if (scalar @property_values != scalar keys %property_name_to_variant_property) { |
|
467 |
push @errors, "Missing property value for part '$makemodel_model $description' in row " . $variant_values->{csv_row}; |
|
468 |
next; |
|
469 |
} |
|
470 |
|
|
471 |
my $variant = first {join(' ', sort map {$_->id} @property_values) eq join(' ', sort map {$_->id} $_->variant_property_values)} |
|
472 |
$parent_variant->variants; |
|
473 |
$variant ||= $parent_variant->create_new_variant(\@property_values); |
|
474 |
|
|
475 |
my $warehouse_description = $variant_values->{warehouse_description}; |
|
476 |
my $warehouse = $warehouse_description_to_warehouse{lc($warehouse_description)}; |
|
477 |
unless ($warehouse) { |
|
478 |
push @errors, "Could not find warehouse '$warehouse_description' for part '$makemodel_model $description' in row " . $variant_values->{csv_row}; |
|
479 |
next; |
|
480 |
} |
|
371 | 481 |
|
372 | 482 |
my $sellprice = $variant_values->{sellprice}; |
373 | 483 |
$sellprice =~ s/,/./; |
374 | 484 |
$variant->update_attributes( |
375 |
ean => $variant_values->{ean}, |
|
485 |
ean => $variant_values->{ean},
|
|
376 | 486 |
description => $variant_values->{description}, |
377 |
sellprice => $sellprice, |
|
487 |
sellprice => $sellprice, |
|
488 |
warehouse => $warehouse, |
|
489 |
bin => $warehouse->bins->[0], |
|
378 | 490 |
); |
379 | 491 |
|
380 | 492 |
# set stock |
... | ... | |
394 | 506 |
} |
395 | 507 |
} |
396 | 508 |
} |
397 |
1; |
|
509 |
if (scalar @errors) { |
|
510 |
say join("\n", @errors); |
|
511 |
die join("\n", @errors); |
|
512 |
} else { |
|
513 |
return 1; |
|
514 |
} |
|
398 | 515 |
}) or do { |
399 |
die t8('Error while creating variants: '), SL::DB->client->error; |
|
516 |
if (SL::DB->client->error) { |
|
517 |
say t8('Error while creating variants: '), SL::DB->client->error; |
|
518 |
} |
|
400 | 519 |
}; |
401 | 520 |
|
Auch abrufbar als: Unified diff
kuw: CSV-Import-Script angepasst