Revision 90651b58
Von Moritz Bunkus vor mehr als 10 Jahren hinzugefügt
SL/Controller/RequirementSpecOrder.pm | ||
---|---|---|
5 | 5 |
|
6 | 6 |
use parent qw(SL::Controller::Base); |
7 | 7 |
|
8 |
use List::MoreUtils qw(uniq); |
|
9 |
use List::Util qw(first); |
|
10 |
|
|
8 | 11 |
use SL::ClientJS; |
9 | 12 |
use SL::DB::Customer; |
13 |
use SL::DB::Order; |
|
10 | 14 |
use SL::DB::Part; |
11 | 15 |
use SL::DB::RequirementSpec; |
12 | 16 |
use SL::DB::RequirementSpecOrder; |
13 | 17 |
use SL::Helper::Flash; |
14 | 18 |
use SL::Locale::String; |
15 | 19 |
|
20 |
use constant TAB_ID => 'ui-tabs-4'; |
|
21 |
|
|
16 | 22 |
use Rose::Object::MakeMethods::Generic |
17 | 23 |
( |
18 |
'scalar --get_set_init' => [ qw(requirement_spec js all_customers all_parts) ], |
|
24 |
scalar => [ qw(parts) ], |
|
25 |
'scalar --get_set_init' => [ qw(requirement_spec js h_unit_name all_customers all_parts) ], |
|
19 | 26 |
); |
20 | 27 |
|
21 | 28 |
__PACKAGE__->run_before('setup'); |
... | ... | |
24 | 31 |
# actions |
25 | 32 |
# |
26 | 33 |
|
27 |
|
|
28 | 34 |
sub action_list { |
29 | 35 |
my ($self) = @_; |
30 | 36 |
|
... | ... | |
35 | 41 |
my ($self) = @_; |
36 | 42 |
|
37 | 43 |
my $html = $self->render('requirement_spec_order/new', { output => 0 }, make_part_title => sub { $_[0]->partnumber . ' ' . $_[0]->description }); |
38 |
$self->js->html('#ui-tabs-4', $html) |
|
44 |
$self->js->html('#' . TAB_ID(), $html) |
|
45 |
->render($self); |
|
46 |
} |
|
47 |
|
|
48 |
sub action_create { |
|
49 |
my ($self) = @_; |
|
50 |
|
|
51 |
# 1. Update sections with selected part IDs. |
|
52 |
my $section_attrs = $::form->{sections} || []; |
|
53 |
my $sections = SL::DB::Manager::RequirementSpecItem->get_all(where => [ id => [ map { $_->{id} } @{ $section_attrs } ] ]); |
|
54 |
my %sections_by_id = map { ($_->{id} => $_) } @{ $sections }; |
|
55 |
|
|
56 |
$sections_by_id{ $_->{id} }->update_attributes(order_part_id => $_->{order_part_id}) for @{ $section_attrs }; |
|
57 |
|
|
58 |
# 2. Create actual quotation/order. |
|
59 |
my $order = $self->create_order(sections => $sections); |
|
60 |
$order->save; |
|
61 |
|
|
62 |
$self->requirement_spec->orders( |
|
63 |
@{ $self->requirement_spec->orders }, |
|
64 |
SL::DB::RequirementSpecOrder->new(order => $order, version => $self->requirement_spec->version) |
|
65 |
); |
|
66 |
$self->requirement_spec->save; |
|
67 |
$self->init_requirement_spec; |
|
68 |
|
|
69 |
# 3. Notify the user and return to list. |
|
70 |
my $html = $self->render('requirement_spec_order/list', { output => 0 }); |
|
71 |
$self->js->html('#' . TAB_ID(), $html) |
|
72 |
->flash('info', $::form->{quotation} ? t8('Sales quotation #1 has been created.', $order->quonumber) : t8('Sales order #1 has been created.', $order->ordnumber)) |
|
39 | 73 |
->render($self); |
40 | 74 |
} |
41 | 75 |
|
... | ... | |
43 | 77 |
my ($self) = @_; |
44 | 78 |
|
45 | 79 |
my $html = $self->render('requirement_spec_order/edit_assignment', { output => 0 }, make_part_title => sub { $_[0]->partnumber . ' ' . $_[0]->description }); |
46 |
$self->js->html('#ui-tabs-4', $html)
|
|
80 |
$self->js->html('#' . TAB_ID(), $html)
|
|
47 | 81 |
->render($self); |
48 | 82 |
} |
49 | 83 |
|
... | ... | |
53 | 87 |
SL::DB::RequirementSpecItem->new(id => $_->{id})->load->update_attributes(order_part_id => ($_->{order_part_id} || undef)) for @{ $sections }; |
54 | 88 |
|
55 | 89 |
my $html = $self->render('requirement_spec_order/list', { output => 0 }); |
56 |
$self->js->html('#ui-tabs-4', $html)
|
|
90 |
$self->js->html('#' . TAB_ID(), $html)
|
|
57 | 91 |
->render($self); |
58 | 92 |
} |
59 | 93 |
|
... | ... | |
61 | 95 |
my ($self) = @_; |
62 | 96 |
|
63 | 97 |
my $html = $self->render('requirement_spec_order/list', { output => 0 }); |
64 |
$self->js->html('#ui-tabs-4', $html)
|
|
98 |
$self->js->html('#' . TAB_ID(), $html)
|
|
65 | 99 |
->render($self); |
66 | 100 |
} |
67 | 101 |
|
... | ... | |
74 | 108 |
|
75 | 109 |
$::auth->assert('sales_quotation_edit'); |
76 | 110 |
$::request->{layout}->use_stylesheet("${_}.css") for qw(jquery.contextMenu requirement_spec); |
77 |
$::request->{layout}->use_javascript("${_}.js") for qw(jquery.jstree jquery/jquery.contextMenu client_js requirement_spec); |
|
111 |
$::request->{layout}->use_javascript("${_}.js") for qw(jquery.jstree jquery/jquery.contextMenu client_js requirement_spec);
|
|
78 | 112 |
|
79 | 113 |
return 1; |
80 | 114 |
} |
... | ... | |
95 | 129 |
|
96 | 130 |
sub init_all_customers { SL::DB::Manager::Customer->get_all_sorted } |
97 | 131 |
sub init_all_parts { SL::DB::Manager::Part->get_all_sorted } |
132 |
sub init_h_unit_name { first { SL::DB::Manager::Unit->find_by(name => $_) } qw(Std h Stunde) }; |
|
133 |
|
|
134 |
sub load_parts_for_sections { |
|
135 |
my ($self, %params) = @_; |
|
136 |
|
|
137 |
$self->parts({ map { ($_->{id} => $_) } @{ SL::DB::Manager::Part->get_all(where => [ id => [ uniq map { $_->{order_part_id} } @{ $params{sections} } ] ]) } }); |
|
138 |
} |
|
139 |
|
|
140 |
sub create_order_item { |
|
141 |
my ($self, %params) = @_; |
|
142 |
|
|
143 |
my $section = $params{section}; |
|
144 |
my $item = $params{item} || SL::DB::OrderItem->new; |
|
145 |
my $part = $self->parts->{ $section->order_part_id }; |
|
146 |
my $description = $section->{keep_description} ? $item->description : $part->description; |
|
147 |
|
|
148 |
if (!$section->{keep_description}) { |
|
149 |
$description = '<%fb_number%> <%title%>' unless $description =~ m{<%}; |
|
150 |
$description =~ s{<% (.+?) %>}{$section->$1}egx; |
|
151 |
} |
|
152 |
|
|
153 |
$item->assign_attributes( |
|
154 |
parts_id => $part->id, |
|
155 |
description => $description, |
|
156 |
qty => $section->time_estimation * 1, |
|
157 |
unit => $self->h_unit_name, |
|
158 |
sellprice => $::form->round_amount($self->requirement_spec->hourly_rate, 2), |
|
159 |
discount => 0, |
|
160 |
project_id => $self->requirement_spec->project_id, |
|
161 |
); |
|
162 |
|
|
163 |
return $item; |
|
164 |
} |
|
165 |
|
|
166 |
sub create_order { |
|
167 |
my ($self, %params) = @_; |
|
168 |
|
|
169 |
$self->load_parts_for_sections(%params); |
|
170 |
|
|
171 |
my @orderitems = map { $self->create_order_item(section => $_) } @{ $params{sections} }; |
|
172 |
my $employee = SL::DB::Manager::Employee->current; |
|
173 |
my $customer = SL::DB::Customer->new(id => $::form->{customer_id})->load; |
|
174 |
my $order = SL::DB::Order->new( |
|
175 |
globalproject_id => $self->requirement_spec->project_id, |
|
176 |
transdate => DateTime->today_local, |
|
177 |
reqdate => $::form->{quotation} && $customer->payment_id ? $customer->payment->calc_date : undef, |
|
178 |
quotation => !!$::form->{quotation}, |
|
179 |
orderitems => \@orderitems, |
|
180 |
customer_id => $customer->id, |
|
181 |
taxincluded => $customer->taxincluded, |
|
182 |
intnotes => $customer->notes, |
|
183 |
language_id => $customer->language_id, |
|
184 |
payment_id => $customer->payment_id, |
|
185 |
taxzone_id => $customer->taxzone_id, |
|
186 |
employee_id => $employee->id, |
|
187 |
salesman_id => $employee->id, |
|
188 |
transaction_description => $self->requirement_spec->displayable_name, |
|
189 |
currency_id => $::instance_conf->get_currency_id, |
|
190 |
); |
|
191 |
|
|
192 |
$order->calculate_prices_and_taxes; |
|
193 |
|
|
194 |
return $order; |
|
195 |
} |
|
98 | 196 |
|
99 | 197 |
1; |
js/locale/de.js | ||
---|---|---|
8 | 8 |
"Copy":"Kopieren", |
9 | 9 |
"Copy requirement spec":"Pflichtenheft kopieren", |
10 | 10 |
"Copy template":"Vorlage kopieren", |
11 |
"Create":"Anlegen", |
|
11 | 12 |
"Create PDF":"PDF erzeugen", |
13 |
"Create new quotation/order":"Neues Angebot/neuen Auftrag anlegen", |
|
12 | 14 |
"Create new qutoation/order":"Neues Angebot/neuen Auftrag anlegen", |
13 | 15 |
"Create new version":"Neue Version anlegen", |
14 | 16 |
"Database Connection Test":"Test der Datenbankverbindung", |
js/requirement_spec.js | ||
---|---|---|
332 | 332 |
var data = 'action=RequirementSpecOrder/' + key |
333 | 333 |
+ '&' + $('#requirement_spec_id').serialize(); |
334 | 334 |
|
335 |
if (key == 'save_assignment')
|
|
335 |
if ((key == 'save_assignment') || (key == 'create'))
|
|
336 | 336 |
data += '&' + $('#quotations_and_orders_article_assignment_form').serialize(); |
337 | 337 |
else |
338 | 338 |
data += '&id=' + encodeURIComponent(ns.find_quotation_order_id(opt.$trigger)); |
... | ... | |
538 | 538 |
}, general_actions) |
539 | 539 |
}); |
540 | 540 |
|
541 |
$.contextMenu({ |
|
542 |
selector: '.quotations-and-orders-new-context-menu', |
|
543 |
items: $.extend({ |
|
544 |
heading: { name: kivi.t8('Create new quotation/order'), className: 'context-menu-heading' } |
|
545 |
, create: { name: kivi.t8('Create'), icon: "edit", callback: ns.standard_quotation_order_ajax_call } |
|
546 |
, cancel: { name: kivi.t8('Cancel'), icon: "close", callback: ns.standard_quotation_order_ajax_call } |
|
547 |
}, general_actions) |
|
548 |
}); |
|
549 |
|
|
541 | 550 |
$.contextMenu({ |
542 | 551 |
selector: '#content', |
543 | 552 |
items: general_actions |
locale/de/all | ||
---|---|---|
540 | 540 |
'Could not spawn the printer command.' => 'Die Druckanwendung konnte nicht gestartet werden.', |
541 | 541 |
'Could not update prices!' => 'Preise konnten nicht aktualisiert werden!', |
542 | 542 |
'Country' => 'Land', |
543 |
'Create' => 'Anlegen', |
|
543 | 544 |
'Create Assembly' => 'Erzeugnis fertigen', |
544 | 545 |
'Create Chart of Accounts' => 'Zu verwendender Kontenplan', |
545 | 546 |
'Create Dataset' => 'Neue Datenbank anlegen', |
... | ... | |
593 | 594 |
'Create new payment term' => 'Neue Zahlungsbedingung anlegen', |
594 | 595 |
'Create new project type' => 'Neuen Projekttypen anlegen', |
595 | 596 |
'Create new quotation or order' => 'Neues Angebot oder neuen Auftrag anlegen', |
597 |
'Create new quotation/order' => 'Neues Angebot/neuen Auftrag anlegen', |
|
596 | 598 |
'Create new qutoation/order' => 'Neues Angebot/neuen Auftrag anlegen', |
597 | 599 |
'Create new templates from master templates' => 'Neue Druckvorlagen aus Vorlagensatz erstellen', |
598 | 600 |
'Create new version' => 'Neue Version anlegen', |
... | ... | |
1951 | 1953 |
'Sales margin' => 'Marge', |
1952 | 1954 |
'Sales margin %' => 'Marge prozentual', |
1953 | 1955 |
'Sales net amount' => 'VK-Betrag', |
1956 |
'Sales order #1 has been created.' => 'Kundenauftrag #1 wurde angelegt.', |
|
1954 | 1957 |
'Sales price' => 'VK-Preis', |
1955 | 1958 |
'Sales price total' => 'VK-Betrag', |
1956 | 1959 |
'Sales quotation' => 'Angebot', |
1960 |
'Sales quotation #1 has been created.' => 'Angebot #1 wurde angelegt.', |
|
1957 | 1961 |
'Salesman' => 'Verkäufer/in', |
1958 | 1962 |
'Salesman (database ID)' => 'Verkäufer (Datenbank-ID)', |
1959 | 1963 |
'Salesperson' => 'Verkäufer', |
templates/webpages/requirement_spec_order/_assignment_form.html | ||
---|---|---|
1 | 1 |
[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE P -%] |
2 | 2 |
[% SET style="width: 400px" %] |
3 | 3 |
|
4 |
<table> |
|
5 |
[% IF for_new %] |
|
6 |
<tr> |
|
7 |
<td>[% LxERP.t8("Record type to create") %]:</td> |
|
8 |
<td>[% L.select_tag('quotation', [ [ 1, LxERP.t8('Sales quotation') ], [ 0, LxERP.t8('Sales Order') ] ], style=style, no_id=1) %]</td> |
|
9 |
</tr> |
|
4 |
<form id="quotations_and_orders_article_assignment_form"> |
|
5 |
<table> |
|
6 |
[% IF for_new %] |
|
7 |
<tr> |
|
8 |
<td>[% LxERP.t8("Record type to create") %]:</td> |
|
9 |
<td>[% L.select_tag('quotation', [ [ 1, LxERP.t8('Sales quotation') ], [ 0, LxERP.t8('Sales Order') ] ], style=style, no_id=1) %]</td> |
|
10 |
</tr> |
|
10 | 11 |
|
11 |
<tr> |
|
12 |
<td>[% LxERP.t8("Customer") %]:</td> |
|
13 |
<td>[% L.select_tag('customer_id', SELF.all_customers, default=SELF.requirement_spec.customer_id, title_key='name', style=style, no_id=1) %]</td> |
|
14 |
</tr> |
|
15 |
[% END %] |
|
12 |
<tr>
|
|
13 |
<td>[% LxERP.t8("Customer") %]:</td>
|
|
14 |
<td>[% L.select_tag('customer_id', SELF.all_customers, default=SELF.requirement_spec.customer_id, title_key='name', style=style, no_id=1) %]</td>
|
|
15 |
</tr>
|
|
16 |
[% END %]
|
|
16 | 17 |
|
17 |
<tr> |
|
18 |
<td>[% LxERP.t8("Assign the following article to all sections") %]:</td> |
|
19 |
<td> |
|
20 |
[% L.select_tag('quotations_and_orders_dummy', SELF.all_parts, default=INSTANCE_CONF.get_requirement_spec_section_order_part_id, title_sub=\make_part_title, id='quoations_and_orders_order_id', style=style) %] |
|
21 |
[% L.button_tag('kivi.requirement_spec.assign_order_part_id_to_all()', LxERP.t8('Assign article')) %] |
|
22 |
</td> |
|
23 |
</tr> |
|
24 |
</table> |
|
18 |
<tr>
|
|
19 |
<td>[% LxERP.t8("Assign the following article to all sections") %]:</td>
|
|
20 |
<td>
|
|
21 |
[% L.select_tag('quotations_and_orders_dummy', SELF.all_parts, default=INSTANCE_CONF.get_requirement_spec_section_order_part_id, title_sub=\make_part_title, id='quoations_and_orders_order_id', style=style) %]
|
|
22 |
[% L.button_tag('kivi.requirement_spec.assign_order_part_id_to_all()', LxERP.t8('Assign article')) %]
|
|
23 |
</td>
|
|
24 |
</tr>
|
|
25 |
</table>
|
|
25 | 26 |
|
26 |
<form id="quotations_and_orders_article_assignment_form"> |
|
27 | 27 |
<table style="width: 100%"> |
28 | 28 |
<thead> |
29 | 29 |
<tr class="listheading"> |
templates/webpages/requirement_spec_order/list.html | ||
---|---|---|
68 | 68 |
[% LxERP.t8("working copy") %] |
69 | 69 |
[% END %] |
70 | 70 |
</td> |
71 |
<td>[% HTML.escape(rs_order.order.quotation ? rs_order.order.quonumber : rs_order.order.ordnumber) %]</td> |
|
71 |
<td> |
|
72 |
<a href="oe.pl?action=edit&id=[% HTML.url(rs_order.order_id) %]&type=[% HTML.url(rs_order.order.type) %]"> |
|
73 |
[% HTML.escape(rs_order.order.quotation ? rs_order.order.quonumber : rs_order.order.ordnumber) %] |
|
74 |
</a> |
|
75 |
</td> |
|
72 | 76 |
<td>[% HTML.escape(rs_order.order.transaction_description) %]</td> |
73 | 77 |
<td>[% rs_order.order.transdate.to_kivitendo(precision='day') %]</td> |
74 | 78 |
<td>[% rs_order.itime.to_kivitendo(precision='day') %]</td> |
templates/webpages/requirement_spec_order/new.html | ||
---|---|---|
1 | 1 |
[%- USE LxERP -%][%- USE L -%] |
2 |
<div id="quotations_and_orders_new" class="quotations-and-orders-edit-assignment-context-menu">
|
|
2 |
<div id="quotations_and_orders_new" class="quotations-and-orders-new-context-menu">
|
|
3 | 3 |
<h2>[% LxERP.t8("Create new quotation or order") %]</h2> |
4 | 4 |
|
5 | 5 |
[% INCLUDE 'requirement_spec_order/_assignment_form.html' |
Auch abrufbar als: Unified diff
Pflichtenhefte: Anlegen von Angeboten/Aufträgen