2 use Test::Deep qw(cmp_deeply ignore superhashof);
8 use SL::Dev::Part qw(new_part new_assembly);
9 use SL::Dev::Inventory qw(create_warehouse_and_bins set_stock);
10 use SL::Dev::Record qw(create_sales_order);
12 use_ok 'Support::TestSetup';
14 use_ok 'SL::DB::Part';
15 use_ok 'SL::DB::Warehouse';
16 use_ok 'SL::DB::Inventory';
18 use_ok 'SL::Helper::Inventory';
20 Support::TestSetup::login();
22 my ($wh, $bin1, $bin2, $assembly1, $part1, $part2);
25 create_standard_stock();
28 # simple stock in, get_stock, get_onhand
35 is(SL::Helper::Inventory::get_stock(part => $part1), "25.00000", 'simple get_stock works');
36 is(SL::Helper::Inventory::get_onhand(part => $part1), "25.00000", 'simple get_onhand works');
38 # stock on some more, get_stock, get_onhand
41 parts_id => $part1->id,
43 transfer_type => 'stock',
44 dst_warehouse_id => $bin1->warehouse_id,
45 dst_bin_id => $bin1->id,
50 parts_id => $part1->id,
52 transfer_type => 'stock',
53 chargenumber => '298345',
54 dst_warehouse_id => $bin1->warehouse_id,
55 dst_bin_id => $bin1->id,
59 is(SL::Helper::Inventory::get_stock(part => $part1), "60.00000", 'normal get_stock works');
60 is(SL::Helper::Inventory::get_onhand(part => $part1), "60.00000", 'normal get_onhand works');
64 my @allocations = SL::Helper::Inventory::allocate(
69 is_deeply(\%{ $allocations[0] }, {
73 parts_id => $part1->id,
75 warehouse_id => $wh->id,
76 comment => undef, # comment is not a partition so is not set by allocate
77 for_object_id => undef,
78 }, 'allocation works');
80 # allocate something where more than one result will match
82 @allocations = SL::Helper::Inventory::allocate(
87 is_deeply(\@allocations, [
92 parts_id => $part1->id,
94 warehouse_id => $wh->id,
96 for_object_id => undef,
101 chargenumber => '298345',
102 parts_id => $part1->id,
104 warehouse_id => $wh->id,
106 for_object_id => undef,
108 ], 'complex allocation works');
110 # try to allocate too much
113 SL::Helper::Inventory::allocate(part => $part1, qty => 100)
115 "allocate too much dies");
120 create_standard_stock();
134 my @alloc1 = SL::Helper::Inventory::allocate(part => $part1, qty => 3);
135 my @alloc2 = SL::Helper::Inventory::allocate(part => $part2, qty => 3);
137 SL::Helper::Inventory::produce_assembly(
140 allocations => [ @alloc1, @alloc2 ],
144 chargenumber => "537",
147 is(SL::Helper::Inventory::get_stock(part => $assembly1), "3.00000", 'produce works');
148 is(SL::Helper::Inventory::get_stock(part => $part1), "2.00000", 'and consumes...');
149 is(SL::Helper::Inventory::get_stock(part => $part2), "7.00000", '..the materials');
151 # produce the same using auto_allocation
154 create_standard_stock();
167 SL::Helper::Inventory::produce_assembly(
174 chargenumber => "537",
177 is(SL::Helper::Inventory::get_stock(part => $assembly1), "3.00000", 'produce with auto allocation works');
178 is(SL::Helper::Inventory::get_stock(part => $part1), "2.00000", 'and consumes...');
179 is(SL::Helper::Inventory::get_stock(part => $part2), "7.00000", '..the materials');
181 # check comments and warehouses
182 $::form->{l_comment} = 'Y';
183 $::form->{l_warehouse_from} = 'Y';
184 $::form->{l_warehouse_to} = 'Y';
185 local $::instance_conf->data->{produce_assembly_same_warehouse} = 1;
187 my @contents = WH->get_warehouse_journal(sort => 'date');
189 cmp_deeply(\@contents,
190 [ ignore(), ignore(),
192 'comment' => 'Used for assembly 6 Test Assembly',
193 'warehouse_from' => 'Warehouse'
196 'comment' => 'Used for assembly 6 Test Assembly',
197 'warehouse_from' => 'Warehouse'
200 'part_type' => 'assembly',
201 'warehouse_to' => 'Warehouse'
204 "Comments for assembly productions are ok"
212 # try to produce without allocations dies
215 SL::Helper::Inventory::produce_assembly(
221 chargenumber => "537",
223 }, "producing without allocations dies");
225 # try to produce with insufficient allocations dies
227 @alloc1 = SL::Helper::Inventory::allocate(part => $part1, qty => 1);
228 @alloc2 = SL::Helper::Inventory::allocate(part => $part2, qty => 1);
231 SL::Helper::Inventory::produce_assembly(
234 allocations => [ @alloc1, @alloc2 ],
238 chargenumber => "537",
240 }, "producing with insufficient allocations dies");
247 create_standard_stock();
262 SL::Helper::Inventory::produce_assembly(
268 chargenumber => "537",
269 bestbefore => DateTime->today->clone->add(days => -14), # expired 2 weeks ago
270 shippingdate => DateTime->today->clone->add(days => 1),
273 is(SL::Helper::Inventory::get_stock(part => $assembly1), "3.00000", 'produce with bestbefore works');
274 is(SL::Helper::Inventory::get_onhand(part => $assembly1), "3.00000", 'produce with bestbefore works');
275 is(SL::Helper::Inventory::get_stock(
277 bestbefore => DateTime->today,
278 ), undef, 'get_stock with bestbefore date skips expired');
280 local $::instance_conf->data->{show_bestbefore} = 1;
281 is(SL::Helper::Inventory::get_onhand(
283 ), undef, 'get_onhand with bestbefore skips expired as of today');
287 local $::instance_conf->data->{show_bestbefore} = 0;
288 is(SL::Helper::Inventory::get_onhand(
290 ), "3.00000", 'get_onhand without bestbefore finds all');
295 SL::DB::Manager::Order->delete_all(all => 1);
296 SL::DB::Manager::Inventory->delete_all(all => 1);
297 SL::DB::Manager::Assembly->delete_all(all => 1);
298 SL::DB::Manager::Part->delete_all(all => 1);
299 SL::DB::Manager::Bin->delete_all(all => 1);
300 SL::DB::Manager::Warehouse->delete_all(all => 1);
303 sub create_standard_stock {
304 ($wh, $bin1) = create_warehouse_and_bins();
305 $bin2 = SL::DB::Bin->new(description => "Bin 2", warehouse => $wh)->save;
308 $assembly1 = new_assembly(number_of_parts => 2)->save;
309 ($part1, $part2) = map { $_->part } $assembly1->assemblies;