5 use Support::TestSetup;
 
  10 use SL::DB::Inventory;
 
  11 use SL::DB::TransferType;
 
  13 use SL::DB::DeliveryOrder;
 
  16 use SL::DB::RecordLink;
 
  17 use SL::DB::DeliveryOrderItemsStock;
 
  21 use SL::Dev::ALL qw(:ALL);
 
  22 use SL::Helper::ShippedQty;
 
  25 Support::TestSetup::login();
 
  29 my ($customer, $vendor, @parts, $unit);
 
  31 $customer = new_customer(name => 'Testkunde'    )->save;
 
  32 $vendor   = new_vendor(  name => 'Testlieferant')->save;
 
  34 my $default_sellprice = 10;
 
  35 my $default_lastcost  =  4;
 
  37 my ($wh) = create_warehouse_and_bins();
 
  38 my $bin1 = SL::DB::Manager::Bin->find_by(description => "Bin 1");
 
  39 my $bin2 = SL::DB::Manager::Bin->find_by(description => "Bin 2");
 
  42     sellprice    => $default_sellprice,
 
  43     warehouse_id => $wh->id,
 
  47 # create 3 parts to be used in test
 
  48 for my $i ( 1 .. 4 ) {
 
  49   new_part( %part_defaults, partnumber => $i, description => "part $i test" )->save;
 
  52 my $part1 = SL::DB::Manager::Part->find_by( partnumber => '1' );
 
  53 my $part2 = SL::DB::Manager::Part->find_by( partnumber => '2' );
 
  54 my $part3 = SL::DB::Manager::Part->find_by( partnumber => '3' );
 
  55 my $part4 = SL::DB::Manager::Part->find_by( partnumber => '4' );
 
  57 my @part_ids; # list of all part_ids to run checks against
 
  58 push( @part_ids, $_->id ) foreach ( $part1, $part2, $part3, $part4 );
 
  59 my %default_transfer_params = ( wh => $wh, bin => $bin1, unit => 'Stck');
 
  62 # test purchases first, so there is actually stock available when sales is tested
 
  64 note("testing purchases, no fill_up");
 
  66 my $purchase_order = create_purchase_order(
 
  68   orderitems => [ create_order_item(part => $part1, qty => 11),
 
  69                   create_order_item(part => $part2, qty => 12),
 
  70                   create_order_item(part => $part3, qty => 13),
 
  74 Rose::DB::Object::Helpers::forget_related($purchase_order, 'orderitems');
 
  75 $purchase_order->orderitems;
 
  77 SL::Helper::ShippedQty
 
  78   ->new(require_stock_out => 1)  # should make no difference while there is no delivery order
 
  79   ->calculate($purchase_order)
 
  82 is($purchase_order->items_sorted->[0]->{shipped_qty}, 0, "first purchase orderitem has no shipped_qty");
 
  83 ok(!$purchase_order->items_sorted->[0]->{delivered},     "first purchase orderitem is not delivered");
 
  85 my $purchase_orderitem_part1 = SL::DB::Manager::OrderItem->find_by( parts_id => $part1->id, trans_id => $purchase_order->id);
 
  87 is($purchase_orderitem_part1->shipped_qty, 0, "OrderItem shipped_qty method ok");
 
  89 is($purchase_order->closed,     0, 'purchase order is open');
 
  90 ok(!$purchase_order->delivered,    'purchase order is not delivered');
 
  92 note('converting purchase order to delivery order');
 
  93 # create purchase delivery order from purchase order
 
  94 my $purchase_delivery_order = $purchase_order->convert_to_delivery_order;
 
  95 is($purchase_order->closed,    0, 'purchase order is open');
 
  96 ok($purchase_order->delivered,    'purchase order is now delivered');
 
  98 SL::Helper::ShippedQty
 
  99   ->new(require_stock_out => 0)
 
 100   ->calculate($purchase_order)
 
 103 is($purchase_order->items_sorted->[0]->{shipped_qty}, 11, "require_stock_out => 0: first purchase orderitem has shipped_qty");
 
 104 ok($purchase_order->items_sorted->[0]->{delivered},       "require_stock_out => 0: first purchase orderitem is delivered");
 
 106 Rose::DB::Object::Helpers::forget_related($purchase_order, 'orderitems');
 
 107 $purchase_order->orderitems;
 
 109 SL::Helper::ShippedQty
 
 110   ->new(require_stock_out => 1)
 
 111   ->calculate($purchase_order)
 
 114 is($purchase_order->items_sorted->[0]->{shipped_qty}, 0,  "require_stock_out => 1: first purchase orderitem has no shipped_qty");
 
 115 ok(!$purchase_order->items_sorted->[0]->{delivered},      "require_stock_out => 1: first purchase orderitem is not delivered");
 
 117 # ship items from delivery order
 
 118 transfer_purchase_delivery_order($purchase_delivery_order);
 
 120 Rose::DB::Object::Helpers::forget_related($purchase_order, 'orderitems');
 
 121 $purchase_order->orderitems;
 
 123 SL::Helper::ShippedQty
 
 124   ->new(require_stock_out => 1, keep_matches => 1)  # shouldn't make a difference now after shipping
 
 125   ->calculate($purchase_order)
 
 128 is($purchase_order->items_sorted->[0]->{shipped_qty}, 11, "require_stock_out => 1: first purchase orderitem has shipped_qty");
 
 129 ok($purchase_order->items_sorted->[0]->{delivered},       "require_stock_out => 1: first purchase orderitem is delivered");
 
 131 my $purchase_orderitem_part2 = SL::DB::Manager::OrderItem->find_by(parts_id => $part1->id, trans_id => $purchase_order->id);
 
 133 is($purchase_orderitem_part2->shipped_qty(require_stock_out => 1), 11, "OrderItem shipped_qty from helper ok");
 
 136 note('testing sales, no fill_up');
 
 138 my $sales_order = create_sales_order(
 
 140   orderitems => [ create_order_item(part => $part1, qty => 5),
 
 141                   create_order_item(part => $part2, qty => 6),
 
 142                   create_order_item(part => $part3, qty => 7),
 
 146 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
 
 147 $sales_order->orderitems;
 
 149 SL::Helper::ShippedQty
 
 150   ->new(require_stock_out => 1)  # should make no difference while there is no delivery order
 
 151   ->calculate($sales_order)
 
 154 is($sales_order->items_sorted->[0]->{shipped_qty}, 0,  "first sales orderitem has no shipped_qty");
 
 155 ok(!$sales_order->items_sorted->[0]->{delivered},      "first sales orderitem is not delivered");
 
 157 my $orderitem_part1 = SL::DB::Manager::OrderItem->find_by(parts_id => $part1->id, trans_id => $sales_order->id);
 
 158 my $orderitem_part2 = SL::DB::Manager::OrderItem->find_by(parts_id => $part2->id, trans_id => $sales_order->id);
 
 160 is($orderitem_part1->shipped_qty, 0, "OrderItem shipped_qty method ok");
 
 162 # create sales delivery order from sales order
 
 163 my $sales_delivery_order = $sales_order->convert_to_delivery_order;
 
 165 SL::Helper::ShippedQty
 
 166   ->new(require_stock_out => 0)
 
 167   ->calculate($sales_order)
 
 170 is($sales_order->items_sorted->[0]->{shipped_qty}, 5, "require_stock_out => 0: first sales orderitem has shipped_qty");
 
 171 ok($sales_order->items_sorted->[0]->{delivered},      "require_stock_out => 0: first sales orderitem is delivered");
 
 173 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
 
 174 $sales_order->orderitems;
 
 176 SL::Helper::ShippedQty
 
 177   ->new(require_stock_out => 1)
 
 178   ->calculate($sales_order)
 
 181 is($sales_order->items_sorted->[0]->{shipped_qty}, 0,  "require_stock_out => 1: first sales orderitem has no shipped_qty");
 
 182 ok(!$sales_order->items_sorted->[0]->{delivered},      "require_stock_out => 1: first sales orderitem is not delivered");
 
 184 # ship items from delivery order
 
 185 transfer_sales_delivery_order($sales_delivery_order);
 
 187 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
 
 188 $sales_order->orderitems;
 
 190 SL::Helper::ShippedQty
 
 191   ->new(require_stock_out => 1)
 
 192   ->calculate($sales_order)
 
 195 is($sales_order->items_sorted->[0]->{shipped_qty}, 5, "require_stock_out => 1: first sales orderitem has no shipped_qty");
 
 196 ok($sales_order->items_sorted->[0]->{delivered},      "require_stock_out => 1: first sales orderitem is not delivered");
 
 198 $orderitem_part1 = SL::DB::Manager::OrderItem->find_by(parts_id => $part1->id, trans_id => $sales_order->id);
 
 200 is($orderitem_part1->shipped_qty(require_stock_out => 1), 5, "OrderItem shipped_qty from helper ok");
 
 204 my $number_of_linked_items = SL::DB::Manager::RecordLink->get_all_count( where => [ from_table => 'orderitems', to_table => 'delivery_order_items' ] );
 
 205 is ($number_of_linked_items , 6, "6 record_links for items, 3 from sales order, 3 from purchase order");
 
 207 note('testing optional orderitems');
 
 209 my $item_optional = create_order_item(part => $part3, qty => 7, optional => 1);
 
 210 ok($item_optional->{optional},       "optional order item");
 
 212 my $sales_order_opt = create_sales_order(
 
 214   orderitems => [ create_order_item(part => $part1, qty => 5),
 
 215                   create_order_item(part => $part2, qty => 6),
 
 221 SL::Helper::ShippedQty
 
 222   ->new(require_stock_out => 1)  # should make no difference while there is no delivery order
 
 223   ->calculate($sales_order_opt)
 
 226 is($sales_order_opt->items_sorted->[2]->{shipped_qty}, 0,  "third optional sales orderitem has no shipped_qty");
 
 227 ok(!$sales_order_opt->items_sorted->[2]->{delivered},      "third optional sales orderitem is not delivered");
 
 228 ok($sales_order_opt->items_sorted->[2]->{optional},        "third optional sales orderitem is optional");
 
 230 my $orderitem_part3_opt = SL::DB::Manager::OrderItem->find_by(parts_id => $part3->id, trans_id => $sales_order_opt->id);
 
 231 is($orderitem_part3_opt->shipped_qty, 0, "OrderItem shipped_qty method ok");
 
 233 # create sales delivery order from sales order
 
 234 my $sales_delivery_order_opt = $sales_order_opt->convert_to_delivery_order;
 
 235 is(scalar @{ $sales_delivery_order_opt->items_sorted }, 3,   "third optional sales delivery orderitem is there");
 
 237 # and delete third item
 
 238 my $optional =  SL::DB::Manager::DeliveryOrderItem->find_by(parts_id => $part3->id, delivery_order_id => $sales_delivery_order_opt->id);
 
 239 SL::DB::DeliveryOrderItem->new(id => $optional->id)->delete;
 
 240 $sales_delivery_order_opt->save(cascade => 1);
 
 241 my $new_sales_delivery_order_opt = SL::DB::Manager::DeliveryOrder->find_by(id => $sales_delivery_order_opt->id);
 
 242 is(scalar @{ $new_sales_delivery_order_opt->items_sorted }, 2,   "third optional sales delivery orderitem is undef");
 
 244 SL::Helper::ShippedQty
 
 245   ->new(require_stock_out => 0)
 
 246   ->calculate($sales_order_opt)
 
 249 is($sales_order_opt->items_sorted->[0]->{shipped_qty}, 5,  "require_stock_out => 0: first sales orderitem has shipped_qty");
 
 250 ok($sales_order_opt->items_sorted->[0]->{delivered},       "require_stock_out => 0: first sales orderitem is delivered");
 
 251 ok($sales_order_opt->items_sorted->[1]->{delivered},       "require_stock_out => 0: second sales orderitem is delivered");
 
 252 ok(!$sales_order_opt->items_sorted->[2]->{delivered},      "require_stock_out => 0: third sales orderitem is NOT delivered");
 
 253 is($sales_order_opt->items_sorted->[2]->{shipped_qty}, 0,  "require_stock_out => 0: third sales orderitem has no shipped_qty");
 
 254 ok($sales_order_opt->{delivered},                          "require_stock_out => 0: order IS delivered");
 
 259 #  legacy unlinked scenario:
 
 261 #  order with two positions of the same part, qtys: 5, 3.
 
 262 #  3 linked delivery orders, with positions:
 
 264 #    2:  1 linked to 1, 3 linked to 2
 
 267 #  should be resolved under fill_up as 5/3, but gets resolved as 4/4
 
 268   my $part = new_part()->save;
 
 269   my $order = create_sales_order(
 
 271       create_order_item(part => $part, qty => 5),
 
 272       create_order_item(part => $part, qty => 3),
 
 275   my $do1 = create_sales_delivery_order(
 
 277       create_delivery_order_item(part => $part, qty => 3),
 
 280   my $do2 = create_sales_delivery_order(
 
 282       create_delivery_order_item(part => $part, qty => 1),
 
 283       create_delivery_order_item(part => $part, qty => 3),
 
 286   my $do3 = create_sales_delivery_order(
 
 288       create_delivery_order_item(part => $part, qty => 1),
 
 291   $order->link_to_record($do1);
 
 292   $order->link_to_record($do2);
 
 293   $order->items_sorted->[0]->link_to_record($do2->items_sorted->[0]);
 
 294   $order->items_sorted->[1]->link_to_record($do2->items_sorted->[1]);
 
 295   $order->link_to_record($do3);
 
 296   $order->items_sorted->[0]->link_to_record($do3->items->[0]);
 
 298   SL::Helper::ShippedQty
 
 299     ->new(fill_up => 1, require_stock_out => 0)
 
 303   is $order->items_sorted->[0]->{shipped_qty}, 5, 'unlinked legacy position test 1';
 
 304   is $order->items_sorted->[1]->{shipped_qty}, 3, 'unlinked legacy position test 2';
 
 312   foreach ( qw(Inventory DeliveryOrderItem DeliveryOrder Price OrderItem Order Part Customer Vendor Bin Warehouse) ) {
 
 313     "SL::DB::Manager::${_}"->delete_all(all => 1);