Revision 7fc41a37
Von Moritz Bunkus vor etwa 2 Jahren hinzugefügt
SL/Helper/Inventory.pm | ||
---|---|---|
use List::UtilsBy qw(sort_by);
|
||
use List::MoreUtils qw(any);
|
||
use POSIX qw(ceil);
|
||
use Scalar::Util qw(blessed);
|
||
|
||
use SL::Locale::String qw(t8);
|
||
use SL::MoreCommon qw(listify);
|
||
... | ... | |
last if $rest_qty == 0;
|
||
}
|
||
if ($rest_qty > 0) {
|
||
die SL::X::Inventory::Allocation->new(
|
||
code => 'not enough to allocate',
|
||
message => t8("can not allocate #1 units of #2, missing #3 units", _format_number($qty), $part->displayable_name, _format_number($rest_qty)),
|
||
die SL::X::Inventory::Allocation::MissingQty->new(
|
||
code => 'not enough to allocate',
|
||
message => t8("can not allocate #1 units of #2, missing #3 units", _format_number($qty), $part->displayable_name, _format_number($rest_qty)),
|
||
part_description => $part->displayable_name,
|
||
to_allocate_qty => $qty,
|
||
missing_qty => $rest_qty,
|
||
);
|
||
} else {
|
||
if ($params{constraints}) {
|
||
... | ... | |
$parts_to_allocate{ $assembly->part->id } += $assembly->qty * $qty;
|
||
}
|
||
|
||
my @allocations;
|
||
my (@allocations, @errors);
|
||
|
||
for my $part_id (keys %parts_to_allocate) {
|
||
my $part = SL::DB::Part->load_cached($part_id);
|
||
push @allocations, allocate(%params, part => $part, qty => $parts_to_allocate{$part_id});
|
||
if ($wh_strict) {
|
||
die SL::X::Inventory::Allocation->new(
|
||
code => "wrong warehouse for part",
|
||
message => t8('Part #1 exists in warehouse #2, but not in warehouse #3 ',
|
||
$part->partnumber . ' ' . $part->description,
|
||
SL::DB::Manager::Warehouse->find_by(id => $allocations[-1]->{warehouse_id})->description,
|
||
$wh->description),
|
||
) unless $allocations[-1]->{warehouse_id} == $wh->id;
|
||
}
|
||
|
||
eval {
|
||
push @allocations, allocate(%params, part => $part, qty => $parts_to_allocate{$part_id});
|
||
if ($wh_strict) {
|
||
die SL::X::Inventory::Allocation->new(
|
||
code => "wrong warehouse for part",
|
||
message => t8('Part #1 exists in warehouse #2, but not in warehouse #3 ',
|
||
$part->partnumber . ' ' . $part->description,
|
||
SL::DB::Manager::Warehouse->find_by(id => $allocations[-1]->{warehouse_id})->description,
|
||
$wh->description),
|
||
) unless $allocations[-1]->{warehouse_id} == $wh->id;
|
||
}
|
||
1;
|
||
} or do {
|
||
my $ex = $@;
|
||
die $ex unless blessed($ex) && $ex->can('rethrow');
|
||
|
||
if ($ex->isa('SL::X::Inventory::Allocation')) {
|
||
push @errors, $@;
|
||
} else {
|
||
$ex->rethrow;
|
||
}
|
||
};
|
||
}
|
||
|
||
if (@errors) {
|
||
die SL::X::Inventory::Allocation::Multi->new(
|
||
code => "multiple errors during allocation",
|
||
message => "multiple errors during allocation",
|
||
errors => \@errors,
|
||
);
|
||
}
|
||
|
||
@allocations;
|
SL/X.pm | ||
---|---|---|
isa => 'SL::X::Base',
|
||
fields => [ qw(code) ],
|
||
},
|
||
'SL::X::Inventory::Allocation::MissingQty' => {
|
||
isa => 'SL::X::Inventory::Allocation',
|
||
fields => [ qw(code part_description to_allocate_qty missing_qty) ],
|
||
},
|
||
'SL::X::Inventory::Allocation::Multi' => {
|
||
isa => 'SL::X::Inventory::Allocation',
|
||
fields => [ qw(errors) ],
|
||
},
|
||
);
|
||
|
||
1;
|
bin/mozilla/wh.pl | ||
---|---|---|
#
|
||
#######################################################################
|
||
|
||
use Carp;
|
||
use List::Util qw(min max first);
|
||
use POSIX qw(strftime);
|
||
use Scalar::Util qw(blessed);
|
||
|
||
use SL::Form;
|
||
use SL::User;
|
||
... | ... | |
$form->{bestbefore} = '';
|
||
}
|
||
|
||
produce_assembly(
|
||
eval {
|
||
produce_assembly(
|
||
part => $assembly, # target assembly
|
||
qty => $form->{qty}, # qty
|
||
auto_allocate => 1,
|
||
... | ... | |
chargenumber => $form->{chargenumber}, # optional
|
||
bestbefore => $form->{bestbefore},
|
||
comment => $form->{comment}, # optional
|
||
);
|
||
);
|
||
1;
|
||
|
||
} or do {
|
||
my $ex = $@;
|
||
die $ex unless blessed($ex) && $ex->isa('SL::X::Inventory::Allocation::Multi');
|
||
|
||
$form->{title} = $locale->text('Produce Assembly');
|
||
$form->header;
|
||
print $form->parse_html_template(
|
||
'wh/produce_assembly_error',
|
||
{
|
||
missing_qty_exceptions => [ grep { $_->isa('SL::X::Inventory::Allocation::MissingQty') } @{ $ex->errors } ],
|
||
other_exceptions => [ grep { !$_->isa('SL::X::Inventory::Allocation::MissingQty') } @{ $ex->errors } ],
|
||
});
|
||
|
||
return $::lxdebug->leave_sub();
|
||
};
|
||
|
||
delete @{$form}{qw(parts_id partnumber description qty unit chargenumber bestbefore comment)};
|
||
|
locale/de/all | ||
---|---|---|
'Additional Billing Addresses' => 'Zusätzliche Rechnungsadressen',
|
||
'Additional articles' => 'Zusätzliche Artikel',
|
||
'Additional articles actions' => 'Aktionen zu zusätzlichen Artikeln',
|
||
'Additional errors:' => 'Weitere Fehler:',
|
||
'Additionally the invoice is marked for direct debit and would have been checked automatically had the bank information been entered.' => 'Weiterhin ist die Rechnung für Lastschrifteinzug vorgesehen und wäre standardmäßig ausgewählt, wenn die Bankinformationen eingetragen wären.',
|
||
'Additionally the invoice is not marked for direct debit and would have been checked automatically had the bank information been entered.' => 'Weiterhin ist die Rechnung nicht für Lastschrifteinzug vorgesehen und wäre standardmäßig ausgewählt, wenn die Bankinformationen eingetragen wären.',
|
||
'Address' => 'Adresse',
|
||
... | ... | |
'Missing parameter #1 in call to sub #2.' => 'Fehlender Parameter \'#1\' in Funktionsaufruf \'#2\'.',
|
||
'Missing parameter (at least one of #1) in call to sub #2.' => 'Fehlernder Parameter (mindestens einer aus \'#1\') in Funktionsaufruf \'#2\'.',
|
||
'Missing parameter for WebDAV file copy' => 'Fehlender Parameter für WebDAV Datei kopieren',
|
||
'Missing qty' => 'Fehlende Menge',
|
||
'Missing taxkeys in invoices with taxes.' => 'Fehlende Steuerschlüssel in Rechnungen mit Steuern',
|
||
'Mitarbeiter' => 'Mitarbeiter',
|
||
'Mixed (requires column "type" or "pclass")' => 'Gemischt (Spalte "type" oder "pclass" notwendig',
|
||
... | ... | |
'Require stock out to consider a delivery order position delivered?' => 'Muss eine Lieferscheinposition ausgelagert sein um als geliefert zu gelten?',
|
||
'Required access right' => 'Benötigtes Zugriffsrecht',
|
||
'Required by' => 'Lieferdatum',
|
||
'Required qty' => 'Erforderliche Menge',
|
||
'Requirement Spec Status' => 'Pflichtenheftstatus',
|
||
'Requirement Spec Statuses' => 'Pflichtenheftstatus',
|
||
'Requirement Spec Templates' => 'Pflichtenheftvorlagen',
|
||
... | ... | |
'The application "#1" was not found on the system.' => 'Die Anwendung "#1" wurde auf dem System nicht gefunden.',
|
||
'The assembly \'#1\' cannot be a part from itself.' => 'Das Erzeugnis \'#1\' kann kein Teil von sich selbst sein.',
|
||
'The assembly \'#1\' would make a loop in assembly tree.' => 'Das Erzeugnis \'#1\' würde eine Schleife im Erzeugnisbaum machen.',
|
||
'The assembly could not be produced.' => 'Das Erzeugnis konnte nicht produziert werden.',
|
||
'The assembly doesn\'t have any items.' => 'Das Erzeugnis enthält keine Artikel.',
|
||
'The assembly has been created.' => 'Das Erzeugnis wurde hergestellt.',
|
||
'The assistant could not find anything wrong with #1. Maybe the problem has been solved in the meantime.' => 'Der Korrekturassistent konnte kein Problem bei #1 feststellen. Eventuell wurde das Problem in der Zwischenzeit bereits behoben.',
|
||
... | ... | |
'The following is only a preview.' => 'Das Folgende ist nur eine Vorschau.',
|
||
'The following list has been generated automatically from existing users collapsing users with identical settings into a single entry.' => 'Die folgende Liste wurde automatisch aus den im System vorhandenen Benutzern zusammengestellt, wobei identische Einstellungen zu einem Eintrag zusammengefasst wurden.',
|
||
'The following old files whose settings have to be merged manually into the new configuration file "config/kivitendo.conf" still exist:' => 'Es existieren noch die folgenden alten Dateien, deren Einstellungen manuell in die neue Konfiguratsdatei "config/kivitendo.conf" migriert werden müssen:',
|
||
'The following parts could not be allocated:' => 'Die folgenden Artikel konnten nicht für die Produktion belegt werden:',
|
||
'The following transaction contains wrong taxes:' => 'Die folgende Buchung enthält falsche Steuern:',
|
||
'The following transaction contains wrong taxkeys:' => 'Die folgende Buchung enthält falsche Steuerschlüssel:',
|
||
'The following transactions are concerned:' => 'Die folgenden Buchungen sind betroffen:',
|
templates/design40_webpages/wh/produce_assembly_error.html | ||
---|---|---|
[%- USE T8 %][%- USE HTML %][%- USE LxERP -%][%- USE L -%]
|
||
|
||
<div class="message message_error">
|
||
<h4>[% LxERP.t8("Error!") %]</h4>
|
||
</div>
|
||
|
||
[% IF missing_qty_exceptions.size %]
|
||
<div class="wrapper">[% LxERP.t8("The following parts could not be allocated:") %]</div>
|
||
|
||
<div class="wrapper">
|
||
<table class="tbl-list">
|
||
<thead>
|
||
<tr>
|
||
<th>[% LxERP.t8("Part") %]</th>
|
||
<th class="right">[% LxERP.t8("Required qty") %]</th>
|
||
<th class="right">[% LxERP.t8("Missing qty") %]</th>
|
||
</tr>
|
||
</thead>
|
||
|
||
<tbody>
|
||
[% FOREACH ex = missing_qty_exceptions %]
|
||
<tr class="listrow">
|
||
<td>[% HTML.escape(ex.part_description) %]</td>
|
||
<td class="numeric">[% HTML.escape(LxERP.format_amount(ex.to_allocate_qty)) %]</td>
|
||
<td class="numeric">[% HTML.escape(LxERP.format_amount(ex.missing_qty)) %]</td>
|
||
</tr>
|
||
[% END %]
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
[% END %]
|
||
|
||
[% IF other_exceptions.size %]
|
||
<div class="wrapper">[% LxERP.t8("Additional errors:") %]</div>
|
||
|
||
<div class="wrapper">
|
||
<ul>
|
||
[% FOREACH ex = other_exceptions %]
|
||
<li>[% HTML.escape(ex.message) %]</li>
|
||
[% END %]
|
||
</ul>
|
||
</div>
|
||
[% END %]
|
templates/webpages/wh/produce_assembly_error.html | ||
---|---|---|
[%- USE T8 %][%- USE HTML %][%- USE LxERP -%][%- USE L -%]
|
||
|
||
<div class="message_error">
|
||
<p>[% LxERP.t8("Error!") %]</p>
|
||
|
||
<p class="message_error_label">[% LxERP.t8("The assembly could not be produced.") %]</p>
|
||
</div>
|
||
|
||
[% IF missing_qty_exceptions.size %]
|
||
<p>[% LxERP.t8("The following parts could not be allocated:") %]</p>
|
||
|
||
<div>
|
||
<table>
|
||
<thead>
|
||
<tr class="listheading">
|
||
<th>[% LxERP.t8("Part") %]</th>
|
||
<th align="right">[% LxERP.t8("Required qty") %]</th>
|
||
<th align="right">[% LxERP.t8("Missing qty") %]</th>
|
||
</tr>
|
||
</thead>
|
||
|
||
<tbody>
|
||
[% FOREACH ex = missing_qty_exceptions %]
|
||
<tr class="listrow">
|
||
<td>[% HTML.escape(ex.part_description) %]</td>
|
||
<td align="right">[% HTML.escape(LxERP.format_amount(ex.to_allocate_qty)) %]</td>
|
||
<td align="right">[% HTML.escape(LxERP.format_amount(ex.missing_qty)) %]</td>
|
||
</tr>
|
||
[% END %]
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
[% END %]
|
||
|
||
[% IF other_exceptions.size %]
|
||
<p>[% LxERP.t8("Additional errors:") %]</p>
|
||
|
||
<div>
|
||
<ul>
|
||
[% FOREACH ex = other_exceptions %]
|
||
<li>[% HTML.escape(ex.message) %]</li>
|
||
[% END %]
|
||
</ul>
|
||
</div>
|
||
[% END %]
|
Auch abrufbar als: Unified diff
Erzeugnis fertigen: alle möglichen Allokationsfehler auf einmal anzeigen