Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 1cc65ebc

Von Moritz Bunkus vor mehr als 10 Jahren hinzugefügt

  • ID 1cc65ebc086c1821dfcd08bcc97f8b6255dcec65
  • Vorgänger 90651b58
  • Nachfolger e142cf7d

Pflichtenhefte: Aktualisieren von Angeboten/Aufträgen

Unterschiede anzeigen:

SL/Controller/RequirementSpecOrder.pm
22 22
use Rose::Object::MakeMethods::Generic
23 23
(
24 24
  scalar                  => [ qw(parts) ],
25
  'scalar --get_set_init' => [ qw(requirement_spec js h_unit_name all_customers all_parts) ],
25
  'scalar --get_set_init' => [ qw(requirement_spec rs_order js h_unit_name all_customers all_parts) ],
26 26
);
27 27

  
28 28
__PACKAGE__->run_before('setup');
......
73 73
           ->render($self);
74 74
}
75 75

  
76
sub action_update {
77
  my ($self)   = @_;
78

  
79
  my $order    = $self->rs_order->order;
80
  my $sections = $self->requirement_spec->sections_sorted;
81

  
82
  my (@orderitems, %sections_seen);
83
  foreach my $item (@{ $order->items_sorted }) {
84
    my $section = first { my $num = $_->fb_number; $item->description =~ m{\b\Q${num}\E\b} && !$sections_seen{ $_->id } } @{ $sections };
85

  
86
    $sections_seen{ $section->id } = 1 if $section;
87

  
88
    push @orderitems, { item => $item, section => $section };
89
  }
90

  
91
  my $html = $self->render(
92
    'requirement_spec_order/update', { output => 0 },
93
    orderitems         => \@orderitems,
94
    sections           => $sections,
95
    make_section_title => sub { $_[0]->fb_number . ' ' . $_[0]->title },
96
  );
97

  
98
  $self->js->html('#' . TAB_ID(), $html)
99
           ->render($self);
100
}
101

  
102
sub action_do_update {
103
  my ($self)           = @_;
104

  
105
  my $order            = $self->rs_order->order;
106
  my $sections         = $self->requirement_spec->sections_sorted;
107
  my %orderitems_by_id = map { ($_->id => $_) } @{ $order->orderitems };
108
  my %sections_by_id   = map { ($_->id => $_) } @{ $sections };
109
  $self->{parts}       = { map { ($_->id => $_) } @{ SL::DB::Manager::Part->get_all(where => [ id => [ uniq map { $_->order_part_id } @{ $sections } ] ]) } };
110

  
111
  my %sections_seen;
112

  
113
  foreach my $attributes (@{ $::form->{orderitems} || [] }) {
114
    my $orderitem = $orderitems_by_id{ $attributes->{id}         };
115
    my $section   = $sections_by_id{   $attributes->{section_id} };
116
    next unless $orderitem && $section;
117

  
118
    $self->create_order_item(section => $section, item => $orderitem)->save;
119
    $sections_seen{ $section->id } = 1;
120
  }
121

  
122
  my @new_orderitems = map  { $self->create_order_item(section => $_) }
123
                       grep { !$sections_seen{ $_->id } }
124
                       @{ $sections };
125

  
126
  $order->orderitems([ @{ $order->orderitems }, @new_orderitems ]) if @new_orderitems;
127

  
128
  $order->calculate_prices_and_taxes;
129
  $order->save;
130

  
131
  $self->init_requirement_spec;
132

  
133
  my $html = $self->render('requirement_spec_order/list', { output => 0 });
134
  $self->js->html('#' . TAB_ID(), $html)
135
           ->flash('info', $::form->{quotation} ? t8('Sales quotation #1 has been updated.', $order->quonumber) : t8('Sales order #1 has been updated.', $order->ordnumber))
136
           ->render($self);
137
}
138

  
76 139
sub action_edit_assignment {
77 140
  my ($self) = @_;
78 141

  
......
123 186
  $self->js(SL::ClientJS->new);
124 187
}
125 188

  
126
#
127
# helpers
128
#
129

  
130 189
sub init_all_customers { SL::DB::Manager::Customer->get_all_sorted }
131 190
sub init_all_parts     { SL::DB::Manager::Part->get_all_sorted     }
132 191
sub init_h_unit_name   { first { SL::DB::Manager::Unit->find_by(name => $_) } qw(Std h Stunde) };
192
sub init_rs_order      { SL::DB::RequirementSpecOrder->new(id => $::form->{rs_order_id})->load };
193

  
194
#
195
# helpers
196
#
133 197

  
134 198
sub load_parts_for_sections {
135 199
  my ($self, %params) = @_;
136 200

  
137
  $self->parts({ map { ($_->{id} => $_) } @{ SL::DB::Manager::Part->get_all(where => [ id => [ uniq map { $_->{order_part_id} } @{ $params{sections} } ] ]) } });
138 201
}
139 202

  
140 203
sub create_order_item {
......
156 219
    qty         => $section->time_estimation * 1,
157 220
    unit        => $self->h_unit_name,
158 221
    sellprice   => $::form->round_amount($self->requirement_spec->hourly_rate, 2),
222
    lastcost    => $part->lastcost,
159 223
    discount    => 0,
160 224
    project_id  => $self->requirement_spec->project_id,
161 225
  );
