Revision 01548f39
Von Tamino Steinert vor 12 Monaten hinzugefügt
SL/Controller/DeliveryOrder.pm | ||
---|---|---|
14 | 14 |
use SL::File; |
15 | 15 |
use SL::MIME; |
16 | 16 |
use SL::YAML; |
17 |
use SL::DBUtils qw(selectall_hashref_query); |
|
17 | 18 |
use SL::DB::History; |
18 | 19 |
use SL::DB::Order; |
19 | 20 |
use SL::DB::Default; |
... | ... | |
1053 | 1054 |
} |
1054 | 1055 |
|
1055 | 1056 |
sub action_transfer_stock { |
1056 |
my ($self) = @_; |
|
1057 |
my ($self, $default_transfer) = @_;
|
|
1057 | 1058 |
|
1058 | 1059 |
if ($self->order->delivered) { |
1059 | 1060 |
return $self->js->flash("error", |
... | ... | |
1084 | 1085 |
$transfer->oe_id($order->id); |
1085 | 1086 |
$transfer->qty($transfer->qty * -1) if $inout eq 'out'; |
1086 | 1087 |
$transfer->qty($transfer->qty * 1) if $inout eq 'in'; |
1088 |
$transfer->comment(t8("Default transfer delivery order")) if $default_transfer; |
|
1087 | 1089 |
|
1088 | 1090 |
push @transfer_requests, $transfer if defined $transfer->qty && $transfer->qty != 0; |
1089 | 1091 |
}; |
... | ... | |
1097 | 1099 |
$_->save for @transfer_requests; |
1098 | 1100 |
$self->order->update_attributes(delivered => 1, closed => 1); |
1099 | 1101 |
}); |
1100 |
# update stock info (set new delivery_order_items_stock_id)
|
|
1102 |
# update qty and stock info
|
|
1101 | 1103 |
foreach my $item (@{$self->order->items}) { |
1102 | 1104 |
$self->order->prepare_stock_info($item); |
1105 |
my $stock_info_yaml = $item->{stock_info}; |
|
1103 | 1106 |
my $item_position = $item->position; |
1107 |
my $stock_qty = $self->calculate_stock_in_out($item); |
|
1108 |
my $unit = $item->unit; |
|
1109 |
$self->js->text("[data-position=$item_position] .data-stock-qty", "$stock_qty $unit"); |
|
1104 | 1110 |
my $selector = "[data-position=$item_position] .data-stock-info"; |
1105 |
$self->js->val($selector, $item->{stock_info});
|
|
1111 |
$self->js->val($selector, $stock_info_yaml);
|
|
1106 | 1112 |
} |
1107 | 1113 |
|
1108 | 1114 |
$self->js |
... | ... | |
1111 | 1117 |
t8('This record has already been delivered.')) |
1112 | 1118 |
->run('kivi.ActionBar.setDisabled', '#transfer_out_action', |
1113 | 1119 |
t8('The parts for this order have already been transferred')) |
1120 |
->run('kivi.ActionBar.setDisabled', '#transfer_out_default_action', |
|
1121 |
t8('The parts for this order have already been transferred')) |
|
1114 | 1122 |
->run('kivi.ActionBar.setDisabled', '#transfer_in_action', |
1115 | 1123 |
t8('The parts for this order have already been transferred')) |
1124 |
->run('kivi.ActionBar.setDisabled', '#transfer_in_default_action', |
|
1125 |
t8('The parts for this order have already been transferred')) |
|
1116 | 1126 |
->run('kivi.ActionBar.setDisabled', '#delete_action', |
1117 | 1127 |
t8('The parts for this order have already been transferred')) |
1118 | 1128 |
->run('kivi.ActionBar.setEnabled', '#undo_transfer_action', |
... | ... | |
1121 | 1131 |
->render; |
1122 | 1132 |
} |
1123 | 1133 |
|
1134 |
sub action_transfer_stock_default { |
|
1135 |
my ($self) = @_; |
|
1136 |
my $delivery_order = $self->order; |
|
1137 |
my @items = @{$delivery_order->items_sorted}; |
|
1138 |
|
|
1139 |
# get default bin if set in config |
|
1140 |
my ($default_warehouse_id, $default_bin_id); |
|
1141 |
if ($::instance_conf->get_transfer_default_use_master_default_bin) { |
|
1142 |
$default_warehouse_id = $::instance_conf->get_warehouse_id; |
|
1143 |
$default_bin_id = $::instance_conf->get_bin_id; |
|
1144 |
} |
|
1145 |
|
|
1146 |
my @transfer_requests = (); |
|
1147 |
my %parts_qty = (); |
|
1148 |
my %units_by_name = map { $_->name => $_ } @{ SL::DB::Manager::Unit->get_all }; |
|
1149 |
foreach my $item (@items) { |
|
1150 |
my $part = $item->part; |
|
1151 |
my $base_unit_factor = $units_by_name{$part->unit}->factor || 1; |
|
1152 |
my $item_unit_factor = $units_by_name{$item->unit}->factor || 1; |
|
1153 |
my $qty = $item->qty * $item_unit_factor / $base_unit_factor; |
|
1154 |
return $self->js->flash('error', t8('Cannot transfer negative entries.'))->render() if $qty < 0; |
|
1155 |
$qty = 0 if (!$::instance_conf->get_transfer_default_services && $part->is_service); |
|
1156 |
|
|
1157 |
$parts_qty{$part->id} += $qty if $qty; |
|
1158 |
push @transfer_requests, { |
|
1159 |
'delivery_order_item_id' => $item->id, |
|
1160 |
'warehouse_id' => $part->warehouse_id || $default_warehouse_id, |
|
1161 |
'bin_id' => $part->bin_id || $default_bin_id, |
|
1162 |
'unit' => $part->unit, |
|
1163 |
'qty' => $qty, |
|
1164 |
# added in check transfer_request out direction if possible |
|
1165 |
'chargenumber' => undef, # $item->serialnumber, # Is not used in delivery order |
|
1166 |
'bestbefore' => undef, # $item->bestbefore, # Is not used in delivery order |
|
1167 |
} |
|
1168 |
} |
|
1169 |
|
|
1170 |
# check transfer_requests are correctly |
|
1171 |
my %parts_errors = (); # missing_bin, missing_qty, multiple_options |
|
1172 |
my $grouped_qty_query = qq| |
|
1173 |
SELECT SUM(qty) as qty, chargenumber, bestbefore |
|
1174 |
FROM inventory |
|
1175 |
WHERE parts_id = ? AND bin_id = ? |
|
1176 |
GROUP BY chargenumber, bestbefore |
|
1177 |
|; |
|
1178 |
my $dbh = $self->order->dbh; |
|
1179 |
my $in_out_direction = $delivery_order->type_data->properties('transfer'); |
|
1180 |
for my $idx (0 .. scalar @transfer_requests - 1) { |
|
1181 |
my $transfer_request = $transfer_requests[$idx]; |
|
1182 |
next unless $transfer_request->{qty}; # empty request |
|
1183 |
my $item = $items[$idx]; |
|
1184 |
my $part_id = $item->parts_id; |
|
1185 |
my $bin_id = $transfer_request->{bin_id}; |
|
1186 |
$parts_errors{$part_id}{missing_bin} = 1 unless $bin_id; |
|
1187 |
next unless $bin_id; |
|
1188 |
if ($in_out_direction eq 'out') { |
|
1189 |
my @grouped_qty = selectall_hashref_query( |
|
1190 |
$::form, $dbh, $grouped_qty_query, $part_id, $bin_id); |
|
1191 |
|
|
1192 |
if (1 < scalar grep {$_->{qty} != 0} @grouped_qty) { |
|
1193 |
$parts_errors{$part_id}{multiple_options} = 1; |
|
1194 |
} |
|
1195 |
my $max_qty = sum0(map {$_->{qty}} @grouped_qty); |
|
1196 |
if ($max_qty < $parts_qty{$part_id}) { |
|
1197 |
$parts_errors{$part_id}{missing_qty} = $parts_qty{$part_id} - $max_qty; |
|
1198 |
} |
|
1199 |
|
|
1200 |
next if $parts_errors{$part_id}; |
|
1201 |
# find correct chargenumber and bestbefore |
|
1202 |
my $stock_info = first {$_->{qty} >= $transfer_request->{qty}} @grouped_qty; |
|
1203 |
$transfer_request->{chargenumber} = $stock_info->{chargenumber}; |
|
1204 |
$transfer_request->{bestbefore} = $stock_info->{bestbefore}; |
|
1205 |
} |
|
1206 |
} |
|
1207 |
|
|
1208 |
# auslagern soll immer gehen, auch wenn nicht genügend auf lager ist. |
|
1209 |
# der lagerplatz ist hier extra konfigurierbar, bspw. Lager-Korrektur mit |
|
1210 |
# Lagerplatz Lagerplatz-Korrektur |
|
1211 |
my $default_warehouse_id_ignore_onhand = $::instance_conf->get_warehouse_id_ignore_onhand; |
|
1212 |
my $default_bin_id_ignore_onhand = $::instance_conf->get_bin_id_ignore_onhand; |
|
1213 |
if ($::instance_conf->get_transfer_default_ignore_onhand && $default_bin_id_ignore_onhand) { |
|
1214 |
foreach my $part_id (keys %parts_errors) { |
|
1215 |
# entsprechende defaults holen |
|
1216 |
# falls chargenumber, bestbefore oder anzahl nicht stimmt, auf automatischen |
|
1217 |
# lagerplatz wegbuchen! |
|
1218 |
foreach (@transfer_requests) { |
|
1219 |
if ($_->{delivery_order_item}->parts_id eq $part_id){ |
|
1220 |
$_->{bin_id} = $default_bin_id_ignore_onhand; |
|
1221 |
$_->{warehouse_id} = $default_warehouse_id_ignore_onhand; |
|
1222 |
} |
|
1223 |
} |
|
1224 |
delete %parts_errors{$part_id}; |
|
1225 |
} |
|
1226 |
} |
|
1227 |
|
|
1228 |
# render errors |
|
1229 |
if (scalar keys %parts_errors) { |
|
1230 |
my @multiple_options = (); |
|
1231 |
foreach my $part_id (keys %parts_errors) { |
|
1232 |
my $part = SL::DB::Part->new(id => $part_id)->load(); |
|
1233 |
if ($parts_errors{$part_id}{missing_bin}){ |
|
1234 |
$self->js->error(t8('No standard bin set for #1.', $part->displayable_name)); |
|
1235 |
} |
|
1236 |
if ($parts_errors{$part_id}{missing_qty}) { |
|
1237 |
$self->js->error( |
|
1238 |
t8('There are #1 of "#2" missing from the standard bin #3 for transfer.', |
|
1239 |
$parts_errors{$part_id}{missing_qty}, $part->displayable_name, $part->bin->full_description)); |
|
1240 |
} |
|
1241 |
if ($parts_errors{$part_id}{multiple_options}){ |
|
1242 |
push @multiple_options, $part; |
|
1243 |
} |
|
1244 |
} |
|
1245 |
if (scalar @multiple_options) { |
|
1246 |
$self->js->error(t8( |
|
1247 |
"There are parts with multiple chargenumbers or bestbefore dates set. This can't be decided automatically. Pleas transfer this delivery order manually. Can't decided for #1.", |
|
1248 |
join ", ", map {$_->displayable_name} @multiple_options) |
|
1249 |
); |
|
1250 |
} |
|
1251 |
return $self->js->render(); |
|
1252 |
} |
|
1253 |
|
|
1254 |
# assign each delivery_order_item it's stock |
|
1255 |
for my $idx (0 .. scalar @transfer_requests - 1) { |
|
1256 |
my %transfer_request = %{$transfer_requests[$idx]}; |
|
1257 |
next unless $transfer_request{qty}; # empty request |
|
1258 |
|
|
1259 |
my $item = $items[$idx]; |
|
1260 |
my @stocks = (SL::DB::DeliveryOrderItemsStock->new(%transfer_request)); |
|
1261 |
$item->delivery_order_stock_entries(@stocks); |
|
1262 |
} |
|
1263 |
|
|
1264 |
my $default_transfer = 1; |
|
1265 |
$self->action_transfer_stock($default_transfer); |
|
1266 |
} |
|
1267 |
|
|
1124 | 1268 |
sub action_undo_transfers { |
1125 | 1269 |
my ( $self ) = @_; |
1126 | 1270 |
|
... | ... | |
1892 | 2036 |
only_if => $self->type_data->properties('transfer') eq 'out', |
1893 | 2037 |
confirm => t8('Do you really want to transfer the stock and set this order to delivered?'), |
1894 | 2038 |
], |
2039 |
action => [ |
|
2040 |
t8('Transfer out via default'), |
|
2041 |
id => 'transfer_out_default_action', |
|
2042 |
call => [ 'kivi.DeliveryOrder.save', { |
|
2043 |
action => 'transfer_stock_default', |
|
2044 |
}], |
|
2045 |
disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') |
|
2046 |
: !$self->order->id ? t8('This object has not been saved yet.') |
|
2047 |
: $self->order->delivered ? t8('The parts for this order have already been transferred') |
|
2048 |
: undef, |
|
2049 |
only_if => $self->type_data->properties('transfer') eq 'out', |
|
2050 |
confirm => t8('Do you really want to transfer the stock and set this order to delivered?'), |
|
2051 |
], |
|
1895 | 2052 |
action => [ |
1896 | 2053 |
t8('Transfer in'), |
1897 | 2054 |
id => 'transfer_in_action', |
... | ... | |
1905 | 2062 |
only_if => $self->type_data->properties('transfer') eq 'in', |
1906 | 2063 |
confirm => t8('Do you really want to transfer the stock and set this order to delivered?'), |
1907 | 2064 |
], |
2065 |
action => [ |
|
2066 |
t8('Transfer in via default'), |
|
2067 |
id => 'transfer_in_default_action', |
|
2068 |
call => [ 'kivi.DeliveryOrder.save', { |
|
2069 |
action => 'transfer_stock_default', |
|
2070 |
}], |
|
2071 |
disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') |
|
2072 |
: !$self->order->id ? t8('This object has not been saved yet.') |
|
2073 |
: $self->order->delivered ? t8('The parts for this order have already been transferred') |
|
2074 |
: undef, |
|
2075 |
only_if => $self->type_data->properties('transfer') eq 'in', |
|
2076 |
confirm => t8('Do you really want to transfer the stock and set this order to delivered?'), |
|
2077 |
], |
|
1908 | 2078 |
action => [ |
1909 | 2079 |
t8('Undo Transfer'), |
1910 | 2080 |
id => 'undo_transfer_action', |
Auch abrufbar als: Unified diff
DeliveryOrder: Ein-/Auslagern über Standard-Lagerplatz