Revision ad910e38
Von Kivitendo Admin vor mehr als 7 Jahren hinzugefügt
SL/Dev/Inventory.pm | ||
---|---|---|
2 | 2 |
|
3 | 3 |
use strict; |
4 | 4 |
use base qw(Exporter); |
5 |
our @EXPORT = qw(create_warehouse_and_bins set_stock); |
|
5 |
our @EXPORT = qw(create_warehouse_and_bins set_stock transfer_stock transfer_sales_delivery_order transfer_purchase_delivery_order transfer_delivery_order_item transfer_in transfer_out);
|
|
6 | 6 |
|
7 | 7 |
use SL::DB::Warehouse; |
8 | 8 |
use SL::DB::Bin; |
9 | 9 |
use SL::DB::Inventory; |
10 | 10 |
use SL::DB::TransferType; |
11 | 11 |
use SL::DB::Employee; |
12 |
use SL::DB::DeliveryOrderItemsStock; |
|
12 | 13 |
use SL::WH; |
13 | 14 |
use DateTime; |
14 | 15 |
use Data::Dumper; |
16 |
use Carp; |
|
15 | 17 |
|
16 | 18 |
sub create_warehouse_and_bins { |
17 | 19 |
my (%params) = @_; |
... | ... | |
184 | 186 |
# return 1; |
185 | 187 |
} |
186 | 188 |
|
189 |
sub _transfer { |
|
190 |
my (%params) = @_; |
|
191 |
|
|
192 |
my $transfer_type = delete $params{transfer_type}; |
|
193 |
|
|
194 |
die "param transfer_type is not a SL::DB::TransferType object: " . Dumper($transfer_type) unless ref($transfer_type) eq 'SL::DB::TransferType'; |
|
195 |
|
|
196 |
my $shippingdate = delete $params{shippingdate} // DateTime->today; |
|
197 |
|
|
198 |
my $part = delete($params{part}) or croak 'part missing'; |
|
199 |
my $qty = delete($params{qty}) or croak 'qty missing'; |
|
200 |
|
|
201 |
# distinguish absolute qty in inventory depending on transfer type direction |
|
202 |
$qty *= -1 if $transfer_type->direction eq 'out'; |
|
203 |
|
|
204 |
# use defaults for unit/wh/bin is they exist and nothing else is specified |
|
205 |
my $unit = delete($params{unit}) // $part->unit or croak 'unit missing'; |
|
206 |
my $bin = delete($params{bin}) // $part->bin or croak 'bin missing'; |
|
207 |
# if bin is given, we don't need a warehouse param |
|
208 |
my $wh = $bin->warehouse or croak 'wh missing'; |
|
209 |
|
|
210 |
WH->transfer({ |
|
211 |
parts_id => $part->id, |
|
212 |
dst_bin => $bin, |
|
213 |
dst_wh => $wh, |
|
214 |
qty => $qty, |
|
215 |
transfer_type => $transfer_type, |
|
216 |
unit => $unit, |
|
217 |
comment => delete $params{comment}, |
|
218 |
shippingdate => $shippingdate, |
|
219 |
}); |
|
220 |
} |
|
221 |
|
|
222 |
sub transfer_in { |
|
223 |
my (%params) = @_; |
|
224 |
|
|
225 |
my $transfer_type = delete $params{transfer_type} // 'stock'; |
|
226 |
|
|
227 |
my $transfer_type_obj = SL::DB::Manager::TransferType->find_by( direction => 'in', description => $transfer_type ) or die "Can't find transfer_type with direction in and descriptin " . $params{transfer_type}; |
|
228 |
|
|
229 |
$params{transfer_type} = $transfer_type_obj; |
|
230 |
|
|
231 |
_transfer(%params); |
|
232 |
} |
|
233 |
|
|
234 |
sub transfer_out { |
|
235 |
my (%params) = @_; |
|
236 |
|
|
237 |
my $transfer_type = delete $params{transfer_type} // 'shipped'; |
|
238 |
|
|
239 |
my $transfer_type_obj = SL::DB::Manager::TransferType->find_by( direction => 'out', description => $transfer_type ) or die "Can't find transfer_type with direction in and descriptin " . $params{transfer_type}; |
|
240 |
|
|
241 |
$params{transfer_type} = $transfer_type_obj; |
|
242 |
|
|
243 |
_transfer(%params); |
|
244 |
} |
|
245 |
|
|
246 |
sub transfer_sales_delivery_order { |
|
247 |
my ($sales_delivery_order) = @_; |
|
248 |
die "first argument must be a sales delivery order Rose DB object" unless ref($sales_delivery_order) eq 'SL::DB::DeliveryOrder' and $sales_delivery_order->is_sales; |
|
249 |
|
|
250 |
die "the delivery order has already been delivered" if $sales_delivery_order->delivered; |
|
251 |
|
|
252 |
my ($wh, $bin, $trans_type); |
|
253 |
|
|
254 |
$sales_delivery_order->db->with_transaction(sub { |
|
255 |
|
|
256 |
foreach my $doi ( @{ $sales_delivery_order->items } ) { |
|
257 |
next if $doi->part->is_service or $doi->part->is_assortment; |
|
258 |
my $trans_type = SL::DB::Manager::TransferType->find_by(direction => 'out', description => 'shipped'); |
|
259 |
transfer_delivery_order_item($doi, $wh, $bin, $trans_type); |
|
260 |
}; |
|
261 |
$sales_delivery_order->delivered(1); |
|
262 |
$sales_delivery_order->save(changes_only=>1); |
|
263 |
1; |
|
264 |
}) or die "error while transferring sales_delivery_order: " . $sales_delivery_order->db->error; |
|
265 |
}; |
|
266 |
|
|
267 |
sub transfer_purchase_delivery_order { |
|
268 |
my ($purchase_delivery_order) = @_; |
|
269 |
die "first argument must be a purchase delivery order Rose DB object" unless ref($purchase_delivery_order) eq 'SL::DB::DeliveryOrder' and not $purchase_delivery_order->is_sales; |
|
270 |
|
|
271 |
my ($wh, $bin, $trans_type); |
|
272 |
|
|
273 |
$purchase_delivery_order->db->with_transaction(sub { |
|
274 |
|
|
275 |
foreach my $doi ( @{ $purchase_delivery_order->items } ) { |
|
276 |
my $trans_type = SL::DB::Manager::TransferType->find_by(direction => 'in', description => 'stock'); |
|
277 |
transfer_delivery_order_item($doi, $wh, $bin, $trans_type); |
|
278 |
}; |
|
279 |
1; |
|
280 |
}) or die "error while transferring purchase_Delivery_order: " . $purchase_delivery_order->db->error; |
|
281 |
}; |
|
282 |
|
|
283 |
sub transfer_delivery_order_item { |
|
284 |
my ($doi, $wh, $bin, $trans_type) = @_; |
|
285 |
|
|
286 |
unless ( defined $trans_type and ref($trans_type eq 'SL::DB::TransferType') ) { |
|
287 |
if ( $doi->record->is_sales ) { |
|
288 |
$trans_type //= SL::DB::Manager::TransferType->find_by(direction => 'out', description => 'shipped'); |
|
289 |
} else { |
|
290 |
$trans_type //= SL::DB::Manager::TransferType->find_by(direction => 'in', description => 'stock'); |
|
291 |
} |
|
292 |
} |
|
293 |
|
|
294 |
$bin //= $doi->part->bin; |
|
295 |
$wh //= $doi->part->warehouse; |
|
296 |
|
|
297 |
die "no bin and wh specified and part has no default bin or wh" unless $bin and $wh; |
|
298 |
|
|
299 |
my $employee = SL::DB::Manager::Employee->current || die "No employee"; |
|
300 |
|
|
301 |
# dois are converted to base_qty, which is qty |
|
302 |
# AM->convert_unit( 'g' => 'kg') * 1000; # 1 |
|
303 |
# $doi->unit $doi->part->unit $doi->qty |
|
304 |
my $dois = SL::DB::DeliveryOrderItemsStock->new( |
|
305 |
delivery_order_item => $doi, |
|
306 |
qty => AM->convert_unit($doi->unit => $doi->part->unit) * $doi->qty, |
|
307 |
unit => $doi->part->unit, |
|
308 |
warehouse_id => $wh->id, |
|
309 |
bin_id => $bin->id, |
|
310 |
)->save; |
|
311 |
|
|
312 |
my $inventory = SL::DB::Inventory->new( |
|
313 |
parts => $dois->delivery_order_item->part, |
|
314 |
qty => $dois->delivery_order_item->record->is_sales ? $dois->qty * -1 : $dois->qty, |
|
315 |
oe => $doi->record, |
|
316 |
warehouse_id => $dois->warehouse_id, |
|
317 |
bin_id => $dois->bin_id, |
|
318 |
trans_type_id => $trans_type->id, |
|
319 |
delivery_order_items_stock => $dois, |
|
320 |
trans_id => $dois->id, |
|
321 |
employee_id => $employee->id, |
|
322 |
shippingdate => $doi->record->transdate, |
|
323 |
)->save; |
|
324 |
}; |
|
325 |
|
|
187 | 326 |
1; |
188 | 327 |
|
189 | 328 |
__END__ |
... | ... | |
280 | 419 |
$part->get_stock(bin_id => $wh->bins->[4]->id); # 3.00000 |
281 | 420 |
$part->get_stock(bin_id => $wh->bins->[2]->id); # 2.00000 |
282 | 421 |
|
422 |
=head2 C<transfer_sales_delivery_order %PARAMS> |
|
423 |
|
|
424 |
Takes a SL::DB::DeliveryOrder object as its first argument and transfers out |
|
425 |
all the items via their default bin, creating the delivery_order_stock and |
|
426 |
inventory entries. |
|
427 |
|
|
428 |
Assumes a fresh delivery order where nothing has been transferred out yet. |
|
429 |
|
|
430 |
Should work like the functions in do.pl transfer_in/transfer_out and DO.pm |
|
431 |
transfer_in_out, except that those work on the current form where as this just |
|
432 |
works on database objects. |
|
433 |
|
|
434 |
As this is just Dev it doesn't check for negative stocks etc. |
|
435 |
|
|
436 |
Usage: |
|
437 |
my $sales_delivery_order = SL::DB::Manager::DeliveryOrder->find_by(donumber => 112); |
|
438 |
SL::Dev::Inventory::transfer_sales_delivery_order($sales_delivery_order1); |
|
439 |
|
|
440 |
=head2 C<transfer_purchase_delivery_order %PARAMS> |
|
441 |
|
|
442 |
Transfer in all the items in a purchase order. |
|
443 |
|
|
444 |
Behaves like C<transfer_sales_delivery_order>. |
|
445 |
|
|
446 |
=head2 C<transfer_delivery_order_item @PARAMS> |
|
447 |
|
|
448 |
Transfers a delivery order item from a delivery order. The whole qty is transferred. |
|
449 |
Doesn't check for available qty. |
|
450 |
|
|
451 |
Usage: |
|
452 |
SL::Dev::Inventory::transfer_delivery_order_item($doi, $wh, $bin, $trans_type); |
|
453 |
|
|
454 |
=head2 C<transfer_in %PARAMS> |
|
455 |
|
|
456 |
Create stock in event for a part. Ideally the interface should mirror how data |
|
457 |
is entered via the web interface. |
|
458 |
|
|
459 |
Does some param checking, sets some defaults, but otherwise uses WH->transfer. |
|
460 |
|
|
461 |
Mandatory params: |
|
462 |
part - an SL::DB::Part object |
|
463 |
qty - a number |
|
464 |
|
|
465 |
Optional params: shippingdate |
|
466 |
bin - an SL::DB::Bin object, defaults to $part->bin |
|
467 |
wh - an SL::DB::Bin object, defaults to $part->warehouse |
|
468 |
unit - a string such as 't', 'Stck', defaults to $part->unit->name |
|
469 |
shippingdate - a DateTime object, defaults to today |
|
470 |
transfer_type - a string such as 'correction', defaults to 'stock' |
|
471 |
comment |
|
472 |
|
|
473 |
Example minimal usage using part default warehouse and bin: |
|
474 |
my ($wh, $bin) = SL::Dev::Inventory::create_warehouse_and_bins(); |
|
475 |
my $part = SL::Dev::Part::create_part(unit => 'kg', warehouse => $wh, bin => $bin)->save; |
|
476 |
SL::Dev::Inventory::transfer_in(part => $part, qty => '0.9', unit => 't', comment => '900 kg in t'); |
|
477 |
|
|
478 |
Example with specific transfer_type and warehouse and bin and shipping_date: |
|
479 |
my $shipping_date = DateTime->today->subtract( days => 20 ); |
|
480 |
SL::Dev::Inventory::transfer_in(part => $part, |
|
481 |
qty => 5, |
|
482 |
transfer_type => 'correction', |
|
483 |
bin => $bin, |
|
484 |
shipping_date => $shipping_date, |
|
485 |
); |
|
486 |
|
|
487 |
=head2 C<transfer_out %PARAMS> |
|
488 |
|
|
489 |
Create stock out event for a part. See C<transfer_in>. |
|
490 |
|
|
283 | 491 |
=head1 BUGS |
284 | 492 |
|
285 | 493 |
Nothing here yet. |
Auch abrufbar als: Unified diff
SL::Dev::Inventory - neue Funktionen ...
... um Lagerbestand zu ändern und um Lieferscheine ein- oder auszulagern.