......
166 230
sub create_order {
167 231
  my ($self, %params) = @_;
168 232

  
169
  $self->load_parts_for_sections(%params);
233
  $self->{parts} = { map { ($_->{id} => $_) } @{ SL::DB::Manager::Part->get_all(where => [ id => [ uniq map { $_->{order_part_id} } @{ $params{sections} } ] ]) } };
170 234

  
171 235
  my @orderitems = map { $self->create_order_item(section => $_) } @{ $params{sections} };
172 236
  my $employee   = SL::DB::Manager::Employee->current;
js/locale/de.js
46 46
"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?",
47 47
"Time/cost estimate actions":"Aktionen für Kosten-/Zeitabschätzung",
48 48
"Toggle marker":"Markierung umschalten",
49
"Update":"Erneuern",
49 50
"Update quotation/order":"Auftrag/Angebot aktualisieren",
50 51
"Version actions":"Aktionen für Versionen"
51 52
});
js/requirement_spec.js
332 332
  var data = 'action=RequirementSpecOrder/' + key
333 333
           + '&' + $('#requirement_spec_id').serialize();
334 334

  
335
  if ((key == 'save_assignment') || (key == 'create'))
336
    data += '&' + $('#quotations_and_orders_article_assignment_form').serialize();
337
  else
338
    data += '&id=' + encodeURIComponent(ns.find_quotation_order_id(opt.$trigger));
335
  if ((key == 'save_assignment') || (key == 'create') || (key == 'do_update'))
336
    data += '&' + $('#quotations_and_orders_form').serialize();
337
  else if ((key == 'update') || (key == 'delete'))
338
    data += '&rs_order_id=' + encodeURIComponent(ns.find_quotation_order_id(opt.$trigger));
339 339

  
340 340
  // console.log("I would normally POST the following now:");
341 341
  // console.log(data);
