From 1cc65ebc086c1821dfcd08bcc97f8b6255dcec65 Mon Sep 17 00:00:00 2001 From: Moritz Bunkus Date: Thu, 11 Jul 2013 17:03:04 +0200 Subject: [PATCH] =?utf8?q?Pflichtenhefte:=20Aktualisieren=20von=20Angebote?= =?utf8?q?n/Auftr=C3=A4gen?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- SL/Controller/RequirementSpecOrder.pm | 78 +++++++++++++++++-- js/locale/de.js | 1 + js/requirement_spec.js | 21 +++-- locale/de/all | 7 ++ .../_assignment_form.html | 2 +- .../requirement_spec_order/update.html | 47 +++++++++++ 6 files changed, 142 insertions(+), 14 deletions(-) create mode 100644 templates/webpages/requirement_spec_order/update.html diff --git a/SL/Controller/RequirementSpecOrder.pm b/SL/Controller/RequirementSpecOrder.pm index 1c43cb43b..6dfab604b 100644 --- a/SL/Controller/RequirementSpecOrder.pm +++ b/SL/Controller/RequirementSpecOrder.pm @@ -22,7 +22,7 @@ use constant TAB_ID => 'ui-tabs-4'; use Rose::Object::MakeMethods::Generic ( scalar => [ qw(parts) ], - 'scalar --get_set_init' => [ qw(requirement_spec js h_unit_name all_customers all_parts) ], + 'scalar --get_set_init' => [ qw(requirement_spec rs_order js h_unit_name all_customers all_parts) ], ); __PACKAGE__->run_before('setup'); @@ -73,6 +73,69 @@ sub action_create { ->render($self); } +sub action_update { + my ($self) = @_; + + my $order = $self->rs_order->order; + my $sections = $self->requirement_spec->sections_sorted; + + my (@orderitems, %sections_seen); + foreach my $item (@{ $order->items_sorted }) { + my $section = first { my $num = $_->fb_number; $item->description =~ m{\b\Q${num}\E\b} && !$sections_seen{ $_->id } } @{ $sections }; + + $sections_seen{ $section->id } = 1 if $section; + + push @orderitems, { item => $item, section => $section }; + } + + my $html = $self->render( + 'requirement_spec_order/update', { output => 0 }, + orderitems => \@orderitems, + sections => $sections, + make_section_title => sub { $_[0]->fb_number . ' ' . $_[0]->title }, + ); + + $self->js->html('#' . TAB_ID(), $html) + ->render($self); +} + +sub action_do_update { + my ($self) = @_; + + my $order = $self->rs_order->order; + my $sections = $self->requirement_spec->sections_sorted; + my %orderitems_by_id = map { ($_->id => $_) } @{ $order->orderitems }; + my %sections_by_id = map { ($_->id => $_) } @{ $sections }; + $self->{parts} = { map { ($_->id => $_) } @{ SL::DB::Manager::Part->get_all(where => [ id => [ uniq map { $_->order_part_id } @{ $sections } ] ]) } }; + + my %sections_seen; + + foreach my $attributes (@{ $::form->{orderitems} || [] }) { + my $orderitem = $orderitems_by_id{ $attributes->{id} }; + my $section = $sections_by_id{ $attributes->{section_id} }; + next unless $orderitem && $section; + + $self->create_order_item(section => $section, item => $orderitem)->save; + $sections_seen{ $section->id } = 1; + } + + my @new_orderitems = map { $self->create_order_item(section => $_) } + grep { !$sections_seen{ $_->id } } + @{ $sections }; + + $order->orderitems([ @{ $order->orderitems }, @new_orderitems ]) if @new_orderitems; + + $order->calculate_prices_and_taxes; + $order->save; + + $self->init_requirement_spec; + + 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 updated.', $order->quonumber) : t8('Sales order #1 has been updated.', $order->ordnumber)) + ->render($self); +} + sub action_edit_assignment { my ($self) = @_; @@ -123,18 +186,18 @@ sub init_js { $self->js(SL::ClientJS->new); } -# -# helpers -# - 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 init_rs_order { SL::DB::RequirementSpecOrder->new(id => $::form->{rs_order_id})->load }; + +# +# helpers +# 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 { @@ -156,6 +219,7 @@ sub create_order_item { qty => $section->time_estimation * 1, unit => $self->h_unit_name, sellprice => $::form->round_amount($self->requirement_spec->hourly_rate, 2), + lastcost => $part->lastcost, discount => 0, project_id => $self->requirement_spec->project_id, ); @@ -166,7 +230,7 @@ sub create_order_item { sub create_order { my ($self, %params) = @_; - $self->load_parts_for_sections(%params); + $self->{parts} = { map { ($_->{id} => $_) } @{ SL::DB::Manager::Part->get_all(where => [ id => [ uniq map { $_->{order_part_id} } @{ $params{sections} } ] ]) } }; my @orderitems = map { $self->create_order_item(section => $_) } @{ $params{sections} }; my $employee = SL::DB::Manager::Employee->current; diff --git a/js/locale/de.js b/js/locale/de.js index 38335a88c..b425c1936 100644 --- a/js/locale/de.js +++ b/js/locale/de.js @@ -46,6 +46,7 @@ namespace("kivi").setupLocale({ "The selected database is still configured for client \"#1\". If you delete the database that client will stop working until you re-configure it. Do you still want to delete the database?":"Die auswählte Datenbank ist noch für Mandant \"#1\" konfiguriert. Wenn Sie die Datenbank löschen, wird der Mandanten nicht mehr funktionieren, bis er anders konfiguriert wurde. Wollen Sie die Datenbank trotzdem löschen?", "Time/cost estimate actions":"Aktionen für Kosten-/Zeitabschätzung", "Toggle marker":"Markierung umschalten", +"Update":"Erneuern", "Update quotation/order":"Auftrag/Angebot aktualisieren", "Version actions":"Aktionen für Versionen" }); diff --git a/js/requirement_spec.js b/js/requirement_spec.js index bf1e2307a..6ea5329ca 100644 --- a/js/requirement_spec.js +++ b/js/requirement_spec.js @@ -332,10 +332,10 @@ ns.standard_quotation_order_ajax_call = function(key, opt) { var data = 'action=RequirementSpecOrder/' + key + '&' + $('#requirement_spec_id').serialize(); - 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)); + if ((key == 'save_assignment') || (key == 'create') || (key == 'do_update')) + data += '&' + $('#quotations_and_orders_form').serialize(); + else if ((key == 'update') || (key == 'delete')) + data += '&rs_order_id=' + encodeURIComponent(ns.find_quotation_order_id(opt.$trigger)); // console.log("I would normally POST the following now:"); // console.log(data); @@ -354,7 +354,7 @@ ns.disable_create_quotation_order_commands = function(key, opt) { ns.assign_order_part_id_to_all = function() { var order_part_id = $('#quoations_and_orders_order_id').val(); - $('#quotations_and_orders_article_assignment_form SELECT[name="sections[].order_part_id"]').each(function(idx, elt) { + $('#quotations_and_orders_form SELECT[name="sections[].order_part_id"]').each(function(idx, elt) { $(elt).val(order_part_id); }); }; @@ -541,12 +541,21 @@ ns.create_context_menus = function(is_template) { $.contextMenu({ selector: '.quotations-and-orders-new-context-menu', items: $.extend({ - heading: { name: kivi.t8('Create new quotation/order'), className: 'context-menu-heading' } + 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: '.quotations-and-orders-update-context-menu', + items: $.extend({ + heading: { name: kivi.t8('Update quotation/order'), className: 'context-menu-heading' } + , do_update: { name: kivi.t8('Update'), icon: "update", 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 a41548b9c..af60767a2 100755 --- a/locale/de/all +++ b/locale/de/all @@ -795,6 +795,7 @@ $self->{texts} = { 'Display options' => 'Anzeigeoptionen', 'Do not change the tax rate of taxkey 0.' => 'Ändern Sie nicht den Steuersatz vom Steuerschlüssel 0.', 'Do not check for duplicates' => 'Nicht nach Dubletten suchen', + 'Do not modify this position' => 'Diese Position nicht verändern', 'Do not set default buchungsgruppe' => 'Nie Standardbuchungsgruppe setzen', 'Do you really want to cancel?' => 'Wollen Sie wirklich abbrechen?', 'Do you really want to close the following SEPA exports? No payment will be recorded for bank collections that haven\'t been marked as executed yet.' => 'Wollen Sie wirklich die folgenden SEPA-Exporte abschließen? Für Überweisungen, die noch nicht gebucht wurden, werden dann keine Zahlungen verbucht.', @@ -1954,10 +1955,12 @@ $self->{texts} = { 'Sales margin %' => 'Marge prozentual', 'Sales net amount' => 'VK-Betrag', 'Sales order #1 has been created.' => 'Kundenauftrag #1 wurde angelegt.', + 'Sales order #1 has been updated.' => 'Kundenauftrag #1 wurde aktualisiert.', 'Sales price' => 'VK-Preis', 'Sales price total' => 'VK-Betrag', 'Sales quotation' => 'Angebot', 'Sales quotation #1 has been created.' => 'Angebot #1 wurde angelegt.', + 'Sales quotation #1 has been updated.' => 'Angebot #1 wurde aktualisiert.', 'Salesman' => 'Verkäufer/in', 'Salesman (database ID)' => 'Verkäufer (Datenbank-ID)', 'Salesperson' => 'Verkäufer', @@ -1995,6 +1998,7 @@ $self->{texts} = { 'Section "#1"' => 'Abschnitt "#1"', 'Section/Function block actions' => 'Abschnitts-/Funktionsblockaktionen', 'Sections' => 'Abschnitte', + 'Sections that are not assigned to any of the items above will be added as new positions.' => 'Abschnitte, die keiner der oben aufgeführten Positionen zugeordnet sind, werden als neue Positionen ergänzt.', 'Select' => 'auswählen', 'Select a Customer' => 'Endkunde auswählen', 'Select a customer' => 'Einen Kunden auswählen', @@ -2626,6 +2630,9 @@ $self->{texts} = { 'Update prices of existing entries' => 'Preise von vorhandenen Artikeln aktualisieren', 'Update properties of existing entries' => 'Eigenschaften von existierenden Einträgen aktualisieren', 'Update quotation/order' => 'Auftrag/Angebot aktualisieren', + 'Update sales order #1' => 'Kundenauftrag #1 aktualisieren', + 'Update sales quotation #1' => 'Angebot #1 aktualisieren', + 'Update with section' => 'Mit Abschnitt aktualisieren', 'Updated' => 'Erneuert am', 'Updating existing entry in database' => 'Existierenden Eintrag in Datenbank aktualisieren', 'Updating prices of existing entry in database' => 'Preis des Eintrags in der Datenbank wird aktualisiert', diff --git a/templates/webpages/requirement_spec_order/_assignment_form.html b/templates/webpages/requirement_spec_order/_assignment_form.html index 6a15f2370..6df34bbb2 100644 --- a/templates/webpages/requirement_spec_order/_assignment_form.html +++ b/templates/webpages/requirement_spec_order/_assignment_form.html @@ -1,7 +1,7 @@ [%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE P -%] [% SET style="width: 400px" %] -
+ [% IF for_new %] diff --git a/templates/webpages/requirement_spec_order/update.html b/templates/webpages/requirement_spec_order/update.html new file mode 100644 index 000000000..f8ed1bffb --- /dev/null +++ b/templates/webpages/requirement_spec_order/update.html @@ -0,0 +1,47 @@ +[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE P -%] +[% SET style = "width: 400px" %] +[% SET order = SELF.rs_order.order %] + +
+ +

+ [% IF order.quotation %] + [% LxERP.t8("Update sales quotation #1", order.quonumber) %] + [% ELSE %] + [% LxERP.t8("Update sales order #1", order.ordnumber) %] + [% END %] +

+ + + [% L.hidden_tag("rs_order_id", SELF.rs_order.id, no_id=1) %] + +
+ + + + + + + + + + + + [% FOREACH item = orderitems %] + + [% L.hidden_tag("orderitems[+].id", item.item.id, no_id=1) %] + + + + + + + [% END %] + +
[% LxERP.t8("Part Number") %][% LxERP.t8("Description") %][% LxERP.t8("Qty") %][% LxERP.t8("Sellprice") %][% LxERP.t8("Update with section") %]
[% HTML.escape(item.item.part.partnumber) %][% HTML.escape(item.item.description) %][% LxERP.format_amount(item.item.qty * 1) %] [% HTML.escape(item.item.unit) %][% LxERP.format_amount(item.item.qty * 1) %] [% HTML.escape(item.item.unit) %][% L.select_tag('orderitems[].section_id', sections, default=item.section.id, title_sub=\make_section_title, style=style, no_id=1, with_empty=1, empty_title=LxERP.t8('Do not modify this position')) %]
+ +

+ [% LxERP.t8("Sections that are not assigned to any of the items above will be added as new positions.") %] +

+
+ -- 2.20.1