From 90651b58b14d7e2dc26a996124d2ba2ef0ea42c2 Mon Sep 17 00:00:00 2001 From: Moritz Bunkus Date: Thu, 11 Jul 2013 11:50:29 +0200 Subject: [PATCH] =?utf8?q?Pflichtenhefte:=20Anlegen=20von=20Angeboten/Auft?= =?utf8?q?r=C3=A4gen?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- SL/Controller/RequirementSpecOrder.pm | 112 ++++++++++++++++-- js/locale/de.js | 2 + js/requirement_spec.js | 11 +- locale/de/all | 4 + .../_assignment_form.html | 40 +++---- .../webpages/requirement_spec_order/list.html | 6 +- .../webpages/requirement_spec_order/new.html | 2 +- 7 files changed, 147 insertions(+), 30 deletions(-) diff --git a/SL/Controller/RequirementSpecOrder.pm b/SL/Controller/RequirementSpecOrder.pm index 696b862b4..1c43cb43b 100644 --- a/SL/Controller/RequirementSpecOrder.pm +++ b/SL/Controller/RequirementSpecOrder.pm @@ -5,17 +5,24 @@ use utf8; use parent qw(SL::Controller::Base); +use List::MoreUtils qw(uniq); +use List::Util qw(first); + use SL::ClientJS; use SL::DB::Customer; +use SL::DB::Order; use SL::DB::Part; use SL::DB::RequirementSpec; use SL::DB::RequirementSpecOrder; use SL::Helper::Flash; use SL::Locale::String; +use constant TAB_ID => 'ui-tabs-4'; + use Rose::Object::MakeMethods::Generic ( - 'scalar --get_set_init' => [ qw(requirement_spec js all_customers all_parts) ], + scalar => [ qw(parts) ], + 'scalar --get_set_init' => [ qw(requirement_spec js h_unit_name all_customers all_parts) ], ); __PACKAGE__->run_before('setup'); @@ -24,7 +31,6 @@ __PACKAGE__->run_before('setup'); # actions # - sub action_list { my ($self) = @_; @@ -35,7 +41,35 @@ sub action_new { my ($self) = @_; my $html = $self->render('requirement_spec_order/new', { output => 0 }, make_part_title => sub { $_[0]->partnumber . ' ' . $_[0]->description }); - $self->js->html('#ui-tabs-4', $html) + $self->js->html('#' . TAB_ID(), $html) + ->render($self); +} + +sub action_create { + my ($self) = @_; + + # 1. Update sections with selected part IDs. + my $section_attrs = $::form->{sections} || []; + my $sections = SL::DB::Manager::RequirementSpecItem->get_all(where => [ id => [ map { $_->{id} } @{ $section_attrs } ] ]); + my %sections_by_id = map { ($_->{id} => $_) } @{ $sections }; + + $sections_by_id{ $_->{id} }->update_attributes(order_part_id => $_->{order_part_id}) for @{ $section_attrs }; + + # 2. Create actual quotation/order. + my $order = $self->create_order(sections => $sections); + $order->save; + + $self->requirement_spec->orders( + @{ $self->requirement_spec->orders }, + SL::DB::RequirementSpecOrder->new(order => $order, version => $self->requirement_spec->version) + ); + $self->requirement_spec->save; + $self->init_requirement_spec; + + # 3. Notify the user and return to list. + my $html = $self->render('requirement_spec_order/list', { output => 0 }); + $self->js->html('#' . TAB_ID(), $html) + ->flash('info', $::form->{quotation} ? t8('Sales quotation #1 has been created.', $order->quonumber) : t8('Sales order #1 has been created.', $order->ordnumber)) ->render($self); } @@ -43,7 +77,7 @@ sub action_edit_assignment { my ($self) = @_; my $html = $self->render('requirement_spec_order/edit_assignment', { output => 0 }, make_part_title => sub { $_[0]->partnumber . ' ' . $_[0]->description }); - $self->js->html('#ui-tabs-4', $html) + $self->js->html('#' . TAB_ID(), $html) ->render($self); } @@ -53,7 +87,7 @@ sub action_save_assignment { SL::DB::RequirementSpecItem->new(id => $_->{id})->load->update_attributes(order_part_id => ($_->{order_part_id} || undef)) for @{ $sections }; my $html = $self->render('requirement_spec_order/list', { output => 0 }); - $self->js->html('#ui-tabs-4', $html) + $self->js->html('#' . TAB_ID(), $html) ->render($self); } @@ -61,7 +95,7 @@ sub action_cancel { my ($self) = @_; my $html = $self->render('requirement_spec_order/list', { output => 0 }); - $self->js->html('#ui-tabs-4', $html) + $self->js->html('#' . TAB_ID(), $html) ->render($self); } @@ -74,7 +108,7 @@ sub setup { $::auth->assert('sales_quotation_edit'); $::request->{layout}->use_stylesheet("${_}.css") for qw(jquery.contextMenu requirement_spec); - $::request->{layout}->use_javascript("${_}.js") for qw(jquery.jstree jquery/jquery.contextMenu client_js requirement_spec); + $::request->{layout}->use_javascript("${_}.js") for qw(jquery.jstree jquery/jquery.contextMenu client_js requirement_spec); return 1; } @@ -95,5 +129,69 @@ sub init_js { sub init_all_customers { SL::DB::Manager::Customer->get_all_sorted } sub init_all_parts { SL::DB::Manager::Part->get_all_sorted } +sub init_h_unit_name { first { SL::DB::Manager::Unit->find_by(name => $_) } qw(Std h Stunde) }; + +sub load_parts_for_sections { + my ($self, %params) = @_; + + $self->parts({ map { ($_->{id} => $_) } @{ SL::DB::Manager::Part->get_all(where => [ id => [ uniq map { $_->{order_part_id} } @{ $params{sections} } ] ]) } }); +} + +sub create_order_item { + my ($self, %params) = @_; + + my $section = $params{section}; + my $item = $params{item} || SL::DB::OrderItem->new; + my $part = $self->parts->{ $section->order_part_id }; + my $description = $section->{keep_description} ? $item->description : $part->description; + + if (!$section->{keep_description}) { + $description = '<%fb_number%> <%title%>' unless $description =~ m{<%}; + $description =~ s{<% (.+?) %>}{$section->$1}egx; + } + + $item->assign_attributes( + parts_id => $part->id, + description => $description, + qty => $section->time_estimation * 1, + unit => $self->h_unit_name, + sellprice => $::form->round_amount($self->requirement_spec->hourly_rate, 2), + discount => 0, + project_id => $self->requirement_spec->project_id, + ); + + return $item; +} + +sub create_order { + my ($self, %params) = @_; + + $self->load_parts_for_sections(%params); + + my @orderitems = map { $self->create_order_item(section => $_) } @{ $params{sections} }; + my $employee = SL::DB::Manager::Employee->current; + my $customer = SL::DB::Customer->new(id => $::form->{customer_id})->load; + my $order = SL::DB::Order->new( + globalproject_id => $self->requirement_spec->project_id, + transdate => DateTime->today_local, + reqdate => $::form->{quotation} && $customer->payment_id ? $customer->payment->calc_date : undef, + quotation => !!$::form->{quotation}, + orderitems => \@orderitems, + customer_id => $customer->id, + taxincluded => $customer->taxincluded, + intnotes => $customer->notes, + language_id => $customer->language_id, + payment_id => $customer->payment_id, + taxzone_id => $customer->taxzone_id, + employee_id => $employee->id, + salesman_id => $employee->id, + transaction_description => $self->requirement_spec->displayable_name, + currency_id => $::instance_conf->get_currency_id, + ); + + $order->calculate_prices_and_taxes; + + return $order; +} 1; diff --git a/js/locale/de.js b/js/locale/de.js index 0739ec38a..38335a88c 100644 --- a/js/locale/de.js +++ b/js/locale/de.js @@ -8,7 +8,9 @@ namespace("kivi").setupLocale({ "Copy":"Kopieren", "Copy requirement spec":"Pflichtenheft kopieren", "Copy template":"Vorlage kopieren", +"Create":"Anlegen", "Create PDF":"PDF erzeugen", +"Create new quotation/order":"Neues Angebot/neuen Auftrag anlegen", "Create new qutoation/order":"Neues Angebot/neuen Auftrag anlegen", "Create new version":"Neue Version anlegen", "Database Connection Test":"Test der Datenbankverbindung", diff --git a/js/requirement_spec.js b/js/requirement_spec.js index 608c644dd..bf1e2307a 100644 --- a/js/requirement_spec.js +++ b/js/requirement_spec.js @@ -332,7 +332,7 @@ ns.standard_quotation_order_ajax_call = function(key, opt) { var data = 'action=RequirementSpecOrder/' + key + '&' + $('#requirement_spec_id').serialize(); - if (key == 'save_assignment') + if ((key == 'save_assignment') || (key == 'create')) data += '&' + $('#quotations_and_orders_article_assignment_form').serialize(); else data += '&id=' + encodeURIComponent(ns.find_quotation_order_id(opt.$trigger)); @@ -538,6 +538,15 @@ ns.create_context_menus = function(is_template) { }, general_actions) }); + $.contextMenu({ + selector: '.quotations-and-orders-new-context-menu', + items: $.extend({ + heading: { name: kivi.t8('Create new quotation/order'), className: 'context-menu-heading' } + , create: { name: kivi.t8('Create'), icon: "edit", callback: ns.standard_quotation_order_ajax_call } + , cancel: { name: kivi.t8('Cancel'), icon: "close", callback: ns.standard_quotation_order_ajax_call } + }, general_actions) + }); + $.contextMenu({ selector: '#content', items: general_actions diff --git a/locale/de/all b/locale/de/all index d1cefb9ff..a41548b9c 100755 --- a/locale/de/all +++ b/locale/de/all @@ -540,6 +540,7 @@ $self->{texts} = { 'Could not spawn the printer command.' => 'Die Druckanwendung konnte nicht gestartet werden.', 'Could not update prices!' => 'Preise konnten nicht aktualisiert werden!', 'Country' => 'Land', + 'Create' => 'Anlegen', 'Create Assembly' => 'Erzeugnis fertigen', 'Create Chart of Accounts' => 'Zu verwendender Kontenplan', 'Create Dataset' => 'Neue Datenbank anlegen', @@ -593,6 +594,7 @@ $self->{texts} = { 'Create new payment term' => 'Neue Zahlungsbedingung anlegen', 'Create new project type' => 'Neuen Projekttypen anlegen', 'Create new quotation or order' => 'Neues Angebot oder neuen Auftrag anlegen', + 'Create new quotation/order' => 'Neues Angebot/neuen Auftrag anlegen', 'Create new qutoation/order' => 'Neues Angebot/neuen Auftrag anlegen', 'Create new templates from master templates' => 'Neue Druckvorlagen aus Vorlagensatz erstellen', 'Create new version' => 'Neue Version anlegen', @@ -1951,9 +1953,11 @@ $self->{texts} = { 'Sales margin' => 'Marge', 'Sales margin %' => 'Marge prozentual', 'Sales net amount' => 'VK-Betrag', + 'Sales order #1 has been created.' => 'Kundenauftrag #1 wurde angelegt.', 'Sales price' => 'VK-Preis', 'Sales price total' => 'VK-Betrag', 'Sales quotation' => 'Angebot', + 'Sales quotation #1 has been created.' => 'Angebot #1 wurde angelegt.', 'Salesman' => 'Verkäufer/in', 'Salesman (database ID)' => 'Verkäufer (Datenbank-ID)', 'Salesperson' => 'Verkäufer', diff --git a/templates/webpages/requirement_spec_order/_assignment_form.html b/templates/webpages/requirement_spec_order/_assignment_form.html index f32e71524..6a15f2370 100644 --- a/templates/webpages/requirement_spec_order/_assignment_form.html +++ b/templates/webpages/requirement_spec_order/_assignment_form.html @@ -1,29 +1,29 @@ [%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE P -%] [% SET style="width: 400px" %] - -[% IF for_new %] - - - - + +
[% LxERP.t8("Record type to create") %]:[% L.select_tag('quotation', [ [ 1, LxERP.t8('Sales quotation') ], [ 0, LxERP.t8('Sales Order') ] ], style=style, no_id=1) %]
+ [% IF for_new %] + + + + - - - - -[% END %] + + + + + [% END %] - - - - -
[% LxERP.t8("Record type to create") %]:[% L.select_tag('quotation', [ [ 1, LxERP.t8('Sales quotation') ], [ 0, LxERP.t8('Sales Order') ] ], style=style, no_id=1) %]
[% LxERP.t8("Customer") %]:[% L.select_tag('customer_id', SELF.all_customers, default=SELF.requirement_spec.customer_id, title_key='name', style=style, no_id=1) %]
[% LxERP.t8("Customer") %]:[% L.select_tag('customer_id', SELF.all_customers, default=SELF.requirement_spec.customer_id, title_key='name', style=style, no_id=1) %]
[% LxERP.t8("Assign the following article to all sections") %]: - [% 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) %] - [% L.button_tag('kivi.requirement_spec.assign_order_part_id_to_all()', LxERP.t8('Assign article')) %] -
+ + [% LxERP.t8("Assign the following article to all sections") %]: + + [% 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) %] + [% L.button_tag('kivi.requirement_spec.assign_order_part_id_to_all()', LxERP.t8('Assign article')) %] + + + - diff --git a/templates/webpages/requirement_spec_order/list.html b/templates/webpages/requirement_spec_order/list.html index 4e0c15d2e..775ce1860 100644 --- a/templates/webpages/requirement_spec_order/list.html +++ b/templates/webpages/requirement_spec_order/list.html @@ -68,7 +68,11 @@ [% LxERP.t8("working copy") %] [% END %] - + diff --git a/templates/webpages/requirement_spec_order/new.html b/templates/webpages/requirement_spec_order/new.html index 7aaabd7e8..5be9660b3 100644 --- a/templates/webpages/requirement_spec_order/new.html +++ b/templates/webpages/requirement_spec_order/new.html @@ -1,5 +1,5 @@ [%- USE LxERP -%][%- USE L -%] -
+

[% LxERP.t8("Create new quotation or order") %]

[% INCLUDE 'requirement_spec_order/_assignment_form.html' -- 2.20.1
[% HTML.escape(rs_order.order.quotation ? rs_order.order.quonumber : rs_order.order.ordnumber) %] + + [% HTML.escape(rs_order.order.quotation ? rs_order.order.quonumber : rs_order.order.ordnumber) %] + + [% HTML.escape(rs_order.order.transaction_description) %] [% rs_order.order.transdate.to_kivitendo(precision='day') %] [% rs_order.itime.to_kivitendo(precision='day') %]