Revision 666d4cad
Von Sven Schöling vor mehr als 11 Jahren hinzugefügt
SL/Controller/Inventory.pm | ||
---|---|---|
1 |
package SL::Controller::Inventory; |
|
2 |
|
|
3 |
use strict; |
|
4 |
use warnings; |
|
5 |
|
|
6 |
use parent qw(SL::Controller::Base); |
|
7 |
|
|
8 |
use SL::DB::Inventory; |
|
9 |
use SL::DB::Part; |
|
10 |
use SL::DB::Warehouse; |
|
11 |
use SL::DB::Unit; |
|
12 |
use SL::WH; |
|
13 |
use SL::Locale::String qw(t8); |
|
14 |
use SL::ClientJS; |
|
15 |
use SL::Presenter; |
|
16 |
use SL::DBUtils; |
|
17 |
use SL::Helper::Flash; |
|
18 |
|
|
19 |
use Rose::Object::MakeMethods::Generic ( |
|
20 |
'scalar --get_set_init' => [ qw(warehouses units js p) ], |
|
21 |
'scalar' => [ qw(warehouse bin unit part) ], |
|
22 |
); |
|
23 |
|
|
24 |
__PACKAGE__->run_before('_check_auth'); |
|
25 |
__PACKAGE__->run_before('_check_warehouses'); |
|
26 |
__PACKAGE__->run_before('load_part_from_form', only => [ qw(stock_in part_changed mini_stock stock) ]); |
|
27 |
__PACKAGE__->run_before('load_unit_from_form', only => [ qw(stock_in part_changed mini_stock stock) ]); |
|
28 |
__PACKAGE__->run_before('load_wh_from_form', only => [ qw(stock_in warehouse_changed stock) ]); |
|
29 |
__PACKAGE__->run_before('load_bin_from_form', only => [ qw(stock_in stock) ]); |
|
30 |
__PACKAGE__->run_before('set_target_from_part', only => [ qw(part_changed) ]); |
|
31 |
__PACKAGE__->run_before('sanitize_target', only => [ qw(stock_in warehouse_changed part_changed) ]); |
|
32 |
__PACKAGE__->run_before('set_layout'); |
|
33 |
|
|
34 |
sub action_stock_in { |
|
35 |
my ($self) = @_; |
|
36 |
|
|
37 |
$::form->{title} = t8('Stock'); |
|
38 |
|
|
39 |
$::request->layout->focus('#part_id_name'); |
|
40 |
$_[0]->render('inventory/warehouse_selection_stock', title => $::form->{title}); |
|
41 |
} |
|
42 |
|
|
43 |
sub action_stock { |
|
44 |
my ($self) = @_; |
|
45 |
|
|
46 |
# do stock |
|
47 |
WH->transfer({ |
|
48 |
parts => $self->part, |
|
49 |
dst_bin => $self->bin, |
|
50 |
dst_wh => $self->warehouse, |
|
51 |
qty => $::form->format_amount(\%::myconfig, $::form->{qty}), |
|
52 |
unit => $self->unit, |
|
53 |
transfer_type => 'stock', |
|
54 |
chargenumber => $::form->{chargenumber}, |
|
55 |
ean => $::form->{ean}, |
|
56 |
comment => $::form->{comment}, |
|
57 |
}); |
|
58 |
|
|
59 |
if ($::form->{write_default_bin}) { |
|
60 |
$self->part->bin($self->bin); |
|
61 |
$self->part->warehouse($self->warehouse); |
|
62 |
$self->part->save; |
|
63 |
} |
|
64 |
|
|
65 |
flash_later('info', t8('Transfer successful')); |
|
66 |
|
|
67 |
# redirect |
|
68 |
$self->redirect_to( |
|
69 |
action => 'stock_in', |
|
70 |
part_id => $self->part->id, |
|
71 |
bin_id => $self->bin->id, |
|
72 |
warehouse_id => $self->warehouse->id, |
|
73 |
); |
|
74 |
} |
|
75 |
|
|
76 |
sub action_part_changed { |
|
77 |
my ($self) = @_; |
|
78 |
|
|
79 |
# no standard? ask user if he wants to write it |
|
80 |
if ($self->part->id && !$self->part->bin_id && !$self->part->warehouse_id) { |
|
81 |
$self->js->show('#write_default_bin_span'); |
|
82 |
} else { |
|
83 |
$self->js->hide('#write_default_bin_span') |
|
84 |
->removeAttr('#write_default_bin', 'checked'); |
|
85 |
} |
|
86 |
|
|
87 |
$self->js |
|
88 |
->replaceWith('#warehouse_id', $self->build_warehouse_select) |
|
89 |
->replaceWith('#bin_id', $self->build_bin_select) |
|
90 |
->replaceWith('#unit_id', $self->build_unit_select) |
|
91 |
->focus('#warehouse_id') |
|
92 |
->render($self); |
|
93 |
} |
|
94 |
|
|
95 |
sub action_warehouse_changed { |
|
96 |
my ($self) = @_; |
|
97 |
|
|
98 |
$self->js |
|
99 |
->replaceWith('#bin_id', $self->build_bin_select) |
|
100 |
->focus('#bin_id') |
|
101 |
->render($self); |
|
102 |
} |
|
103 |
|
|
104 |
sub action_mini_stock { |
|
105 |
my ($self) = @_; |
|
106 |
|
|
107 |
my $stock = $self->part->get_simple_stock; |
|
108 |
my $stock_by_bin = { map { $_->{bin_id} => $_ } @$stock }; |
|
109 |
my $stock_empty = ! grep { $_->{sum} * 1 } @$stock; |
|
110 |
|
|
111 |
$self->js |
|
112 |
->html('#stock', $self->render('inventory/_stock', { output => 0 }, stock => $stock_by_bin, stock_empty => $stock_empty )) |
|
113 |
->render($self); |
|
114 |
} |
|
115 |
|
|
116 |
sub action_last_journal { |
|
117 |
my ($self) = @_; |
|
118 |
|
|
119 |
# my $jounal = $self->journal; |
|
120 |
|
|
121 |
} |
|
122 |
|
|
123 |
#================================================================ |
|
124 |
|
|
125 |
sub _check_auth { |
|
126 |
$main::auth->assert('warehouse_management'); |
|
127 |
} |
|
128 |
|
|
129 |
sub _check_warehouses { |
|
130 |
$_[0]->show_no_warehouses_error if !@{ $_[0]->warehouses }; |
|
131 |
} |
|
132 |
|
|
133 |
sub init_warehouses { |
|
134 |
SL::DB::Manager::Warehouse->get_all; |
|
135 |
} |
|
136 |
|
|
137 |
sub init_units { |
|
138 |
SL::DB::Manager::Unit->get_all; |
|
139 |
} |
|
140 |
|
|
141 |
sub init_js { |
|
142 |
SL::ClientJS->new; |
|
143 |
} |
|
144 |
|
|
145 |
sub init_p { |
|
146 |
SL::Presenter->get; |
|
147 |
} |
|
148 |
|
|
149 |
sub set_target_from_part { |
|
150 |
my ($self) = @_; |
|
151 |
|
|
152 |
return if !$self->part; |
|
153 |
|
|
154 |
$self->warehouse($self->part->warehouse) if $self->part->warehouse; |
|
155 |
$self->bin( $self->part->bin) if $self->part->bin; |
|
156 |
} |
|
157 |
|
|
158 |
sub sanitize_target { |
|
159 |
my ($self) = @_; |
|
160 |
|
|
161 |
$self->warehouse(SL::DB::Manager::Warehouse->get_first) if !$self->warehouse || !$self->warehouse->id; |
|
162 |
$self->bin ($self->warehouse->bins->[0]) if !$self->bin || !$self->bin->id; |
|
163 |
} |
|
164 |
|
|
165 |
sub load_part_from_form { |
|
166 |
$_[0]->part(SL::DB::Manager::Part->find_by_or_create(id => $::form->{part_id})); |
|
167 |
} |
|
168 |
|
|
169 |
sub load_unit_from_form { |
|
170 |
$_[0]->unit(SL::DB::Manager::Unit->find_by_or_create(id => $::form->{unit_id})); |
|
171 |
} |
|
172 |
|
|
173 |
sub load_wh_from_form { |
|
174 |
$_[0]->warehouse(SL::DB::Manager::Warehouse->find_by_or_create(id => $::form->{warehouse_id})); |
|
175 |
} |
|
176 |
|
|
177 |
sub load_bin_from_form { |
|
178 |
$_[0]->bin(SL::DB::Manager::Bin->find_by_or_create(id => $::form->{bin_id})); |
|
179 |
} |
|
180 |
|
|
181 |
sub set_layout { |
|
182 |
$::request->layout->add_javascripts('client_js.js'); |
|
183 |
} |
|
184 |
|
|
185 |
sub build_warehouse_select { |
|
186 |
$_[0]->p->select_tag('warehouse_id', $_[0]->warehouses, |
|
187 |
title_key => 'description', |
|
188 |
default => $_[0]->warehouse->id, |
|
189 |
onchange => 'reload_bin_selection()', |
|
190 |
) |
|
191 |
} |
|
192 |
|
|
193 |
sub build_bin_select { |
|
194 |
$_[0]->p->select_tag('bin_id', [ $_[0]->warehouse->bins ], |
|
195 |
title_key => 'description', |
|
196 |
default => $_[0]->bin->id, |
|
197 |
); |
|
198 |
} |
|
199 |
|
|
200 |
sub build_unit_select { |
|
201 |
$_[0]->part->id |
|
202 |
? $_[0]->p->select_tag('unit_id', $_[0]->part->available_units, |
|
203 |
title_key => 'name', |
|
204 |
default => $_[0]->part->unit_obj->id, |
|
205 |
) |
|
206 |
: $_[0]->p->select_tag('unit_id', $_[0]->units, |
|
207 |
title_key => 'name', |
|
208 |
) |
|
209 |
} |
|
210 |
|
|
211 |
sub mini_journal { |
|
212 |
my ($self) = @_; |
|
213 |
|
|
214 |
# get last 10 transaction ids |
|
215 |
my $query = 'SELECT trans_id, max(itime) FROM inventory GROUP BY trans_id ORDER BY max(itime) DESC LIMIT 10'; |
|
216 |
my @ids = selectall_array_query($::form, $::form->get_standard_dbh, $query); |
|
217 |
|
|
218 |
my $objs = SL::DB::Manager::Inventory->get_all(query => [ trans_id => \@ids ]); |
|
219 |
|
|
220 |
# at most 2 of them belong to a transaction and the qty determins in or out. |
|
221 |
# sort them for display |
|
222 |
my %transactions; |
|
223 |
for (@$objs) { |
|
224 |
$transactions{ $_->trans_id }{ $_->qty > 0 ? 'in' : 'out' } = $_; |
|
225 |
$transactions{ $_->trans_id }{base} = $_; |
|
226 |
} |
|
227 |
# and get them into order again |
|
228 |
my @sorted = map { $transactions{$_} } @ids; |
|
229 |
|
|
230 |
return \@sorted; |
|
231 |
} |
|
232 |
|
|
233 |
sub show_no_warehouse_error { |
|
234 |
my ($self) = @_; |
|
235 |
|
|
236 |
my $msg = t8('No warehouse has been created yet or the quantity of the bins is not configured yet.') . ' '; |
|
237 |
|
|
238 |
if ($::auth->check_right($::form->{login}, 'config')) { # TODO wut? |
|
239 |
$msg .= t8('You can create warehouses and bins via the menu "System -> Warehouses".'); |
|
240 |
} else { |
|
241 |
$msg .= t8('Please ask your administrator to create warehouses and bins.'); |
|
242 |
} |
|
243 |
$::form->show_generic_error($msg); |
|
244 |
} |
|
245 |
|
|
246 |
1; |
SL/DB/Bin.pm | ||
---|---|---|
8 | 8 |
|
9 | 9 |
__PACKAGE__->meta->make_manager_class; |
10 | 10 |
|
11 |
sub full_description { |
|
12 |
my ($self) = @_; |
|
13 |
|
|
14 |
$self->warehouse |
|
15 |
? $self->warehouse->description . "/" . $self->description |
|
16 |
: $self->description |
|
17 |
} |
|
18 |
|
|
11 | 19 |
1; |
SL/DB/Part.pm | ||
---|---|---|
179 | 179 |
return $charts->{$taxzone}->{$type}; |
180 | 180 |
} |
181 | 181 |
|
182 |
# this is designed to ignore chargenumbers, expiration dates and just give a list of how much <-> where |
|
183 |
sub get_simple_stock { |
|
184 |
my ($self, %params) = @_; |
|
185 |
|
|
186 |
return [] unless $self->id; |
|
187 |
|
|
188 |
my $query = <<''; |
|
189 |
SELECT sum(qty), warehouse_id, bin_id FROM inventory WHERE parts_id = ? |
|
190 |
GROUP BY warehouse_id, bin_id |
|
191 |
|
|
192 |
my $stock_info = selectall_hashref_query($::form, $::form->get_standard_dbh, $query, $self->id); |
|
193 |
[ map { bless $_, 'SL::DB::Part::SimpleStock'} @$stock_info ]; |
|
194 |
} |
|
195 |
# helper class to have bin/warehouse accessors in stock result |
|
196 |
{ package SL::DB::Part::SimpleStock; |
|
197 |
sub warehouse { require SL::DB::Warehouse; SL::DB::Manager::Warehouse->find_by_or_create(id => $_[0]->{warehouse_id}) } |
|
198 |
sub bin { require SL::DB::Bin; SL::DB::Manager::Bin ->find_by_or_create(id => $_[0]->{bin_id}) } |
|
199 |
} |
|
200 |
|
|
182 | 201 |
sub long_description { |
183 | 202 |
join ' ', grep $_, map $_[0]->$_, qw(partnumber description); |
184 | 203 |
} |
css/lx-office-erp/main.css | ||
---|---|---|
54 | 54 |
background-color: whitesmoke; |
55 | 55 |
} |
56 | 56 |
|
57 |
button:hover, |
|
58 |
input[type="button"]:hover, |
|
59 |
input[type="submit"]:hover { |
|
57 |
button:hover:enabled,
|
|
58 |
input[type="button"]:hover:enabled,
|
|
59 |
input[type="submit"]:hover:enabled {
|
|
60 | 60 |
border: 1px; |
61 | 61 |
background-color: lightgray; |
62 | 62 |
border-color: gray; |
locale/de/all | ||
---|---|---|
1121 | 1121 |
'Jan' => 'Jan', |
1122 | 1122 |
'January' => 'Januar', |
1123 | 1123 |
'Journal' => 'Buchungsjournal', |
1124 |
'Journal of Last 10 Transfers' => 'Letzte 10 Lagertransaktionen', |
|
1124 | 1125 |
'Jul' => 'Jul', |
1125 | 1126 |
'July' => 'Juli', |
1126 | 1127 |
'Jump to' => 'Springe zu', |
... | ... | |
1322 | 1323 |
'No shipto selected to delete' => 'Keine Lieferadresse zum Löschen ausgewählt', |
1323 | 1324 |
'No summary account' => 'Kein Sammelkonto', |
1324 | 1325 |
'No transaction selected!' => 'Keine Transaktion ausgewählt', |
1326 |
'No transactions yet.' => 'Bisher keine Buchungen.', |
|
1325 | 1327 |
'No transfers were executed in this export.' => 'In diesem SEPA-Export wurden keine Überweisungen ausgeführt.', |
1326 | 1328 |
'No users have been created yet.' => 'Es wurden noch keine Benutzer anleget.', |
1327 | 1329 |
'No valid number entered for pricegroup "#1".' => 'Für Preisgruppe "#1" wurde keine gültige Nummer eingegeben.', |
... | ... | |
1343 | 1345 |
'Nothing has been selected for removal.' => 'Es wurde nichts für eine Entnahme ausgewählt.', |
1344 | 1346 |
'Nothing has been selected for transfer.' => 'Es wurde nichts zum Umlagern ausgewählt.', |
1345 | 1347 |
'Nothing selected!' => 'Es wurde nichts ausgewählt!', |
1348 |
'Nothing stocked yet.' => 'Noch nichts eingelagert.', |
|
1346 | 1349 |
'Nov' => 'Nov', |
1347 | 1350 |
'November' => 'November', |
1348 | 1351 |
'Number' => 'Nummer', |
... | ... | |
1871 | 1874 |
'Steuersatz' => 'Steuersatz', |
1872 | 1875 |
'Stock' => 'Einlagern', |
1873 | 1876 |
'Stock Qty for Date' => 'Lagerbestand am', |
1877 |
'Stock for part #1' => 'Bestand für Artikel #1', |
|
1874 | 1878 |
'Stock value' => 'Bestandswert', |
1875 | 1879 |
'Stocked Qty' => 'Lagermenge', |
1876 | 1880 |
'Stop task server' => 'Task-Server beenden', |
... | ... | |
2248 | 2252 |
'Transfer out' => 'Auslagern', |
2249 | 2253 |
'Transfer out via default' => 'Auslagern über Standard-Lagerplatz', |
2250 | 2254 |
'Transfer qty' => 'Umlagermenge', |
2255 |
'Transfer successful' => 'Lagervorgang erfolgreich', |
|
2251 | 2256 |
'Translation' => 'Übersetzung', |
2252 | 2257 |
'Trial Balance' => 'Summen- und Saldenliste', |
2253 | 2258 |
'Trial balance between %s and %s' => 'Summen- und Saldenlisten vom %s bis zum %s', |
... | ... | |
2374 | 2379 |
'Workflow request_quotation' => 'Workflow Preisanfrage', |
2375 | 2380 |
'Workflow sales_order' => 'Workflow Auftrag', |
2376 | 2381 |
'Workflow sales_quotation' => 'Workflow Angebot', |
2382 |
'Write bin to default bin in part?' => 'Diesen Lagerplatz als Standardlagerplatz im Artikel setzen?', |
|
2377 | 2383 |
'Wrong Period' => 'Falscher Zeitraum', |
2378 | 2384 |
'Wrong tax keys recorded' => 'Gespeicherte Steuerschlüssel sind falsch', |
2379 | 2385 |
'Wrong taxes recorded' => 'Gespeicherte Steuern passen nicht zum Steuerschlüssel', |
menu.ini | ||
---|---|---|
229 | 229 |
|
230 | 230 |
[Warehouse--Stock] |
231 | 231 |
ACCESS=warehouse_management |
232 |
module=wh.pl |
|
233 |
action=transfer_warehouse_selection |
|
234 |
trans_type=stock |
|
232 |
module=controller.pl |
|
233 |
action=Inventory/stock_in |
|
235 | 234 |
|
236 | 235 |
[Warehouse--Produce Assembly] |
237 | 236 |
ACCESS=warehouse_management |
templates/webpages/inventory/_journal.html | ||
---|---|---|
1 |
[% USE L %] |
|
2 |
[% USE HTML %] |
|
3 |
[% USE LxERP %] |
|
4 |
[% USE T8 %] |
|
5 |
<h3>[% 'Journal of Last 10 Transfers' | $T8 %]</h3> |
|
6 |
|
|
7 |
[%- IF journal.size %] |
|
8 |
<table> |
|
9 |
<tr class='listheading'> |
|
10 |
<th>[% 'Date' | $T8 %]</th> |
|
11 |
<th>[% 'Trans Type' | $T8 %]</th> |
|
12 |
<th>[% 'Part' | $T8 %]</th> |
|
13 |
<th>[% 'Warehouse From' | $T8 %]</th> |
|
14 |
<th>[% 'Qty' | $T8 %]</th> |
|
15 |
<th>[% 'Unit' | $T8 %]</th> |
|
16 |
<th>[% 'Warehouse To' | $T8 %]</th> |
|
17 |
<th>[% 'Charge Number' | $T8 %]</th> |
|
18 |
<th>[% 'Comment' | $T8 %]</th> |
|
19 |
</tr> |
|
20 |
[% FOREACH row = journal %] |
|
21 |
<tr class='listrow'> |
|
22 |
<td>[% row.base.itime_as_date %]</td> |
|
23 |
<td>[% row.base.trans_type.description | $T8 %]</td> |
|
24 |
<td>[% row.base.part.long_description | html %]</td> |
|
25 |
<td>[% row.out ? row.out.bin.full_description : '-' | html %]</td> |
|
26 |
<td class='numeric'>[% row.in ? row.in.qty_as_number : LxERP.format_amount(-1 * row.out.qty, 2) %]</td> |
|
27 |
<td>[% row.base.part.unit | html %]</td> |
|
28 |
<td>[% row.in ? row.in.bin.full_description : '-' | html %]</td> |
|
29 |
<td>[% row.base.chargenumber | html %]</td> |
|
30 |
<td>[% row.base.comment | html %]</td> |
|
31 |
</tr> |
|
32 |
[% END %] |
|
33 |
</table> |
|
34 |
[%- ELSE %] |
|
35 |
<p>[% 'No transactions yet.' | $T8 %]</p> |
|
36 |
[%- END %] |
templates/webpages/inventory/_stock.html | ||
---|---|---|
1 |
[%- USE HTML %] |
|
2 |
[%- USE LxERP %] |
|
3 |
[%- USE L %] |
|
4 |
[%- USE T8 %] |
|
5 |
[%- IF SELF.part.id %] |
|
6 |
<h3>[% LxERP.t8('Stock for part #1', SELF.part.long_description) %]</h3> |
|
7 |
|
|
8 |
[%- IF stock_empty && !SELF.part.bin_id %] |
|
9 |
<p>[% 'Nothing stocked yet.' | $T8 %]</p> |
|
10 |
[%- ELSE %] |
|
11 |
<table> |
|
12 |
<tr class='listheading'> |
|
13 |
<th>[% 'Warehouse' | $T8 %]</th> |
|
14 |
<th>[% 'Bin' | $T8 %]</th> |
|
15 |
<th>[% 'Qty' | $T8 %]</th> |
|
16 |
</tr> |
|
17 |
[%- FOREACH wh = SELF.warehouses -%] |
|
18 |
[%- FOREACH bin = wh.bins -%] |
|
19 |
[%#- display any bins with stock and default bin -%] |
|
20 |
[%- SET stock__set = stock.${bin.id} -%] |
|
21 |
[%- IF stock__set.sum > 0 || SELF.part.bin_id == bin.id -%] |
|
22 |
<tr class='listrow'> |
|
23 |
<td>[% bin.warehouse.description %]</td> |
|
24 |
<td>[% bin.description %]</td> |
|
25 |
<td class='numeric'>[% LxERP.format_amount(stock__set.sum, 2) %]</td> |
|
26 |
</tr> |
|
27 |
[%- END -%] |
|
28 |
[%- END -%] |
|
29 |
[%- END %] |
|
30 |
</table> |
|
31 |
[%- END %] |
|
32 |
[%- END %] |
templates/webpages/inventory/warehouse_selection_stock.html | ||
---|---|---|
1 |
[%- USE T8 %] |
|
2 |
[%- USE L %] |
|
3 |
[%- USE HTML %] |
|
4 |
[%- USE LxERP %] |
|
5 |
|
|
6 |
<h1>[% title | html %]</div> |
|
7 |
|
|
8 |
[%- PROCESS 'common/flash.html' %] |
|
9 |
|
|
10 |
<form name="Form" method="post" action="controller.pl"> |
|
11 |
|
|
12 |
<table> |
|
13 |
<tr> |
|
14 |
<th align="right" nowrap>[% 'Part' | $T8 %]</th> |
|
15 |
<td>[% L.part_picker('part_id', SELF.part) %]</td> |
|
16 |
</tr> |
|
17 |
|
|
18 |
<tr> |
|
19 |
<th align="right" nowrap>[% 'Destination warehouse' | $T8 %]</th> |
|
20 |
<td>[% L.select_tag('warehouse_id', SELF.warehouses, default=SELF.warehouse.id, title_key='description') %] |
|
21 |
[% IF SELF.warehouse.id %] |
|
22 |
[% L.select_tag('bin_id', SELF.warehouse.bins, default=SELF.bin.id, title_key='description') %] |
|
23 |
[%- ELSE %] |
|
24 |
<span id='bin_id'></span> |
|
25 |
[% END %] |
|
26 |
<span id='write_default_bin_span' style='display:none'><br>[% L.checkbox_tag('write_default_bin', label=LxERP.t8('Write bin to default bin in part?')) %]</span> |
|
27 |
</td> |
|
28 |
</tr> |
|
29 |
|
|
30 |
<tr> |
|
31 |
<th align="right" nowrap>[% 'Charge number' | $T8 %]</th> |
|
32 |
<td>[% L.input_tag('chargenumber', SELF.chargenumber, size=30) %]</td> |
|
33 |
</tr> |
|
34 |
|
|
35 |
[% IF INSTANCE_CONF.get_show_bestbefore %] |
|
36 |
<tr> |
|
37 |
<th align="right" nowrap>[% 'Best Before' | $T8 %]</th> |
|
38 |
<td>[% L.date_tag('bestbefore', SELF.bestbefore) %]</td> |
|
39 |
</tr> |
|
40 |
[%- END %] |
|
41 |
|
|
42 |
<tr> |
|
43 |
<th align="right" nowrap>[% 'EAN' | $T8 %]</th> |
|
44 |
<td><input name="ean" size="30" value="[% HTML.escape(ean) %]"></td> |
|
45 |
</tr> |
|
46 |
|
|
47 |
<tr> |
|
48 |
<th align="right" nowrap>[% 'Quantity' | $T8 %]</th> |
|
49 |
<td> |
|
50 |
<input name="qty" size="10" value="[% HTML.escape(LxERP.format_amount(qty)) %]"> |
|
51 |
[%- IF SELF.part.unit %] |
|
52 |
[% L.select_tag('unit_id', SELF.part.available_units, title_key='name', default=SELF.unit.id) %] |
|
53 |
[%- ELSE %] |
|
54 |
[% L.select_tag('unit_id', SELF.units, title_key='name') %] |
|
55 |
[%- END %] |
|
56 |
</td> |
|
57 |
</tr> |
|
58 |
|
|
59 |
<tr> |
|
60 |
<th align="right" nowrap>[% 'Optional comment' | $T8 %]</th> |
|
61 |
<td><input name="comment" size="60" value="[% HTML.escape(comment) %]"></td> |
|
62 |
</tr> |
|
63 |
</table> |
|
64 |
|
|
65 |
<input type="hidden" name="action" value="Inventory/dispatch"> |
|
66 |
<input type="submit" id='action_stock' class="submit" name="action_stock" value="[% 'Stock' | $T8 %]" [% IF !SELF.part.id %]disabled[% END %]> |
|
67 |
</form> |
|
68 |
|
|
69 |
<div id='stock'> |
|
70 |
[%- PROCESS 'inventory/_stock.html' %] |
|
71 |
</div> |
|
72 |
<div id='journal'> |
|
73 |
[%- PROCESS 'inventory/_journal.html' journal=SELF.mini_journal %] |
|
74 |
</div> |
|
75 |
|
|
76 |
<script type='text/javascript'> |
|
77 |
function reload_warehouse_selection () { |
|
78 |
$.post("controller.pl", { action: 'Inventory/part_changed', part_id: function(){ return $('#part_id').val() } }, kivi.eval_json_result); |
|
79 |
$.post("controller.pl", { action: 'Inventory/mini_stock', part_id: function(){ return $('#part_id').val() } }, kivi.eval_json_result); |
|
80 |
} |
|
81 |
function reload_bin_selection () { |
|
82 |
$.post("controller.pl", { action: 'Inventory/warehouse_changed', warehouse_id: function(){ return $('#warehouse_id').val() } }, kivi.eval_json_result); |
|
83 |
} |
|
84 |
$(function(){ |
|
85 |
$('#part_id').change(reload_warehouse_selection); |
|
86 |
$('#part_id').change(function(){ |
|
87 |
if ($('#part_id').val() > 0) |
|
88 |
$('#action_stock').removeAttr('disabled'); |
|
89 |
else |
|
90 |
$('#action_stock').attr('disabled', 'disabled'); |
|
91 |
}); |
|
92 |
$('#warehouse_id').change(reload_bin_selection); |
|
93 |
}) |
|
94 |
</script> |
Auch abrufbar als: Unified diff
Inventory Controller und neue stock_in Maske
Alte Methode ist weiter im Code vorhanden, wird aber geplant nach und nach
durch das neue Interface ersetzt.
Benötigt Partpicker