Revision 34f13160
Von Bernd Bleßmann vor 4 Monaten hinzugefügt
SL/Controller/StockCountingReconciliation.pm | ||
---|---|---|
4 | 4 |
use parent qw(SL::Controller::Base); |
5 | 5 |
|
6 | 6 |
use English qw(-no_match_vars); |
7 |
use List::Util qw(sum sum0); |
|
7 |
use List::Util qw(any sum sum0);
|
|
8 | 8 |
use POSIX qw(strftime); |
9 | 9 |
|
10 | 10 |
use SL::Controller::Helper::GetModels; |
... | ... | |
57 | 57 |
my $objects = $self->models->get; |
58 | 58 |
|
59 | 59 |
# group always |
60 |
my $grouped_objects_by; |
|
61 |
my @grouped_objects; |
|
62 |
foreach my $object (@$objects) { |
|
63 |
my $group_object; |
|
64 |
if (!$grouped_objects_by->{$object->counting_id}->{$object->part_id}->{$object->bin_id}) { |
|
65 |
$group_object = SL::DB::StockCountingItem->new( |
|
66 |
counting => $object->counting, part => $object->part, bin => $object->bin, qty => 0); |
|
67 |
push @grouped_objects, $group_object; |
|
68 |
$grouped_objects_by->{$object->counting_id}->{$object->part_id}->{$object->bin_id} = $group_object; |
|
69 |
|
|
70 |
} else { |
|
71 |
$group_object = $grouped_objects_by->{$object->counting_id}->{$object->part_id}->{$object->bin_id} |
|
72 |
} |
|
73 |
|
|
74 |
$group_object->id($group_object->id ? ($group_object->id . ',' . $object->id) : $object->id); |
|
75 |
$group_object->qty($group_object->qty + $object->qty); |
|
76 |
} |
|
77 |
|
|
78 |
$objects = \@grouped_objects; |
|
79 |
|
|
60 |
$objects = $self->group_items_by_part_and_bin($objects); |
|
80 | 61 |
$self->get_stocked($objects); |
81 | 62 |
$self->get_inbetweens($objects); |
82 | 63 |
|
... | ... | |
92 | 73 |
# return if $counting->is_reconciliated; |
93 | 74 |
# return if scalar(@{$counting->items}) == 0; |
94 | 75 |
|
95 |
my $counting_items = $counting->items; |
|
96 |
|
|
97 |
$self->get_stocked($counting_items); |
|
98 |
$self->get_inbetweens($counting_items); |
|
99 |
|
|
100 |
my $counted_by_part_and_bin; |
|
101 |
my $stocked_by_part_and_bin; |
|
102 |
my $inbetweens_by_part_and_bin; |
|
103 |
my $item_ids_by_part_and_bin; |
|
104 |
foreach my $item (@$counting_items) { |
|
105 |
$counted_by_part_and_bin ->{$item->part_id}->{$item->bin_id} += $item->qty; |
|
106 |
$stocked_by_part_and_bin ->{$item->part_id}->{$item->bin_id} ||= $item->{stocked}; |
|
107 |
$inbetweens_by_part_and_bin->{$item->part_id}->{$item->bin_id} ||= $item->{inbetweens}; |
|
108 |
push @{$item_ids_by_part_and_bin->{$item->part_id}->{$item->bin_id}}, $item->id; |
|
109 |
} |
|
76 |
# my $counting_items = $counting->items; |
|
77 |
my $grouped_counting_items = $self->group_items_by_part_and_bin(\@{$counting->items}); |
|
78 |
$self->get_stocked($grouped_counting_items); |
|
79 |
$self->get_inbetweens($grouped_counting_items); |
|
110 | 80 |
|
111 | 81 |
my $comment = t8('correction from stock counting (counting "#1")', $counting->name); |
112 | 82 |
|
... | ... | |
114 | 84 |
$::form->throw_on_error(sub { |
115 | 85 |
eval { |
116 | 86 |
SL::DB->client->with_transaction(sub { |
117 |
foreach my $part_id (keys %$counted_by_part_and_bin) { |
|
118 |
foreach my $bin_id (keys %{$counted_by_part_and_bin->{$part_id}}) { |
|
119 |
my $counted_qty = $counted_by_part_and_bin ->{$part_id}->{$bin_id}; |
|
120 |
my $stocked_qty = $stocked_by_part_and_bin ->{$part_id}->{$bin_id}; |
|
121 |
my $inbetween_qty = $inbetweens_by_part_and_bin->{$part_id}->{$bin_id}; |
|
122 |
|
|
123 |
my $transfer_qty = $counted_qty - $stocked_qty + $inbetween_qty; |
|
124 |
|
|
125 |
my $src_or_dst = $transfer_qty < 0? 'src' : 'dst'; |
|
126 |
$transfer_qty = abs($transfer_qty); |
|
127 |
|
|
128 |
# Do stock. |
|
129 |
# todo: run in transaction and record the inventory id in the counting items |
|
130 |
my %transfer_params = ( |
|
131 |
parts_id => $part_id, |
|
132 |
$src_or_dst.'_bin_id' => $bin_id, |
|
133 |
qty => $transfer_qty, |
|
134 |
transfer_type => 'correction', |
|
135 |
comment => $comment, |
|
136 |
); |
|
137 |
|
|
138 |
my @trans_ids = WH->transfer(\%transfer_params); |
|
139 |
|
|
140 |
if (scalar(@trans_ids) != 1) { |
|
141 |
die "Program logic error: no error, but no transfer" if scalar(@trans_ids) == 0; |
|
142 |
die "Program logic error: too many transfers" if scalar(@trans_ids) > 1; |
|
143 |
} |
|
144 |
|
|
145 |
# Get inventory entries via trans_ids- |
|
146 |
my $inventories = SL::DB::Manager::Inventory->get_all(where => [trans_id => $trans_ids[0]]); |
|
147 |
if (scalar(@$inventories) != 1) { |
|
148 |
die "Program logic error: no error, but no inventory entry" if scalar(@$inventories) == 0; |
|
149 |
die "Program logic error: too many inventory entries" if scalar(@$inventories) > 1; |
|
150 |
} |
|
151 |
|
|
152 |
|
|
153 |
SL::DB::Manager::StockCountingItem->update_all(set => {correction_inventory_id => $inventories->[0]->id}, |
|
154 |
where => [id => $item_ids_by_part_and_bin->{$part_id}->{$bin_id}]); |
|
87 |
foreach my $group_item (@$grouped_counting_items) { |
|
88 |
my $counted_qty = $group_item->qty; |
|
89 |
my $stocked_qty = $group_item->{stocked}; |
|
90 |
my $inbetween_qty = $group_item->{inbetweens}; |
|
91 |
|
|
92 |
my $transfer_qty = $counted_qty - $stocked_qty + $inbetween_qty; |
|
93 |
|
|
94 |
my $src_or_dst = $transfer_qty < 0? 'src' : 'dst'; |
|
95 |
$transfer_qty = abs($transfer_qty); |
|
96 |
|
|
97 |
# Do stock. |
|
98 |
# todo: run in transaction and record the inventory id in the counting items |
|
99 |
my %transfer_params = ( |
|
100 |
parts_id => $group_item->part_id, |
|
101 |
$src_or_dst.'_bin_id' => $group_item->bin_id, |
|
102 |
qty => $transfer_qty, |
|
103 |
transfer_type => 'correction', |
|
104 |
comment => $comment, |
|
105 |
); |
|
106 |
|
|
107 |
my @trans_ids = WH->transfer(\%transfer_params); |
|
108 |
|
|
109 |
if (scalar(@trans_ids) != 1) { |
|
110 |
die "Program logic error: no error, but no transfer" if scalar(@trans_ids) == 0; |
|
111 |
die "Program logic error: too many transfers" if scalar(@trans_ids) > 1; |
|
112 |
} |
|
113 |
|
|
114 |
# Get inventory entries via trans_ids- |
|
115 |
my $inventories = SL::DB::Manager::Inventory->get_all(where => [trans_id => $trans_ids[0]]); |
|
116 |
if (scalar(@$inventories) != 1) { |
|
117 |
die "Program logic error: no error, but no inventory entry" if scalar(@$inventories) == 0; |
|
118 |
die "Program logic error: too many inventory entries" if scalar(@$inventories) > 1; |
|
155 | 119 |
} |
120 |
|
|
121 |
|
|
122 |
SL::DB::Manager::StockCountingItem->update_all(set => {correction_inventory_id => $inventories->[0]->id}, |
|
123 |
where => [id => $group_item->{ids}]); |
|
156 | 124 |
} |
157 | 125 |
|
158 | 126 |
1; |
... | ... | |
265 | 233 |
$self->{filter_summary} = join ', ', @filter_strings; |
266 | 234 |
} |
267 | 235 |
|
236 |
sub group_items_by_part_and_bin { |
|
237 |
my ($self, $objects) = @_; |
|
238 |
|
|
239 |
return [] if scalar @{$objects || []} == 0; |
|
240 |
|
|
241 |
if (any { $_->counting_id != $objects->[0]->counting_id } @$objects) { |
|
242 |
die 'can only group stock counting items if they belong too the same counting'; |
|
243 |
} |
|
244 |
|
|
245 |
my $grouped_objects_by; |
|
246 |
my @grouped_objects; |
|
247 |
foreach my $object (@$objects) { |
|
248 |
my $group_object; |
|
249 |
if (!$grouped_objects_by->{$object->part_id}->{$object->bin_id}) { |
|
250 |
$group_object = SL::DB::StockCountingItem->new( |
|
251 |
counting => $object->counting, part => $object->part, bin => $object->bin, qty => 0); |
|
252 |
push @grouped_objects, $group_object; |
|
253 |
$grouped_objects_by->{$object->part_id}->{$object->bin_id} = $group_object; |
|
254 |
|
|
255 |
} else { |
|
256 |
$group_object = $grouped_objects_by->{$object->part_id}->{$object->bin_id} |
|
257 |
} |
|
258 |
|
|
259 |
push @{$group_object->{ids}}, $object->id; |
|
260 |
$group_object->qty($group_object->qty + $object->qty); |
|
261 |
} |
|
262 |
|
|
263 |
return \@grouped_objects; |
|
264 |
} |
|
265 |
|
|
268 | 266 |
sub get_stocked { |
269 | 267 |
my ($self, $objects) = @_; |
270 | 268 |
|
Auch abrufbar als: Unified diff
Zwischeninventur-Abgleich: Gruppier-Methode wiederverwenden