1 use Test::More tests => 52;
8 use Support::TestSetup;
11 use Rose::DB::Object::Helpers qw(forget_related);
13 use SL::DB::BackgroundJob;
14 use SL::DB::DeliveryOrder;
16 use_ok 'SL::BackgroundJob::ConvertTimeRecordings';
18 use SL::Dev::ALL qw(:ALL);
20 Support::TestSetup::login();
23 foreach (qw(TimeRecording OrderItem Order DeliveryOrder Project Part Customer RecordLink)) {
24 "SL::DB::Manager::${_}"->delete_all(all => 1);
26 SL::DB::Manager::Employee->delete_all(where => [ '!login' => 'unittests' ]);
29 ########################################
31 $::myconfig{numberformat} = '1000.00';
32 my $old_locale = $::locale;
33 # set locale to en so we can match errors
34 $::locale = Locale->new('en');
39 ########################################
40 # two time recordings, one order linked with project_id in time recording entry
41 ########################################
42 my $part = new_service(partnumber => 'Serv1', unit => 'Std')->save;
43 my $project = create_project(projectnumber => 'p1', description => 'Project 1');
44 my $customer = new_customer()->save;
45 $::form->{type} = 'sales_order';
47 # sales order with globalproject_id
48 my $sales_order = create_sales_order(
50 customer => $customer,
51 globalproject => $project,
53 orderitems => [ create_order_item(part => $part, qty => 3, sellprice => 70), ]
57 push @time_recordings, new_time_recording(
58 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 5),
59 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 5),
60 customer => $customer,
64 push @time_recordings, new_time_recording(
65 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 12, minute => 5),
66 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 14, minute => 5),
67 customer => $customer,
74 from_date => '01.01.2021',
75 to_date => '30.04.2021',
77 my $db_obj = SL::DB::BackgroundJob->new();
78 $db_obj->set_data(%data);
79 my $job = SL::BackgroundJob::ConvertTimeRecordings->new;
80 my $ret = $job->run($db_obj);
82 is_deeply($job->{job_errors}, [], 'no errros');
83 like($ret, qr{^Number of delivery orders created: 1}, 'one delivery order created');
85 my $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
86 is(scalar @$linked_dos, 1, 'one delivery order linked to order');
87 is($linked_dos->[0]->globalproject_id, $sales_order->globalproject_id, 'project ids match');
89 my $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
90 is(scalar @$linked_items, 1, 'one delivery order item linked to order item');
91 is($linked_items->[0]->qty*1, 3, 'qty in delivery order');
92 is($linked_items->[0]->base_qty*1, 3, 'base_qty in delivery order');
94 # reload order and orderitems to get changes to deliverd and ship
95 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
98 ok($sales_order->delivered, 'related order is delivered');
99 is($sales_order->items->[0]->ship*1, 3, 'ship in related order');
104 ########################################
105 # two time recordings, one order linked with project_id in time recording entry
106 # unit in order is 'min', but part is 'Std'
107 ########################################
108 $part = new_service(partnumber => 'Serv1', unit => 'Std')->save;
109 $project = create_project(projectnumber => 'p1', description => 'Project 1');
110 $customer = new_customer()->save;
112 $sales_order = create_sales_order(
114 customer => $customer,
115 globalproject => $project,
117 orderitems => [ create_order_item(part => $part, qty => 180, unit => 'min', sellprice => 70), ]
120 @time_recordings = ();
121 push @time_recordings, new_time_recording(
122 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 10),
123 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 10),
124 customer => $customer,
128 push @time_recordings, new_time_recording(
129 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 12, minute => 10),
130 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 14, minute => 10),
131 customer => $customer,
138 from_date => '01.04.2021',
139 to_date => '30.04.2021',
141 $db_obj = SL::DB::BackgroundJob->new();
142 $db_obj->set_data(%data);
143 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
144 $ret = $job->run($db_obj);
146 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
147 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
148 is($linked_items->[0]->qty*1, 3, 'different units: qty in delivery order');
149 is($linked_items->[0]->base_qty*1, 3, 'different units: base_qty in delivery order');
151 # reload order and orderitems to get changes to deliverd and ship
152 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
155 ok($sales_order->delivered, 'different units: related order is delivered');
156 is($sales_order->items->[0]->ship*1, 180, 'different units: ship in related order');
161 ########################################
162 # two time recordings, one order linked with project_id in time recording entry
163 # unit in order is 'Std', but part is 'min'
164 ########################################
165 $part = new_service(partnumber => 'Serv1', unit => 'min')->save;
166 $project = create_project(projectnumber => 'p1', description => 'Project 1');
167 $customer = new_customer()->save;
169 $sales_order = create_sales_order(
171 customer => $customer,
172 globalproject => $project,
174 orderitems => [ create_order_item(part => $part, qty => 2, unit => 'Std', sellprice => 70), ]
177 @time_recordings = ();
178 push @time_recordings, new_time_recording(
179 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 10),
180 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 10),
181 customer => $customer,
185 push @time_recordings, new_time_recording(
186 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 12, minute => 10),
187 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 13, minute => 10),
188 customer => $customer,
195 from_date => '01.04.2021',
196 to_date => '30.04.2021',
198 $db_obj = SL::DB::BackgroundJob->new();
199 $db_obj->set_data(%data);
200 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
201 $ret = $job->run($db_obj);
203 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
204 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
205 is($linked_items->[0]->qty*1, 2, 'different units 2: qty in delivery order');
206 is($linked_items->[0]->base_qty*1, 120, 'different units 2: base_qty in delivery order');
208 # reload order and orderitems to get changes to deliverd and ship
209 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
212 ok($sales_order->delivered, 'different units 2: related order is delivered');
213 is($sales_order->items->[0]->ship*1, 2, 'different units 2: ship in related order');
218 ########################################
219 # two time recordings, one with start/end one with date/duration
220 ########################################
221 $part = new_service(partnumber => 'Serv1', unit => 'min')->save;
222 $customer = new_customer()->save;
224 @time_recordings = ();
225 push @time_recordings, new_time_recording(
226 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 10),
227 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 10),
228 customer => $customer,
232 push @time_recordings, new_time_recording(
233 date => DateTime->new(year => 2021, month => 4, day => 19),
237 customer => $customer,
243 from_date => '01.04.2021',
244 to_date => '30.04.2021',
246 $db_obj = SL::DB::BackgroundJob->new();
247 $db_obj->set_data(%data);
248 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
249 $ret = $job->run($db_obj);
251 my $dos = SL::DB::Manager::DeliveryOrder->get_all(where => [customer_id => $customer->id]);
252 is($dos->[0]->items->[0]->qty*1, 180/60, 'date/duration and start/end: qty in delivery order');
253 is($dos->[0]->items->[0]->base_qty*1, 180, 'date/duration and start/end2: base_qty in delivery order');
258 ########################################
259 # time recording, linked with order_id
260 ########################################
261 $part = new_service(partnumber => 'Serv1', unit => 'Std')->save;
262 $customer = new_customer()->save;
264 # sales order with globalproject_id
265 $sales_order = create_sales_order(
267 customer => $customer,
269 orderitems => [ create_order_item(part => $part, qty => 3, sellprice => 70), ]
272 @time_recordings = ();
273 push @time_recordings, new_time_recording(
274 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 5),
275 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 5),
276 customer => $customer,
277 order => $sales_order,
283 from_date => '01.04.2021',
284 to_date => '30.04.2021',
285 customernumbers => [$customer->number],
287 $db_obj = SL::DB::BackgroundJob->new();
288 $db_obj->set_data(%data);
289 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
290 $ret = $job->run($db_obj);
292 is_deeply($job->{job_errors}, [], 'no errros');
293 like($ret, qr{^Number of delivery orders created: 1}, 'linked by order_id: one delivery order created');
295 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
296 is(scalar @$linked_dos, 1, 'linked by order_id: one delivery order linked to order');
298 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
299 is(scalar @$linked_items, 1, 'linked by order_id: one delivery order item linked to order item');
300 is($linked_items->[0]->qty*1, 1, 'linked by order_id: qty in delivery order');
301 is($linked_items->[0]->base_qty*1, 1, 'linked by order_id: base_qty in delivery order');
303 # reload order and orderitems to get changes to deliverd and ship
304 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
307 is($sales_order->items->[0]->ship*1, 1, 'linked by order_id: ship in related order');
312 ########################################
313 # override project and part
314 ########################################
315 $part = new_service(partnumber => 'Serv1', unit => 'Std')->save;
316 my $part2 = new_service(partnumber => 'Serv2', unit => 'min')->save;
317 $project = create_project(projectnumber => 'p1', description => 'Project 1');
318 my $project2 = create_project(projectnumber => 'p2', description => 'Project 2');
319 $customer = new_customer()->save;
321 $sales_order = create_sales_order(
323 customer => $customer,
324 globalproject => $project,
326 orderitems => [ create_order_item(part => $part, qty => 180, unit => 'min', sellprice => 70), ]
328 my $sales_order2 = create_sales_order(
330 customer => $customer,
331 globalproject => $project,
333 orderitems => [ create_order_item(part => $part2, qty => 180, unit => 'min', sellprice => 70), ]
337 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 10),
338 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 10),
339 customer => $customer,
344 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 10),
345 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 12, minute => 10),
346 customer => $customer,
347 project => $project2,
351 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 12, minute => 10),
352 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 13, minute => 10),
353 customer => $customer,
358 from_date => '01.04.2021',
359 to_date => '30.04.2021',
360 override_part_id => $part->id,
361 override_project_id => $project->id,
363 $db_obj = SL::DB::BackgroundJob->new();
364 $db_obj->set_data(%data);
365 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
366 $ret = $job->run($db_obj);
368 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
369 is($linked_dos->[0]->globalproject_id, $project->id, 'overriden part and project: project in delivery order');
371 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
372 is($linked_items->[0]->qty*1, 3, 'overriden part and project: qty in delivery order');
373 is($linked_items->[0]->base_qty*1, 3, 'overriden part and project: base_qty in delivery order');
374 is($linked_items->[0]->parts_id, $part->id, 'overriden part and project: part id');
376 my $linked_dos2 = $sales_order2->linked_records(to => 'DeliveryOrder');
377 is(scalar @$linked_dos2, 0, 'overriden part and project: no delivery order for unused order');
379 # reload order and orderitems to get changes to deliverd and ship
380 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
382 Rose::DB::Object::Helpers::forget_related($sales_order2, 'orderitems');
385 is($sales_order ->items->[0]->ship||0, 180, 'overriden part and project: ship in related order');
386 is($sales_order2->items->[0]->ship||0, 0, 'overriden part and project: ship in not related order');
391 ########################################
392 # default project and part
393 ########################################
394 $part = new_service(partnumber => 'Serv1', unit => 'Std')->save;
395 $project = create_project(projectnumber => 'p1', description => 'Project 1');
396 $customer = new_customer()->save;
398 $sales_order = create_sales_order(
400 customer => $customer,
401 globalproject => $project,
403 orderitems => [ create_order_item(part => $part, qty => 180, unit => 'min', sellprice => 70), ]
407 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 10),
408 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 40),
409 customer => $customer,
414 from_date => '01.04.2021',
415 to_date => '30.04.2021',
416 default_part_id => $part->id,
417 default_project_id => $project->id,
419 $db_obj = SL::DB::BackgroundJob->new();
420 $db_obj->set_data(%data);
421 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
422 $ret = $job->run($db_obj);
424 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
425 is($linked_dos->[0]->globalproject_id, $project->id, 'default and project: project in delivery order');
427 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
428 is($linked_items->[0]->qty*1, 1.5, 'default part and project: qty in delivery order');
429 is($linked_items->[0]->base_qty*1, 1.5, 'default part and project: base_qty in delivery order');
430 is($linked_items->[0]->parts_id, $part->id, 'default part and project: part id');
432 # reload order and orderitems to get changes to deliverd and ship
433 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
436 is($sales_order->items->[0]->ship*1, 90, 'default part and project: ship in related order');
441 ########################################
443 ########################################
444 $part = new_service(partnumber => 'Serv1', unit => 'Std')->save;
445 $customer = new_customer()->save;
447 $sales_order = create_sales_order(
449 customer => $customer,
451 orderitems => [ create_order_item(part => $part, qty => 3, sellprice => 70), ]
454 @time_recordings = ();
455 push @time_recordings, new_time_recording(
456 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 0),
457 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 6),
458 customer => $customer,
459 order => $sales_order,
464 from_date => '01.01.2021',
465 to_date => '30.04.2021',
469 $db_obj = SL::DB::BackgroundJob->new();
470 $db_obj->set_data(%data);
471 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
472 $ret = $job->run($db_obj);
474 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
475 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
476 is($linked_items->[0]->qty*1, 0.25, 'rounding to quarter hour: qty in delivery order');
477 is($linked_items->[0]->base_qty*1, 0.25, 'rounding to quarter hour: base_qty in delivery order');
479 # reload order and orderitems to get changes to deliverd and ship
480 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
483 is($sales_order->items->[0]->ship*1, 0.25, 'rounding to quarter hour: ship in related order');
488 ########################################
490 ########################################
491 $part = new_service(partnumber => 'Serv1', unit => 'Std')->save;
492 $customer = new_customer()->save;
494 $sales_order = create_sales_order(
496 customer => $customer,
498 orderitems => [ create_order_item(part => $part, qty => 3, sellprice => 70), ]
501 @time_recordings = ();
502 push @time_recordings, new_time_recording(
503 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 0),
504 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 6),
505 customer => $customer,
506 order => $sales_order,
511 from_date => '01.01.2021',
512 to_date => '30.04.2021',
516 $db_obj = SL::DB::BackgroundJob->new();
517 $db_obj->set_data(%data);
518 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
519 $ret = $job->run($db_obj);
521 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
522 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
523 is($linked_items->[0]->qty*1, 0.1, 'no rounding: qty in delivery order');
524 is($linked_items->[0]->base_qty*1, 0.1, 'no rounding: base_qty in delivery order');
526 # reload order and orderitems to get changes to deliverd and ship
527 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
530 is($sales_order->items->[0]->ship*1, 0.1, 'no rounding: ship in related order');
535 ########################################
536 # are wrong params detected?
537 ########################################
539 from_date => 'x01.04.2021',
541 $db_obj = SL::DB::BackgroundJob->new();
542 $db_obj->set_data(%data);
543 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
546 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
547 ok($err_msg =~ '^Cannot convert date.', 'wrong date string detected');
551 $customer = new_customer()->save;
553 customernumbers => ['a fantasy', $customer->number],
556 $db_obj = SL::DB::BackgroundJob->new();
557 $db_obj->set_data(%data);
558 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
561 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
562 ok($err_msg =~ '^Not all customer numbers are valid', 'wrong customer number detected');
567 customernumbers => '123',
570 $db_obj = SL::DB::BackgroundJob->new();
571 $db_obj->set_data(%data);
572 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
575 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
576 ok($err_msg =~ '^Customer numbers must be given in an array', 'wrong customer number data type detected');
581 override_part_id => '123',
584 $db_obj = SL::DB::BackgroundJob->new();
585 $db_obj->set_data(%data);
586 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
589 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
590 ok($err_msg =~ '^No valid part found by given override part id', 'invalid part id detected');
594 $part = new_service(partnumber => 'Serv1', unit => 'Std', obsolete => 1)->save;
596 override_part_id => $part->id,
599 $db_obj = SL::DB::BackgroundJob->new();
600 $db_obj->set_data(%data);
601 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
604 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
605 ok($err_msg =~ '^No valid part found by given override part id', 'obsolete part detected');
610 override_project_id => 123,
613 $db_obj = SL::DB::BackgroundJob->new();
614 $db_obj->set_data(%data);
615 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
618 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
619 ok($err_msg =~ '^No valid project found by given override project id', 'invalid project id detected');
623 $project = create_project(projectnumber => 'p1', description => 'Project 1', valid => 0)->save;
625 override_project_id => $project->id,
628 $db_obj = SL::DB::BackgroundJob->new();
629 $db_obj->set_data(%data);
630 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
633 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
634 ok($err_msg =~ '^No valid project found by given override project id', 'invalid project detected');
641 ########################################
643 $::locale = $old_locale;
649 # set emacs to perl mode