Revision c7ad052c
Von Kivitendo Admin vor mehr als 1 Jahr hinzugefügt
SL/Controller/DispositionManager.pm | ||
---|---|---|
1 |
package SL::Controller::DispositionManager; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use parent qw(SL::Controller::Base); |
|
6 |
|
|
7 |
use SL::DB::Part; |
|
8 |
use SL::DB::PurchaseBasketItem; |
|
9 |
use SL::PriceSource; |
|
10 |
use SL::Locale::String qw(t8); |
|
11 |
use Data::Dumper; |
|
12 |
|
|
13 |
sub action_list_parts { |
|
14 |
my ( $self ) = @_; |
|
15 |
|
|
16 |
my $parts = $self->_get_parts; |
|
17 |
|
|
18 |
$self->_setup_list_action_bar; |
|
19 |
$self->render('disposition_manager/list_parts', title => t8('Parts short onhand'), PARTS => $parts); |
|
20 |
} |
|
21 |
|
|
22 |
sub action_add_to_purchase_basket{ |
|
23 |
my ( $self ) = @_; |
|
24 |
|
|
25 |
my $parts_to_add = delete($::form->{ids}) || []; |
|
26 |
foreach my $id (@{ $parts_to_add }) { |
|
27 |
my $part = SL::DB::Manager::Part->find_by(id => $id) or die "Can't find part with id: $id\n"; |
|
28 |
my $basket_part = SL::DB::PurchaseBasketItem->new( |
|
29 |
parts_id => $part->id, |
|
30 |
qty => $part->min_order_qty, # was ist wenn min_order_qty < (rop-onhand) ist? sollte dann nicht (rop-onhand) genommen werden? |
|
31 |
description => $part->description, # Warum wird description zusätzlich gespeichert, parts_id sollte doch reichen? Falls die sich in den Stammdaten in der Zwischenzeit verändert? zumal du in action_transfer_to_purchase_order explizit $part->description verwendest |
|
32 |
)->save; |
|
33 |
} |
|
34 |
$self->action_show_basket; |
|
35 |
|
|
36 |
} |
|
37 |
|
|
38 |
sub action_show_basket { |
|
39 |
my ( $self ) = @_; |
|
40 |
|
|
41 |
$::request->{layout}->add_javascripts('kivi.DispositionManager.js'); |
|
42 |
my $basket_items = SL::DB::Manager::PurchaseBasketItem->get_all( query => [ cleared => 'F' ], with_objects => [ 'part', 'part.makemodels' ]); |
|
43 |
$self->_setup_show_basket_action_bar; |
|
44 |
$self->render('disposition_manager/show_purchase_basket', BASKET_ITEMS => $basket_items, title => "Purchase basket" ); |
|
45 |
} |
|
46 |
|
|
47 |
sub action_transfer_to_purchase_order { |
|
48 |
|
|
49 |
my ( $self ) = @_; |
|
50 |
require SL::DB::Order; |
|
51 |
require SL::DB::OrderItem; |
|
52 |
require SL::DB::Part; |
|
53 |
require SL::DB::Vendor; |
|
54 |
my @error_report; |
|
55 |
|
|
56 |
my $v_id = $::form->{vendor_ids}->[0] ; |
|
57 |
|
|
58 |
my ($vendor, $employee); |
|
59 |
$vendor = SL::DB::Manager::Vendor->find_by(id => $v_id) or die "Can't find vendor"; |
|
60 |
$employee = SL::DB::Manager::Employee->current or die "Can't find employee"; |
|
61 |
|
|
62 |
my $basket_items = SL::DB::Manager::PurchaseBasketItem->get_all( query => [ id => \@{ $::form->{ids} } ] ); |
|
63 |
|
|
64 |
# create order first so we have a record for PriceSource |
|
65 |
my $order = SL::DB::Order->new( |
|
66 |
vendor_id => $vendor->id, |
|
67 |
employee_id => $employee->id, |
|
68 |
intnotes => $vendor->notes, |
|
69 |
salesman_id => $employee->id, |
|
70 |
payment_id => $vendor->payment_id, |
|
71 |
taxzone_id => $vendor->taxzone_id, |
|
72 |
currency_id => $vendor->currency_id, |
|
73 |
transdate => DateTime->today_local |
|
74 |
); |
|
75 |
|
|
76 |
my $i = 0; |
|
77 |
my @items; |
|
78 |
|
|
79 |
foreach my $basket_item ( @{ $basket_items } ) { |
|
80 |
$i++; |
|
81 |
my $mm = SL::DB::Manager::MakeModel->get_first( query => [ make => $vendor->id, parts_id => $basket_item->parts_id] ); |
|
82 |
|
|
83 |
my $current_order_item = SL::DB::OrderItem->new( |
|
84 |
part => $basket_item->part, |
|
85 |
description => $basket_item->part->description, |
|
86 |
qty => $basket_item->qty || 1, |
|
87 |
unit => $basket_item->part->unit, |
|
88 |
position => $i, |
|
89 |
); |
|
90 |
|
|
91 |
my $price_source = SL::PriceSource->new(record_item => $current_order_item, record => $order); |
|
92 |
$current_order_item->sellprice($price_source->best_price->price); |
|
93 |
$current_order_item->active_price_source($price_source->best_price->source); |
|
94 |
push(@items, $current_order_item); |
|
95 |
} |
|
96 |
|
|
97 |
$order->orderitems( [ @items ] ); |
|
98 |
$order->db->with_transaction( sub { |
|
99 |
$order->calculate_prices_and_taxes; |
|
100 |
$order->save; |
|
101 |
|
|
102 |
my $snumbers = "ordernumber_" . $order->ordnumber; |
|
103 |
SL::DB::History->new( |
|
104 |
trans_id => $order->id, |
|
105 |
snumbers => $snumbers, |
|
106 |
employee_id => SL::DB::Manager::Employee->current->id, |
|
107 |
addition => 'SAVED', |
|
108 |
what_done => 'PurchaseBasket->Order', |
|
109 |
)->save(); |
|
110 |
foreach my $item(@{ $order->orderitems }){ |
|
111 |
$item->parse_custom_variable_values->save; |
|
112 |
$item->{custom_variables} = \@{ $item->cvars_by_config }; |
|
113 |
$item->save; |
|
114 |
} |
|
115 |
SL::DB::Manager::PurchaseBasketItem->delete_all( where => [ id => \@{ $::form->{ids} }]); |
|
116 |
return 1; |
|
117 |
}) || die "error: " . $order->db->error; |
|
118 |
$self->redirect_to(controller => "oe.pl", action => 'edit', type => 'purchase_order', vc => 'vendor', id => $order->id); |
|
119 |
} |
|
120 |
|
|
121 |
sub _get_parts { |
|
122 |
my ($self) = @_; |
|
123 |
|
|
124 |
my $query = <<SQL; |
|
125 |
SELECT * |
|
126 |
FROM parts |
|
127 |
WHERE onhand <= rop |
|
128 |
AND rop != 0 |
|
129 |
AND id NOT IN( SELECT parts_id FROM purchase_basket_items ) |
|
130 |
AND NOT obsolete |
|
131 |
SQL |
|
132 |
|
|
133 |
return SL::DB::Manager::Part->get_objects_from_sql( sql => $query ); |
|
134 |
}; |
|
135 |
|
|
136 |
|
|
137 |
sub _setup_list_action_bar { |
|
138 |
my ($self) = @_; |
|
139 |
for my $bar ($::request->layout->get('actionbar')) { |
|
140 |
$bar->add( |
|
141 |
action => [ |
|
142 |
t8('Action'), |
|
143 |
submit => [ '#form', { action => "DispositionManager/add_to_purchase_basket" } ], |
|
144 |
tooltip => t8('Add to purchase basket'), |
|
145 |
], |
|
146 |
); |
|
147 |
} |
|
148 |
} |
|
149 |
|
|
150 |
sub _setup_show_basket_action_bar { |
|
151 |
my ($self) = @_; |
|
152 |
for my $bar ($::request->layout->get('actionbar')) { |
|
153 |
$bar->add( |
|
154 |
action => [ |
|
155 |
t8('Reload'), |
|
156 |
submit => [ '#purchasebasket', { action => "DispositionManager/show_basket" } ], |
|
157 |
], |
|
158 |
action => [ |
|
159 |
t8('Action'), |
|
160 |
call => [ 'kivi.DispositionManager.create_order' ], |
|
161 |
tooltip => t8('Create purchase order'), |
|
162 |
], |
|
163 |
); |
|
164 |
} |
|
165 |
} |
|
166 |
1; |
|
167 |
|
|
168 |
__END__ |
|
169 |
|
|
170 |
=encoding utf-8 |
|
171 |
|
|
172 |
=head1 NAME |
|
173 |
|
|
174 |
SL::Controller::DispositionManager Controller to manage purchase orders for parts |
|
175 |
|
|
176 |
=head1 DESCRIPTION |
|
177 |
|
|
178 |
This controller shows a list of parts using the filter minimum stock (rop). |
|
179 |
From this list it is possible to put parts in a purchase basket to order. |
|
180 |
It's also possible to put parts from the parts edit form in the purchase basket. |
|
181 |
|
|
182 |
From the purchase basket you can create a purchase order by using the filter vendor. |
|
183 |
The quantity to order will be prefilled by the value min_qty_to_order from parts or |
|
184 |
makemodel(vendor_parts) or default to qty 1. |
|
185 |
|
|
186 |
Tables: |
|
187 |
|
|
188 |
=over 2 |
|
189 |
|
|
190 |
=item purchase_basket |
|
191 |
|
|
192 |
=back |
|
193 |
|
|
194 |
Dependencies: |
|
195 |
|
|
196 |
=over 2 |
|
197 |
|
|
198 |
=item parts |
|
199 |
|
|
200 |
=item makemodels |
|
201 |
|
|
202 |
|
|
203 |
=back |
|
204 |
|
|
205 |
=head1 URL ACTIONS |
|
206 |
|
|
207 |
=over 4 |
|
208 |
|
|
209 |
=item C<action_list_parts> |
|
210 |
|
|
211 |
List the parts by the filter min stock (rop) and not in an open purchase order. |
|
212 |
|
|
213 |
=item C<action_add_to_purchase_basket> |
|
214 |
|
|
215 |
Adds one or more parts to the purchase basket. |
|
216 |
|
|
217 |
=item C<action_show_basket> |
|
218 |
|
|
219 |
Shows a list with parts which are in the basket. |
|
220 |
This list can be filtered by vendor. Then you can create a purchase order. |
|
221 |
|
|
222 |
=item C<action_transfer_to_purchase_order> |
|
223 |
|
|
224 |
Transfers the marked and by vendor filtered parts to a purchase order. |
|
225 |
Deletes the entry in the purchase basket. |
|
226 |
|
|
227 |
=back |
|
228 |
|
|
229 |
=head1 BUGS |
|
230 |
|
|
231 |
None yet. :) |
|
232 |
|
|
233 |
=head1 AUTHOR |
|
234 |
|
|
235 |
W. Hahn E<lt>wh@futureworldsearch.netE<gt> |
|
236 |
|
|
237 |
=cut |
SL/Controller/DispositionsManager.pm | ||
---|---|---|
1 |
package SL::Controller::DispositionsManager; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use parent qw(SL::Controller::Base); |
|
6 |
|
|
7 |
use SL::DB::Part; |
|
8 |
use SL::DB::PurchaseBasket; |
|
9 |
use SL::Locale::String qw(t8); |
|
10 |
|
|
11 |
sub action_list_parts { |
|
12 |
my ( $self ) = @_; |
|
13 |
|
|
14 |
my $parts = $self->_get_parts; |
|
15 |
|
|
16 |
$self->_setup_list_action_bar; |
|
17 |
$self->render('dispositionsmanager/list_parts', title => t8('Parts short onhand'), PARTS => $parts); |
|
18 |
} |
|
19 |
|
|
20 |
sub action_add_to_purchase_basket{ |
|
21 |
my ( $self ) = @_; |
|
22 |
|
|
23 |
my $parts_to_add = delete($::form->{id}) || []; |
|
24 |
foreach my $id (@{ $parts_to_add }) { |
|
25 |
my $part = SL::DB::Manager::Part->get_first( query => [ id => $id ] ); |
|
26 |
my $basket_part = SL::DB::PurchaseBasket->new( |
|
27 |
parts_id => $part->id, |
|
28 |
qty => $part->min_order_qty, |
|
29 |
description => $part->description, |
|
30 |
); |
|
31 |
$basket_part->save; |
|
32 |
} |
|
33 |
$self->action_show_basket; |
|
34 |
|
|
35 |
} |
|
36 |
|
|
37 |
sub action_show_basket { |
|
38 |
my ( $self ) = @_; |
|
39 |
|
|
40 |
$::request->{layout}->add_javascripts('kivi.DispositionsManager.js'); |
|
41 |
my $basket = SL::DB::Manager::PurchaseBasket->get_all( query => [ cleared => 'F' ], with_objects => [ 'parts', 'parts.makemodels' ]); |
|
42 |
$self->_setup_show_basket_action_bar; |
|
43 |
$self->render('dispositionsmanager/show_purchase_basket', PARTS => $basket, title => "Purchase basket" ); |
|
44 |
} |
|
45 |
|
|
46 |
sub action_transfer_to_purchase_order { |
|
47 |
my ( $self ) = @_; |
|
48 |
require SL::DB::Order; |
|
49 |
require SL::DB::OrderItem; |
|
50 |
require SL::DB::Part; |
|
51 |
require SL::DB::Vendor; |
|
52 |
my @error_report; |
|
53 |
|
|
54 |
my $v_id = $::form->{vendor_id}->[0] ; |
|
55 |
my $vendor = SL::DB::Manager::Vendor->find_by(id => $v_id); |
|
56 |
die "Can't find vendor" unless $vendor; |
|
57 |
my $employee = SL::DB::Manager::Employee->current; |
|
58 |
die "Can't find employee" unless $employee; |
|
59 |
my $basket_items= SL::DB::Manager::PurchaseBasket->get_all( query => [ id => \@{ $::form->{id} } ] ); |
|
60 |
|
|
61 |
my @items = map{ |
|
62 |
my $part = SL::DB::Manager::Part->get_first( query => [ id => $_->parts_id,]); |
|
63 |
my $mm = SL::DB::Manager::MakeModel->get_first( query => [ make => $vendor->id, parts_id => $_->parts_id] ); |
|
64 |
|
|
65 |
unless($part){ |
|
66 |
push @error_report, t8('Part with id: #1 not found', $_->parts_id); |
|
67 |
}else{ |
|
68 |
my $current_order_item = SL::DB::OrderItem->new( |
|
69 |
parts_id => $_->parts_id, |
|
70 |
description => $part->description, |
|
71 |
qty => $_->qty, |
|
72 |
sellprice => $mm->lastcost, |
|
73 |
unit => $part->unit, |
|
74 |
position => $_->id, |
|
75 |
active_price_source => "makemodel/" . $mm->id, |
|
76 |
); |
|
77 |
} |
|
78 |
}@{$basket_items}; |
|
79 |
|
|
80 |
my $order = SL::DB::Order->new( |
|
81 |
vendor_id => $vendor->id, |
|
82 |
orderitems => [ @items ], |
|
83 |
employee_id => $employee->id, |
|
84 |
intnotes => $vendor->notes, |
|
85 |
salesman_id => $employee->id, |
|
86 |
payment_id => $vendor->payment_id, |
|
87 |
taxzone_id => $vendor->taxzone_id, |
|
88 |
currency_id => $vendor->currency_id, |
|
89 |
transdate => DateTime->today_local |
|
90 |
); |
|
91 |
|
|
92 |
$order->db->with_transaction( sub { |
|
93 |
$order->calculate_prices_and_taxes; |
|
94 |
$order->save; |
|
95 |
|
|
96 |
my $snumbers = "ordernumber_" . $order->ordnumber; |
|
97 |
SL::DB::History->new( |
|
98 |
trans_id => $order->id, |
|
99 |
snumbers => $snumbers, |
|
100 |
employee_id => SL::DB::Manager::Employee->current->id, |
|
101 |
addition => 'SAVED', |
|
102 |
what_done => 'PurchaseBaket->Order', |
|
103 |
)->save(); |
|
104 |
foreach my $item(@{ $order->orderitems }){ |
|
105 |
$item->parse_custom_variable_values->save; |
|
106 |
$item->{custom_variables} = \@{ $item->cvars_by_config }; |
|
107 |
$item->save; |
|
108 |
} |
|
109 |
SL::DB::Manager::PurchaseBasket->delete_all( where => [ id => \@{ $::form->{id} }]); |
|
110 |
}) || die $order->db->error; |
|
111 |
$self->redirect_to(controller => "oe.pl", action => 'edit', type => 'purchase_order', vc => 'vendor', id => $order->id); |
|
112 |
|
|
113 |
} |
|
114 |
|
|
115 |
sub _get_parts { |
|
116 |
my ($self) = @_; |
|
117 |
|
|
118 |
my $query = <<SQL; |
|
119 |
SELECT * |
|
120 |
FROM parts |
|
121 |
WHERE onhand <= rop |
|
122 |
AND rop != 0 |
|
123 |
AND id NOT IN( SELECT parts_id FROM purchase_basket ) AND NOT obsolete |
|
124 |
SQL |
|
125 |
|
|
126 |
return SL::DB::Manager::Part->get_objects_from_sql( sql => $query ); |
|
127 |
}; |
|
128 |
|
|
129 |
|
|
130 |
sub _setup_list_action_bar { |
|
131 |
my ($self) = @_; |
|
132 |
for my $bar ($::request->layout->get('actionbar')) { |
|
133 |
$bar->add( |
|
134 |
action => [ |
|
135 |
t8('Action'), |
|
136 |
submit => [ '#form', { action => "DispositionsManager/add_to_purchase_basket" } ], |
|
137 |
tooltip => t8('Add to purchase basket'), |
|
138 |
], |
|
139 |
); |
|
140 |
} |
|
141 |
} |
|
142 |
|
|
143 |
sub _setup_show_basket_action_bar { |
|
144 |
my ($self) = @_; |
|
145 |
for my $bar ($::request->layout->get('actionbar')) { |
|
146 |
$bar->add( |
|
147 |
action => [ |
|
148 |
t8('Reload'), |
|
149 |
submit => [ '#purchasebasket', { action => "DispositionsManager/show_basket" } ], |
|
150 |
], |
|
151 |
action => [ |
|
152 |
t8('Action'), |
|
153 |
call => [ 'kivi.DispositionsManager.create_order' ], |
|
154 |
tooltip => t8('Create purchase order'), |
|
155 |
], |
|
156 |
); |
|
157 |
} |
|
158 |
} |
|
159 |
1; |
|
160 |
|
|
161 |
__END__ |
|
162 |
|
|
163 |
=encoding utf-8 |
|
164 |
|
|
165 |
=head1 NAME |
|
166 |
|
|
167 |
SL::Controller::DispositionsManager Controller to manage purchase orders for parts |
|
168 |
|
|
169 |
=head1 DESCRIPTION |
|
170 |
|
|
171 |
This controller shows a list of parts using the filter minimum stock (rop). |
|
172 |
From this list it is possible to put parts in a purchase basket to order. |
|
173 |
It's also possible to put parts from the parts edit form in the purchase basket. |
|
174 |
|
|
175 |
From the purchase basket you can create a purchase order by using the filter vendor. |
|
176 |
The quantity to order will be prefilled by the value min_qty_to_order from parts or |
|
177 |
makemodel(vendor_parts) or default to qty 1. |
|
178 |
|
|
179 |
Tables: |
|
180 |
|
|
181 |
=over 2 |
|
182 |
|
|
183 |
=item purchase_basket |
|
184 |
|
|
185 |
=back |
|
186 |
|
|
187 |
Dependencies: |
|
188 |
|
|
189 |
=over 2 |
|
190 |
|
|
191 |
=item parts |
|
192 |
|
|
193 |
=item makemodels |
|
194 |
|
|
195 |
|
|
196 |
=back |
|
197 |
|
|
198 |
=head1 URL ACTIONS |
|
199 |
|
|
200 |
=over 4 |
|
201 |
|
|
202 |
=item C<action_list_parts> |
|
203 |
|
|
204 |
List the parts by the filter min stock (rop) and not in an open purchase order. |
|
205 |
|
|
206 |
=item C<action_add_to_purchase_basket> |
|
207 |
|
|
208 |
Adds one or more parts to the purchase basket. |
|
209 |
|
|
210 |
=item C<action_show_basket> |
|
211 |
|
|
212 |
Shows a list with parts which are in the basket. |
|
213 |
This list can be filtered by vendor. Then you can create a purchase order. |
|
214 |
|
|
215 |
=item C<action_transfer_to_purchase_order> |
|
216 |
|
|
217 |
Transfers the marked and by vendor filtered parts to a purchase order. |
|
218 |
Deletes the entry in the purchase basket. |
|
219 |
|
|
220 |
=back |
|
221 |
|
|
222 |
=head1 BUGS |
|
223 |
|
|
224 |
None yet. :) |
|
225 |
|
|
226 |
=head1 AUTHOR |
|
227 |
|
|
228 |
W. Hahn E<lt>wh@futureworldsearch.netE<gt> |
|
229 |
|
|
230 |
=cut |
SL/DB/Helper/ALL.pm | ||
---|---|---|
108 | 108 |
use SL::DB::ProjectRole; |
109 | 109 |
use SL::DB::ProjectStatus; |
110 | 110 |
use SL::DB::ProjectType; |
111 |
use SL::DB::PurchaseBasketItem; |
|
111 | 112 |
use SL::DB::PurchaseInvoice; |
112 | 113 |
use SL::DB::Reclamation; |
113 | 114 |
use SL::DB::ReclamationItem; |
SL/DB/Helper/Mappings.pm | ||
---|---|---|
188 | 188 |
project_statuses => 'project_status', |
189 | 189 |
project_types => 'project_type', |
190 | 190 |
purchase_basket => 'purchase_basket', |
191 |
purchase_basket_items => 'purchase_basket_item', |
|
191 | 192 |
reclamations => 'Reclamation', |
192 | 193 |
reclamation_items => 'ReclamationItem', |
193 | 194 |
reclamation_reasons => 'ReclamationReason', |
SL/DB/Manager/PurchaseBasket.pm | ||
---|---|---|
1 |
# This file has been auto-generated only because it didn't exist. |
|
2 |
# Feel free to modify it at will; it will not be overwritten automatically. |
|
3 |
|
|
4 |
package SL::DB::Manager::PurchaseBasket; |
|
5 |
|
|
6 |
use strict; |
|
7 |
|
|
8 |
use parent qw(SL::DB::Helper::Manager); |
|
9 |
|
|
10 |
sub object_class { 'SL::DB::PurchaseBasket' } |
|
11 |
|
|
12 |
__PACKAGE__->make_manager_methods; |
|
13 |
|
|
14 |
1; |
SL/DB/Manager/PurchaseBasketItem.pm | ||
---|---|---|
1 |
# This file has been auto-generated only because it didn't exist. |
|
2 |
# Feel free to modify it at will; it will not be overwritten automatically. |
|
3 |
|
|
4 |
package SL::DB::Manager::PurchaseBasketItem; |
|
5 |
|
|
6 |
use strict; |
|
7 |
|
|
8 |
use parent qw(SL::DB::Helper::Manager); |
|
9 |
|
|
10 |
sub object_class { 'SL::DB::PurchaseBasketItem' } |
|
11 |
|
|
12 |
__PACKAGE__->make_manager_methods; |
|
13 |
|
|
14 |
1; |
SL/DB/MetaSetup/PurchaseBasket.pm | ||
---|---|---|
1 |
# This file has been auto-generated. Do not modify it; it will be overwritten |
|
2 |
# by rose_auto_create_model.pl automatically. |
|
3 |
package SL::DB::PurchaseBasket; |
|
4 |
|
|
5 |
use strict; |
|
6 |
|
|
7 |
use parent qw(SL::DB::Object); |
|
8 |
|
|
9 |
__PACKAGE__->meta->table('purchase_basket'); |
|
10 |
|
|
11 |
__PACKAGE__->meta->columns( |
|
12 |
cleared => { type => 'boolean', default => 'false', not_null => 1 }, |
|
13 |
description => { type => 'text' }, |
|
14 |
id => { type => 'serial', not_null => 1 }, |
|
15 |
parts_id => { type => 'integer' }, |
|
16 |
qty => { type => 'numeric', precision => 15, scale => 5 }, |
|
17 |
); |
|
18 |
|
|
19 |
__PACKAGE__->meta->primary_key_columns([ 'id' ]); |
|
20 |
|
|
21 |
__PACKAGE__->meta->foreign_keys( |
|
22 |
parts => { |
|
23 |
class => 'SL::DB::Part', |
|
24 |
key_columns => { parts_id => 'id' }, |
|
25 |
}, |
|
26 |
); |
|
27 |
|
|
28 |
1; |
|
29 |
; |
SL/DB/MetaSetup/PurchaseBasketItem.pm | ||
---|---|---|
1 |
# This file has been auto-generated. Do not modify it; it will be overwritten |
|
2 |
# by rose_auto_create_model.pl automatically. |
|
3 |
package SL::DB::PurchaseBasketItem; |
|
4 |
|
|
5 |
use strict; |
|
6 |
|
|
7 |
use parent qw(SL::DB::Object); |
|
8 |
|
|
9 |
__PACKAGE__->meta->table('purchase_basket_items'); |
|
10 |
|
|
11 |
__PACKAGE__->meta->columns( |
|
12 |
cleared => { type => 'boolean', default => 'false', not_null => 1 }, |
|
13 |
description => { type => 'text' }, |
|
14 |
id => { type => 'serial', not_null => 1 }, |
|
15 |
parts_id => { type => 'integer' }, |
|
16 |
qty => { type => 'numeric', precision => 15, scale => 5 }, |
|
17 |
); |
|
18 |
|
|
19 |
__PACKAGE__->meta->primary_key_columns([ 'id' ]); |
|
20 |
|
|
21 |
__PACKAGE__->meta->foreign_keys( |
|
22 |
part => { |
|
23 |
class => 'SL::DB::Part', |
|
24 |
key_columns => { parts_id => 'id' }, |
|
25 |
}, |
|
26 |
); |
|
27 |
|
|
28 |
1; |
|
29 |
; |
SL/DB/PurchaseBasket.pm | ||
---|---|---|
1 |
# This file has been auto-generated only because it didn't exist. |
|
2 |
# Feel free to modify it at will; it will not be overwritten automatically. |
|
3 |
|
|
4 |
package SL::DB::PurchaseBasket; |
|
5 |
|
|
6 |
use strict; |
|
7 |
|
|
8 |
use SL::DB::MetaSetup::PurchaseBasket; |
|
9 |
use SL::DB::Manager::PurchaseBasket; |
|
10 |
|
|
11 |
__PACKAGE__->meta->initialize; |
|
12 |
|
|
13 |
|
|
14 |
1; |
SL/DB/PurchaseBasketItem.pm | ||
---|---|---|
1 |
# This file has been auto-generated only because it didn't exist. |
|
2 |
# Feel free to modify it at will; it will not be overwritten automatically. |
|
3 |
|
|
4 |
package SL::DB::PurchaseBasketItem; |
|
5 |
|
|
6 |
use strict; |
|
7 |
|
|
8 |
use SL::DB::MetaSetup::PurchaseBasketItem; |
|
9 |
use SL::DB::Manager::PurchaseBasketItem; |
|
10 |
|
|
11 |
__PACKAGE__->meta->initialize; |
|
12 |
|
|
13 |
1; |
js/kivi.DispositionManager.js | ||
---|---|---|
1 |
namespace('kivi.DispositionManager', function(ns) { |
|
2 |
ns.sort_vendors = function() { |
|
3 |
$("table tr").each(function(index) { |
|
4 |
if ( index !== 0 ) { |
|
5 |
$row = $(this); |
|
6 |
//alert( $row.find("select[name='vendor_id[]']").val() + '!=' + $('#cv_id').val()); |
|
7 |
if( $row.find("select[name='vendor_id[]']").val() != $('#cv_id').val()) { |
|
8 |
$row.remove(); |
|
9 |
} |
|
10 |
} |
|
11 |
}); |
|
12 |
} |
|
13 |
ns.create_order = function() { |
|
14 |
var data = $('#purchasebasket').serializeArray(); |
|
15 |
data.push({ name: 'action', value: 'DispositionManager/transfer_to_purchase_order' }); |
|
16 |
|
|
17 |
$.post("controller.pl", data, kivi.eval_json_result); |
|
18 |
} |
|
19 |
}); |
js/kivi.DispositionsManager.js | ||
---|---|---|
1 |
namespace('kivi.DispositionsManager', function(ns) { |
|
2 |
ns.sort_vendors = function() { |
|
3 |
$("table tr").each(function(index) { |
|
4 |
if ( index !== 0 ) { |
|
5 |
$row = $(this); |
|
6 |
//alert( $row.find("select[name='vendor_id[]']").val() + '!=' + $('#cv_id').val()); |
|
7 |
if( $row.find("select[name='vendor_id[]']").val() != $('#cv_id').val()) { |
|
8 |
$row.remove(); |
|
9 |
} |
|
10 |
} |
|
11 |
}); |
|
12 |
} |
|
13 |
ns.create_order = function() { |
|
14 |
var data = $('#purchasebasket').serializeArray(); |
|
15 |
data.push({ name: 'action', value: 'DispositionsManager/transfer_to_purchase_order' }); |
|
16 |
|
|
17 |
$.post("controller.pl", data, kivi.eval_json_result); |
|
18 |
} |
|
19 |
}); |
locale/de/all | ||
---|---|---|
1216 | 1216 |
'Display in basic data tab' => 'Im Reiter Basisdaten anzeigen', |
1217 | 1217 |
'Display options' => 'Anzeigeoptionen', |
1218 | 1218 |
'Displayable Name Preferences' => 'Einstellungen für Anzeigenamen', |
1219 |
'Disposition manager' => 'Dispositionsmanager', |
|
1219 | 1220 |
'Do not change the tax rate of taxkey 0.' => 'Ändern Sie nicht den Steuersatz vom Steuerschlüssel 0.', |
1220 | 1221 |
'Do not check for duplicates' => 'Nicht nach Dubletten suchen', |
1221 | 1222 |
'Do not create Factur-X/ZUGFeRD invoices' => 'Keine Factur-X-/ZUGFeRD-Rechnungen erzeugen', |
menus/user/10-disposition-manager.yaml | ||
---|---|---|
1 |
--- |
|
2 |
- parent: ap |
|
3 |
id: ap_disp_manager |
|
4 |
name: Disposition manager |
|
5 |
icon: rfq_add |
|
6 |
order: 150 |
|
7 |
access: request_quotation_edit |
|
8 |
- parent: ap_disp_manager |
|
9 |
id: ap_disp_manager_onhand |
|
10 |
name: List short onhand |
|
11 |
order: 160 |
|
12 |
params: |
|
13 |
action: DispositionManager/list_parts |
|
14 |
- parent: ap_disp_manager |
|
15 |
id: ap_disp_manager_basket |
|
16 |
name: Show purchase basket |
|
17 |
order: 170 |
|
18 |
params: |
|
19 |
action: DispositionManager/show_basket |
menus/user/10-dispositionsmanager.yaml | ||
---|---|---|
1 |
--- |
|
2 |
- parent: ap |
|
3 |
id: ap_disp_manager |
|
4 |
name: Dispositionsmanager |
|
5 |
icon: rfq_add |
|
6 |
order: 150 |
|
7 |
access: request_quotation_edit |
|
8 |
- parent: ap_disp_manager |
|
9 |
id: ap_disp_manager_onhand |
|
10 |
name: List short onhand |
|
11 |
order: 160 |
|
12 |
params: |
|
13 |
action: DispositionsManager/list_parts |
|
14 |
- parent: ap_disp_manager |
|
15 |
id: ap_disp_manager_basket |
|
16 |
name: Show purchase basket |
|
17 |
order: 170 |
|
18 |
params: |
|
19 |
action: DispositionsManager/show_basket |
scripts/rose_auto_create_model.pl | ||
---|---|---|
83 | 83 |
|
84 | 84 |
assembly => { parts_id => 'part', id => 'assembly_part' }, |
85 | 85 |
assortment_items => { parts_id => 'part' }, |
86 |
purchase_basket_items => { parts_id => 'part' }, |
|
86 | 87 |
|
87 | 88 |
dunning => { trans_id => 'invoice', fee_interest_ar_id => 'fee_interest_invoice' }, |
88 | 89 |
}, |
sql/Pg-upgrade2/purchase_basket.sql | ||
---|---|---|
1 | 1 |
-- @tag: purchase_basket |
2 |
-- @description: Tabelle für den Dispostionsmanager |
|
2 |
-- @description: Tabelle für den Dispositionsmanager
|
|
3 | 3 |
-- @depends: release_3_5_1 |
4 | 4 |
-- @ignore: 0 |
5 | 5 |
|
6 |
CREATE TABLE purchase_basket ( |
|
6 |
CREATE TABLE purchase_basket_items (
|
|
7 | 7 |
id SERIAL PRIMARY KEY, |
8 | 8 |
parts_id INTEGER REFERENCES parts(id), |
9 | 9 |
qty NUMERIC(15,5), |
t/controllers/disposition_manager/disposition_manager.t | ||
---|---|---|
1 | 1 |
use strict; |
2 |
use Test::More; |
|
2 |
use Test::More tests => 9;
|
|
3 | 3 |
|
4 | 4 |
use lib 't'; |
5 | 5 |
use Support::TestSetup; |
... | ... | |
7 | 7 |
use SL::DB::Part; |
8 | 8 |
use SL::DB::Inventory; |
9 | 9 |
use SL::DB::MakeModel; |
10 |
use SL::DB::PurchaseBasket; |
|
11 |
use SL::Controller::DispositionsManager;
|
|
10 |
use SL::DB::PurchaseBasketItem;
|
|
11 |
use SL::Controller::DispositionManager; |
|
12 | 12 |
use DateTime; |
13 | 13 |
use Data::Dumper; |
14 | 14 |
use SL::Dev::Part qw(new_part); |
... | ... | |
25 | 25 |
my $vendor = new_vendor()->save; |
26 | 26 |
|
27 | 27 |
my $part1 = new_part( |
28 |
partnumber => 'Testpart 1 rop no stock', |
|
28 |
partnumber => 'TP 1', |
|
29 |
description => 'Testpart 1 rop no stock', |
|
30 |
sellprice => 5, |
|
31 |
lastcost => 3, |
|
29 | 32 |
rop => 20, |
30 | 33 |
warehouse_id => $wh->id, |
31 | 34 |
bin_id => $bin->id, |
... | ... | |
33 | 36 |
)->save; |
34 | 37 |
|
35 | 38 |
my $part2 = new_part( |
36 |
partnumber => 'Testpart 2 rop with stock', |
|
39 |
partnumber => 'TP 2', |
|
40 |
description => 'Testpart 2 norop', |
|
37 | 41 |
rop => 60, |
38 | 42 |
)->save; |
39 |
set_stock(part => $part2, bin_id => $bin->id, qty => 10); |
|
43 |
set_stock(part => $part2, bin_id => $bin->id, qty => 80); |
|
44 |
|
|
45 |
for my $i (1 .. 10) { |
|
46 |
my $part = new_part( |
|
47 |
partnumber => "TPO $i", |
|
48 |
description => "Testpart onhand $i", |
|
49 |
rop => 50, |
|
50 |
sellprice => 5, |
|
51 |
lastcost => 3, |
|
52 |
warehouse_id => $wh->id, |
|
53 |
bin_id => $bin->id, |
|
54 |
makemodels => [ _create_makemodel_for_vendor(vendor => $vendor) ], |
|
55 |
)->save; |
|
56 |
set_stock(part => $part, bin_id => $bin->id, qty => ($i * 10)); |
|
57 |
} |
|
40 | 58 |
|
41 |
my $part3 = new_part( |
|
42 |
partnumber => 'Testpart 3 norop', |
|
43 |
rop => 60, |
|
44 |
)->save; |
|
45 |
set_stock(part => $part3, bin_id => $bin->id, qty => 80); |
|
59 |
my $controller = SL::Controller::DispositionManager->new(); |
|
60 |
my $reorder_parts = $controller->_get_parts; |
|
61 |
is(scalar @{$reorder_parts}, 6, "found 6 parts where onhand <= rop"); |
|
62 |
|
|
63 |
# die; # die here if you want to test making basket manually |
|
64 |
|
|
65 |
note('creating purchase basket items'); |
|
66 |
$::form = Support::TestSetup->create_new_form; |
|
67 |
$::form->{ids} = [ map { $_->id } @{$reorder_parts} ]; |
|
68 |
|
|
69 |
# call action_add_to_purchase_basket while redirecting rendered HTML output |
|
70 |
my $output; |
|
71 |
open(my $outputFH, '>', \$output) or die; |
|
72 |
my $oldFH = select $outputFH; |
|
73 |
$controller->action_add_to_purchase_basket; |
|
74 |
select $oldFH; |
|
75 |
close $outputFH; |
|
76 |
|
|
77 |
is(SL::DB::Manager::PurchaseBasketItem->get_all_count(), 6, "6 items in purchase basket ok"); |
|
78 |
|
|
79 |
# die; # die here if you want to test creating purchase orders manually |
|
80 |
|
|
81 |
note('making purchase order from purchase basket items'); |
|
82 |
my $purchase_basket_items = SL::DB::Manager::PurchaseBasketItem->get_all; |
|
83 |
$::form = Support::TestSetup->create_new_form; |
|
84 |
$::form->{ids} = [ map { $_->id } @{ $purchase_basket_items } ]; |
|
85 |
$::form->{vendor_ids} = [ map { $vendor->id } @{ $purchase_basket_items } ]; |
|
86 |
|
|
87 |
$controller->action_transfer_to_purchase_order; |
|
88 |
|
|
89 |
is(SL::DB::Manager::Order->get_all_count( where => [ SL::DB::Manager::Order->type_filter('purchase_order') ] ), 1, "1 purchase order created ok"); |
|
90 |
is(SL::DB::Manager::PurchaseBasketItem->get_all_count(), 0, "purchase basket empty after purchase order was created"); |
|
46 | 91 |
|
47 |
my $controller = SL::Controller::DispositionsManager->new(); |
|
48 |
my $parts = $controller->_get_parts; |
|
92 |
my $purchase_order = SL::DB::Manager::Order->get_first(); |
|
49 | 93 |
|
50 |
is(scalar @{$parts}, 2, "found 2 parts that are below rop"); |
|
94 |
is( scalar @{$purchase_order->items}, 6, "Purchase order has 6 item ok"); |
|
95 |
my $first_item = $purchase_order->items_sorted->[0]; |
|
96 |
is( $first_item->parts_id, $part1->id, "Purchase order: first item is part1"); |
|
97 |
is( $first_item->qty, 1, "Purchase order: first item has qty 1"); |
|
98 |
cmp_ok( $purchase_order->netamount, '==', 12, "Purchase order: netamount ok"); |
|
99 |
is( $first_item->active_price_source, 'makemodel/' . $first_item->part->makemodels->[0]->id, "Purchase order: first item has correct active_price_source"); |
|
51 | 100 |
|
52 | 101 |
done_testing(); |
53 | 102 |
# clear_up(); |
... | ... | |
56 | 105 |
my %params = @_; |
57 | 106 |
SL::DB::Manager::Inventory->delete_all(all => 1); |
58 | 107 |
SL::DB::Manager::Order->delete_all(all => 1); |
59 |
SL::DB::Manager::PurchaseBasket->delete_all(all => 1); |
|
108 |
SL::DB::Manager::PurchaseBasketItem->delete_all(all => 1);
|
|
60 | 109 |
SL::DB::Manager::MakeModel->delete_all(all => 1); |
61 | 110 |
SL::DB::Manager::Part->delete_all(all => 1); |
62 | 111 |
SL::DB::Manager::Vendor->delete_all(all => 1); |
... | ... | |
73 | 122 |
my $mm = SL::DB::MakeModel->new(make => $vendor->id, |
74 | 123 |
model => '', |
75 | 124 |
min_order_qty => '1', |
76 |
lastcost => 0,
|
|
125 |
lastcost => 2,
|
|
77 | 126 |
sortorder => 1, |
78 | 127 |
); |
79 | 128 |
$mm->assign_attributes( %params ); |
templates/webpages/disposition_manager/list_parts.html | ||
---|---|---|
1 |
[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%] |
|
2 |
[% USE Dumper %] |
|
3 |
[%- INCLUDE 'common/flash.html' %] |
|
4 |
<h1>[% title %]</h1> |
|
5 |
<hr> |
|
6 |
<h2>[% 'Short onhand' | $T8 %]</h2> |
|
7 |
<form id="form"> |
|
8 |
<table> |
|
9 |
<thead> |
|
10 |
<tr class="listheading"> |
|
11 |
<th>[% L.checkbox_tag('check_all') %][% 'Purchase basket' | $T8 %] </th> |
|
12 |
<th>[% 'Partnumber' | $T8 %] </th> |
|
13 |
<th>[% 'Description' | $T8 %] </th> |
|
14 |
<th>[% 'Onhand' | $T8 %] </th> |
|
15 |
<th>[% 'Rop' | $T8 %] </th> |
|
16 |
<th>[% 'Minimum order quantity' | $T8 %] </th> |
|
17 |
</tr> |
|
18 |
</thead> |
|
19 |
[% FOREACH part = PARTS %] |
|
20 |
[% IF !part.get_ordered_qty(part.id) %] |
|
21 |
<tr class="listrow"> |
|
22 |
<td>[% IF part.makemodels.size %][% L.checkbox_tag('ids[+]', checked = '1', value=part.id) %][% ELSE %][% 'No Vendor' | $T8 %][% END %]</td> |
|
23 |
<td>[% HTML.escape(part.partnumber) %] </td> |
|
24 |
<td>[% HTML.escape(part.description) %]</td> |
|
25 |
<td class="numeric">[% part.onhand_as_number %]</td> |
|
26 |
<td class="numeric">[% part.rop_as_number %] </td> |
|
27 |
<td class="numeric">[% part.min_order_qty_as_number %] </td> |
|
28 |
</tr> |
|
29 |
[% END %] |
|
30 |
[% END %] |
|
31 |
</table> |
|
32 |
</form> |
|
33 |
<hr> |
|
34 |
<h2>[% 'Short onhand Ordered' | $T8 %]</h2> |
|
35 |
<table> |
|
36 |
<thead> |
|
37 |
<tr class="listheading"> |
|
38 |
<th>[% 'Partnumber' | $T8 %] </th> |
|
39 |
<th>[% 'Description' | $T8 %] </th> |
|
40 |
<th>[% 'onhand' | $T8 %] </th> |
|
41 |
<th>[% 'rop' | $T8 %] </th> |
|
42 |
<th>[% 'Ordered purchase' | $T8 %] </th> |
|
43 |
</tr> |
|
44 |
</thead> |
|
45 |
[% FOREACH part = PARTS %] |
|
46 |
[% IF part.get_ordered_qty(part.id) %] |
|
47 |
<tr class="listrow"> |
|
48 |
<td>[% HTML.escape(part.partnumber) %] </td> |
|
49 |
<td>[% HTML.escape(part.description) %] </td> |
|
50 |
<td class="numeric">[% part.onhand_as_number %] </td> |
|
51 |
<td class="numeric">[% part.rop_as_number %] </td> |
|
52 |
<td class="numeric">[% part.get_ordered_qty(part.id) %] </td> |
|
53 |
</tr> |
|
54 |
[% END %] |
|
55 |
[% END %] |
|
56 |
</table> |
|
57 |
<script type="text/javascript"> |
|
58 |
<!-- |
|
59 |
|
|
60 |
kivi.DispositionManager.sort_vendors(); |
|
61 |
$(function() { |
|
62 |
alert('hallo9'); |
|
63 |
$('#check_all').checkall('INPUT[name^="id"]'); |
|
64 |
kivi.DispositionManager.sort_vendors(); |
|
65 |
}); |
|
66 |
--> |
|
67 |
</script> |
templates/webpages/disposition_manager/show_purchase_basket.html | ||
---|---|---|
1 |
[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%][% USE P %] |
|
2 |
[% USE Dumper %] |
|
3 |
[%- INCLUDE 'common/flash.html' %] |
|
4 |
<h1>[% title %]</h1> |
|
5 |
[% # Dumper.dump_html(BASKET_ITEMS) %] |
|
6 |
<form id="purchasebasket" style="margin:1em;"> |
|
7 |
[% P.customer_vendor.picker('vendor_id2', '', type='vendor', fat_set_item=1) %]<br> |
|
8 |
<div>id from change: <span id='change3'></span></div> |
|
9 |
[% L.hidden_tag('cv_id', '') %] |
|
10 |
<table id="baskettable" width="100%"> |
|
11 |
<thead> |
|
12 |
<tr class="listheading"> |
|
13 |
<th>[% L.checkbox_tag('check_all') %][% 'Purchase basket' | $T8 %] </th> |
|
14 |
<th>[% 'Partnumber' | $T8 %] </th> |
|
15 |
<th>[% 'Description' | $T8 %] </th> |
|
16 |
<th>[% 'Onhand' | $T8 %] </th> |
|
17 |
<th>[% 'Rop' | $T8 %] </th> |
|
18 |
<th>[% 'Order quantity' | $T8 %] </th> |
|
19 |
<th>[% 'Vendor' | $T8 %] </th> |
|
20 |
</tr> |
|
21 |
</thead> |
|
22 |
<tbody> |
|
23 |
[% FOREACH basket_item = BASKET_ITEMS %] |
|
24 |
[% SET select_size = basket_item.part.vendor_dropdown.size %] |
|
25 |
[% IF !basket_item.part.get_ordered_qty(part.id) %] |
|
26 |
<tr class="listrow"> |
|
27 |
<td>[% L.checkbox_tag('ids[+]', checked = '1', value=basket_item.id) %]</td> |
|
28 |
<td>[% HTML.escape(basket_item.part.partnumber) %] </td> |
|
29 |
<td>[% HTML.escape(basket_item.part.description) %]</td> |
|
30 |
<td class="numeric">[% basket_item.part.onhand_as_number %] </td> |
|
31 |
<td class="numeric">[% basket_item.part.rop_as_number %] </td> |
|
32 |
<td class="numeric">[% basket_item.qty_as_number %] </td> |
|
33 |
<td>[% L.select_tag('vendor_ids[]', basket_item.part.vendor_dropdown, value_key = 'value', title_key = 'title', default = basket_item.part.makemodels.item(0).make, size = select_size, style='width: 350px;' ) %]</td> |
|
34 |
</tr> |
|
35 |
[% END %] |
|
36 |
[% END %] |
|
37 |
</tbody> |
|
38 |
</table> |
|
39 |
</form> |
|
40 |
<hr> |
|
41 |
<script type="text/javascript"> |
|
42 |
<!-- |
|
43 |
|
|
44 |
$('#vendor_id2').change(function() { $('#change3').html($('#vendor_id2').val()) }) |
|
45 |
$('#vendor_id2').on('set_item:CustomerVendorPicker', function(e,o) { |
|
46 |
$('#cv_id').val(o.id) |
|
47 |
kivi.DispositionManager.sort_vendors(); |
|
48 |
}) |
|
49 |
$(function() { |
|
50 |
$('#check_all').checkall('INPUT[name^="id"]'); |
|
51 |
}); |
|
52 |
--> |
|
53 |
</script> |
templates/webpages/dispositionsmanager/list_parts.html | ||
---|---|---|
1 |
[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%] |
|
2 |
[% USE Dumper %] |
|
3 |
[%- INCLUDE 'common/flash.html' %] |
|
4 |
<h1>[% title %]</h1> |
|
5 |
<hr> |
|
6 |
<h2>[% 'Short onhand' | $T8 %]</h2> |
|
7 |
<form id="form"> |
|
8 |
<table> |
|
9 |
<thead> |
|
10 |
<tr class="listheading"> |
|
11 |
<th>[% L.checkbox_tag('check_all') %][% 'Purchasebasket' | $T8 %] </th> |
|
12 |
<th>[% 'Partnumber' | $T8 %] </th> |
|
13 |
<th>[% 'Description' | $T8 %] </th> |
|
14 |
<th>[% 'Onhand' | $T8 %] </th> |
|
15 |
<th>[% 'Rop' | $T8 %] </th> |
|
16 |
<th>[% 'Minimum order quantity' | $T8 %] </th> |
|
17 |
</tr> |
|
18 |
</thead> |
|
19 |
[% FOREACH part = PARTS %] |
|
20 |
[% IF !part.get_ordered_qty(part.id) %] |
|
21 |
<tr class="listrow"> |
|
22 |
<td>[% IF part.makemodels.size %][% L.checkbox_tag('id[]', checked = '1', value=part.id) %][% ELSE %][% 'No Vendor' | $T8 %][% END %]</td> |
|
23 |
<td>[% HTML.escape(part.partnumber) %] </td> |
|
24 |
<td>[% HTML.escape(part.description) %]</td> |
|
25 |
<td class="numeric">[% part.onhand_as_number %]</td> |
|
26 |
<td class="numeric">[% part.rop_as_number %] </td> |
|
27 |
<td class="numeric">[% part.min_order_qty_as_number %] </td> |
|
28 |
</tr> |
|
29 |
[% END %] |
|
30 |
[% END %] |
|
31 |
</table> |
|
32 |
</form> |
|
33 |
<hr> |
|
34 |
<h2>[% 'Short onhand Ordered' | $T8 %]</h2> |
|
35 |
<table> |
|
36 |
<thead> |
|
37 |
<tr class="listheading"> |
|
38 |
<th>[% 'Partnumber' | $T8 %] </th> |
|
39 |
<th>[% 'Description' | $T8 %] </th> |
|
40 |
<th>[% 'onhand' | $T8 %] </th> |
|
41 |
<th>[% 'rop' | $T8 %] </th> |
|
42 |
<th>[% 'Ordered purchase' | $T8 %] </th> |
|
43 |
</tr> |
|
44 |
</thead> |
|
45 |
[% FOREACH part = PARTS %] |
|
46 |
[% IF part.get_ordered_qty(part.id) %] |
|
47 |
<tr class="listrow"> |
|
48 |
<td>[% HTML.escape(part.partnumber) %] </td> |
|
49 |
<td>[% HTML.escape(part.description) %] </td> |
|
50 |
<td>[% part.onhand_as_number %] </td> |
|
51 |
<td>[% part.rop_as_number %] </td> |
|
52 |
<td>[% part.get_ordered_qty(part.id) %] </td> |
|
53 |
</tr> |
|
54 |
[% END %] |
|
55 |
[% END %] |
|
56 |
</table> |
|
57 |
<script type="text/javascript"> |
|
58 |
<!-- |
|
59 |
|
|
60 |
kivi.DispositionsManager.sort_vendors(); |
|
61 |
$(function() { |
|
62 |
alert('hallo9'); |
|
63 |
$('#check_all').checkall('INPUT[name^="id"]'); |
|
64 |
kivi.DispositionsManager.sort_vendors(); |
|
65 |
}); |
|
66 |
--> |
|
67 |
</script> |
templates/webpages/dispositionsmanager/show_purchase_basket.html | ||
---|---|---|
1 |
[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%][% USE P %] |
|
2 |
[% USE Dumper %] |
|
3 |
[%- INCLUDE 'common/flash.html' %] |
|
4 |
<h1>[% title %]</h1> |
|
5 |
[% # Dumper.dump_html(PARTS) %] |
|
6 |
<form id="purchasebasket" style="margin:1em;"> |
|
7 |
[% P.customer_vendor.picker('vendor_id2', '', type='vendor', fat_set_item=1) %]<br> |
|
8 |
<div>id from change: <span id='change3'></span></div> |
|
9 |
[% L.hidden_tag('cv_id', '') %] |
|
10 |
<table id="baskettable" width="100%"> |
|
11 |
<thead> |
|
12 |
<tr class="listheading"> |
|
13 |
<th>[% L.checkbox_tag('check_all') %][% 'Purchasebasket' | $T8 %] </th> |
|
14 |
<th>[% 'Partnumber' | $T8 %] </th> |
|
15 |
<th>[% 'Description' | $T8 %] </th> |
|
16 |
<th>[% 'Onhand' | $T8 %] </th> |
|
17 |
<th>[% 'Rop' | $T8 %] </th> |
|
18 |
<th>[% 'Order quantity' | $T8 %] </th> |
|
19 |
<th>[% 'Vendor' | $T8 %] </th> |
|
20 |
</tr> |
|
21 |
</thead> |
|
22 |
<tbody> |
|
23 |
[% FOREACH part = PARTS %] |
|
24 |
[% SET select_size = part.parts.vendor_dropdown.size %] |
|
25 |
[% IF !part.part.get_ordered_qty(part.id) %] |
|
26 |
<tr class="listrow"> |
|
27 |
<td>[% L.checkbox_tag('id[]', checked = '1', value=part.id) %]</td> |
|
28 |
<td>[% HTML.escape(part.parts.partnumber) %] </td> |
|
29 |
<td>[% HTML.escape(part.parts.description) %]</td> |
|
30 |
<td class="numeric">[% part.parts.onhand_as_number %] </td> |
|
31 |
<td class="numeric">[% part.parts.rop_as_number %] </td> |
|
32 |
<td class="numeric">[% part.qty_as_number %] </td> |
|
33 |
<td>[% L.select_tag('vendor_id[]', part.parts.vendor_dropdown, value_key = 'value', title_key = 'title', default = part.parts.makemodels.item(0).make, size = select_size, style='width: 350px;' ) %]</td> |
|
34 |
</tr> |
|
35 |
[% END %] |
|
36 |
[% END %] |
|
37 |
</tbody> |
|
38 |
</table> |
|
39 |
</form> |
|
40 |
<hr> |
|
41 |
<script type="text/javascript"> |
|
42 |
<!-- |
|
43 |
|
|
44 |
$('#vendor_id2').change(function() { $('#change3').html($('#vendor_id2').val()) }) |
|
45 |
$('#vendor_id2').on('set_item:CustomerVendorPicker', function(e,o) { |
|
46 |
$('#cv_id').val(o.id) |
|
47 |
kivi.DispositionsManager.sort_vendors(); |
|
48 |
}) |
|
49 |
$(function() { |
|
50 |
$('#check_all').checkall('INPUT[name^="id"]'); |
|
51 |
}); |
|
52 |
--> |
|
53 |
</script> |
Auch abrufbar als: Unified diff
Disposition Manager - ein paar Änderungen 2 neu
Folgende Sachen habe ich umbenannt:
DispositionsManager
> DispositionManager>PurchaseBucketItem: rose foreign key Relationship für parts: parts -> partdispositionsmanager -> disposition_manager
purchase_bucket -> purchase_bucket_item
form arrayrefs: id -> ids, vendor_id -> vendor_ids
SL::DB::MetaSetup
Dadurch, daß sich die Dateinamen geändert haben, ist leider die
git-Änderungshistorie ausgehebelt...