......
354 354

  
355 355
ns.assign_order_part_id_to_all = function() {
356 356
  var order_part_id = $('#quoations_and_orders_order_id').val();
357
  $('#quotations_and_orders_article_assignment_form SELECT[name="sections[].order_part_id"]').each(function(idx, elt) {
357
  $('#quotations_and_orders_form SELECT[name="sections[].order_part_id"]').each(function(idx, elt) {
358 358
    $(elt).val(order_part_id);
359 359
  });
360 360
};
......
541 541
  $.contextMenu({
542 542
    selector: '.quotations-and-orders-new-context-menu',
543 543
    items:    $.extend({
544
        heading: { name: kivi.t8('Create new quotation/order'), className: 'context-menu-heading'    }
544
        heading: { name: kivi.t8('Create new quotation/order'), className: 'context-menu-heading'          }
545 545
      , create:  { name: kivi.t8('Create'), icon: "edit",  callback: ns.standard_quotation_order_ajax_call }
546 546
      , cancel:  { name: kivi.t8('Cancel'), icon: "close", callback: ns.standard_quotation_order_ajax_call }
547 547
    }, general_actions)
548 548
  });
549 549

  
550
  $.contextMenu({
551
    selector: '.quotations-and-orders-update-context-menu',
552
    items:    $.extend({
553
        heading:   { name: kivi.t8('Update quotation/order'), className: 'context-menu-heading'               }
554
      , do_update: { name: kivi.t8('Update'), icon: "update", callback: ns.standard_quotation_order_ajax_call }
555
      , cancel:    { name: kivi.t8('Cancel'), icon: "close",  callback: ns.standard_quotation_order_ajax_call }
556
    }, general_actions)
557
  });
558

  
550 559
  $.contextMenu({
551 560
    selector: '#content',
552 561
    items:    general_actions
locale/de/all
795 795
  'Display options'             => 'Anzeigeoptionen',
796 796
  'Do not change the tax rate of taxkey 0.' => 'Ändern Sie nicht den Steuersatz vom Steuerschlüssel 0.',
797 797
  'Do not check for duplicates' => 'Nicht nach Dubletten suchen',
798
  'Do not modify this position' => 'Diese Position nicht verändern',
798 799
  'Do not set default buchungsgruppe' => 'Nie Standardbuchungsgruppe setzen',
799 800
  'Do you really want to cancel?' => 'Wollen Sie wirklich abbrechen?',
800 801
  '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 1955
  'Sales margin %'              => 'Marge prozentual',
1955 1956
  'Sales net amount'            => 'VK-Betrag',
1956 1957
  'Sales order #1 has been created.' => 'Kundenauftrag #1 wurde angelegt.',
1958
  'Sales order #1 has been updated.' => 'Kundenauftrag #1 wurde aktualisiert.',
1957 1959
  'Sales price'                 => 'VK-Preis',
1958 1960
  'Sales price total'           => 'VK-Betrag',
1959 1961
  'Sales quotation'             => 'Angebot',
1960 1962
  'Sales quotation #1 has been created.' => 'Angebot #1 wurde angelegt.',
1963
  'Sales quotation #1 has been updated.' => 'Angebot #1 wurde aktualisiert.',
1961 1964
  'Salesman'                    => 'Verkäufer/in',
1962 1965
  'Salesman (database ID)'      => 'Verkäufer (Datenbank-ID)',
1963 1966
  'Salesperson'                 => 'Verkäufer',
......
1995 1998
  'Section "#1"'                => 'Abschnitt "#1"',
1996 1999
  'Section/Function block actions' => 'Abschnitts-/Funktionsblockaktionen',
1997 2000
  'Sections'                    => 'Abschnitte',
2001
  '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.',
1998 2002
  'Select'                      => 'auswählen',
1999 2003
  'Select a Customer'           => 'Endkunde auswählen',
2000 2004
  'Select a customer'           => 'Einen Kunden auswählen',
......
2626 2630
  'Update prices of existing entries' => 'Preise von vorhandenen Artikeln aktualisieren',
2627 2631
  'Update properties of existing entries' => 'Eigenschaften von existierenden Einträgen aktualisieren',
2628 2632
  'Update quotation/order'      => 'Auftrag/Angebot aktualisieren',
2633
  'Update sales order #1'       => 'Kundenauftrag #1 aktualisieren',
2634
  'Update sales quotation #1'   => 'Angebot #1 aktualisieren',
2635
  'Update with section'         => 'Mit Abschnitt aktualisieren',
2629 2636
  'Updated'                     => 'Erneuert am',
2630 2637
  'Updating existing entry in database' => 'Existierenden Eintrag in Datenbank aktualisieren',
2631 2638
  'Updating prices of existing entry in database' => 'Preis des Eintrags in der Datenbank wird aktualisiert',
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
<form id="quotations_and_orders_article_assignment_form">
4
<form id="quotations_and_orders_form">
5 5
 <table>
6 6
  [% IF for_new %]
7 7
  <tr>
templates/webpages/requirement_spec_order/update.html
1
[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE P -%]
2
[% SET style = "width: 400px" %]
3
[% SET order = SELF.rs_order.order %]
4

  
5
<div class="quotations-and-orders-update-context-menu">
6

  
7
 <h2>
8
  [% IF order.quotation %]
9
   [% LxERP.t8("Update sales quotation #1", order.quonumber) %]
10
  [% ELSE %]
11
   [% LxERP.t8("Update sales order #1", order.ordnumber) %]
12
  [% END %]
13
 </h2>
14

  
15
 <form id="quotations_and_orders_form">
16
  [% L.hidden_tag("rs_order_id", SELF.rs_order.id, no_id=1) %]
17

  
18
  <table style="width: 100%">
19
   <thead>
20
    <tr class="listheading">
21
     <th>[% LxERP.t8("Part Number") %]</th>
22
     <th>[% LxERP.t8("Description") %]</th>
23
     <th align="right">[% LxERP.t8("Qty") %]</th>
24
     <th align="right">[% LxERP.t8("Sellprice") %]</th>
25
     <th>[% LxERP.t8("Update with section") %]</th>
26
    </tr>
27
   </thead>
28

  
29
   <tbody>
30
    [% FOREACH item = orderitems %]
31
    <tr class="listrow">
32
     [% L.hidden_tag("orderitems[+].id", item.item.id, no_id=1) %]
33
     <td>[% HTML.escape(item.item.part.partnumber) %]</td>
34
     <td>[% HTML.escape(item.item.description) %]</td>
35
     <td align="right">[% LxERP.format_amount(item.item.qty * 1) %] [% HTML.escape(item.item.unit) %]</td>
36
     <td align="right">[% LxERP.format_amount(item.item.qty * 1) %] [% HTML.escape(item.item.unit) %]</td>
37
     <td>[% 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')) %]</td>
38
    </tr>
39
    [% END %]
40
   </tbody>
41
  </table>
42

  
43
  <p>
44
   [% LxERP.t8("Sections that are not assigned to any of the items above will be added as new positions.") %]
45
  </p>
46
 </form>
47
</div>

Auch abrufbar als: Unified diff