Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 0c319351

Von Moritz Bunkus vor mehr als 10 Jahren hinzugefügt

  • ID 0c3193511e1ea50fad793887ede6ac5732d85074
  • Vorgänger 4bc8abba
  • Nachfolger 31ead75c

Pflichtenhefte: zusätzliche Artikel zuweisen und bearbeiten können

Unterschiede anzeigen:

SL/Controller/RequirementSpecOrder.pm
70 70
  $order->db->with_transaction(sub {
71 71
    $order->save;
72 72

  
73
    $self->requirement_spec->orders(
74
      @{ $self->requirement_spec->orders },
75
      SL::DB::RequirementSpecOrder->new(order => $order, version => $self->requirement_spec->version)
76
    );
73
    $self->requirement_spec->add_orders(SL::DB::RequirementSpecOrder->new(order => $order, version => $self->requirement_spec->version));
77 74
    $self->requirement_spec->save;
78 75

  
79 76
    $self->requirement_spec->link_to_record($order);
......
247 244
# helpers
248 245
#
249 246

  
250
sub load_parts_for_sections {
251
  my ($self, %params) = @_;
252

  
253
}
254

  
255 247
sub create_order_item {
256 248
  my ($self, %params) = @_;
257 249

  
SL/Controller/RequirementSpecPart.pm
1
package SL::Controller::RequirementSpecPart;
2

  
3
use strict;
4

  
5
use parent qw(SL::Controller::Base);
6

  
7
use Carp;
8
use List::MoreUtils qw(any);
9

  
10
use SL::ClientJS;
11
use SL::DB::Customer;
12
use SL::DB::Project;
13
use SL::DB::RequirementSpec;
14
use SL::DB::RequirementSpecPart;
15
use SL::Helper::Flash;
16
use SL::Locale::String;
17

  
18
use Rose::Object::MakeMethods::Generic
19
(
20
  'scalar --get_set_init' => [ qw(requirement_spec js) ],
21
);
22

  
23
__PACKAGE__->run_before('check_auth');
24

  
25
#
26
# actions
27
#
28

  
29
sub action_show {
30
  my ($self, %params) = @_;
31

  
32
  $self->render('requirement_spec_part/show', { layout => 0 });
33
}
34

  
35
sub action_ajax_edit {
36
  my ($self, %params) = @_;
37

  
38
  my $html = $self->render('requirement_spec_part/_edit', { output => 0 });
39

  
40
  $self->js
41
   ->hide('#additional_parts_list_container')
42
   ->after('#additional_parts_list_container', $html)
43
   ->on('#edit_additional_parts_form INPUT[type=text]', 'keydown', 'kivi.requirement_spec.additional_parts_input_key_down')
44
   ->focus('#additional_parts_add_part_id_name')
45
   ->run('kivi.requirement_spec.prepare_edit_additional_parts_form')
46
   ->reinit_widgets
47
   ->render;
48
}
49

  
50
sub action_ajax_add {
51
  my ($self)  = @_;
52

  
53
  my $part      = SL::DB::Part->new(id => $::form->{part_id})->load(with_objects => [ qw(unit_obj) ]);
54
  my $rs_part   = SL::DB::RequirementSpecPart->new(
55
    part        => $part,
56
    qty         => 1,
57
    unit        => $part->unit_obj,
58
    description => $part->description,
59
  );
60
  my $row       = $self->render('requirement_spec_part/_part', { output => 0 }, part => $rs_part);
61

  
62
  $self->js
63
   ->val(  '#additional_parts_add_part_id',      '')
64
   ->val(  '#additional_parts_add_part_id_name', '')
65
   ->focus('#additional_parts_add_part_id_name')
66
   ->append('#edit_additional_parts_list tbody', $row)
67
   ->hide('#edit_additional_parts_list_empty')
68
   ->show('#edit_additional_parts_list')
69
   ->render;
70
}
71

  
72
sub action_ajax_save {
73
  my ($self) = @_;
74

  
75
  my $db = $self->requirement_spec->db;
76
  $db->do_transaction(sub {
77
    # Make Emacs happy
78
    1;
79
    my $parts    = $::form->{additional_parts} || [];
80
    my $position = 1;
81
    $_->{position} = $position++ for @{ $parts };
82

  
83
    $self->requirement_spec->update_attributes(parts => $parts)->load;
84

  
85
    1;
86
  }) or do {
87
    return $self->js->error(t8('Saving failed. Error message from the database: #1', $db->error))->render;
88
  };
89

  
90
  my $html = $self->render('requirement_spec_part/show', { output => 0 }, initially_hidden => !!$::form->{keep_open});
91

  
92
  $self->js
93
    ->replaceWith('#additional_parts_list_container', $html)
94
    ->action_if(!$::form->{keep_open}, 'remove', '#additional_parts_form_container')
95
    ->render;
96
}
97

  
98
#
99
# filters
100
#
101

  
102
sub check_auth {
103
  my ($self, %params) = @_;
104
  $::auth->assert('requirement_spec_edit');
105
}
106

  
107
#
108
# helpers
109
#
110

  
111
sub init_js { SL::ClientJS->new(controller => $_[0]) }
112

  
113
sub init_requirement_spec {
114
  SL::DB::RequirementSpec->new(id => $::form->{requirement_spec_id})->load(
115
    with_objects => [ qw(parts parts.part parts.unit) ],
116
  );
117
}
118

  
119
1;
SL/DB/Helper/ALL.pm
83 83
use SL::DB::RequirementSpecDependency;
84 84
use SL::DB::RequirementSpecItem;
85 85
use SL::DB::RequirementSpecOrder;
86
use SL::DB::RequirementSpecPart;
86 87
use SL::DB::RequirementSpecPicture;
87 88
use SL::DB::RequirementSpecPredefinedText;
88 89
use SL::DB::RequirementSpecRisk;
SL/DB/Helper/Mappings.pm
163 163
  requirement_spec_item_dependencies   => 'RequirementSpecDependency',
164 164
  requirement_spec_items               => 'RequirementSpecItem',
165 165
  requirement_spec_orders              => 'RequirementSpecOrder',
166
  requirement_spec_parts               => 'RequirementSpecPart',
166 167
  requirement_spec_pictures            => 'RequirementSpecPicture',
167 168
  requirement_spec_predefined_texts    => 'RequirementSpecPredefinedText',
168 169
  requirement_spec_risks               => 'RequirementSpecRisk',
SL/DB/Manager/RequirementSpecPart.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::RequirementSpecPart;
5

  
6
use strict;
7

  
8
use SL::DB::Helper::Manager;
9
use base qw(SL::DB::Helper::Manager);
10

  
11
sub object_class { 'SL::DB::RequirementSpecPart' }
12

  
13
__PACKAGE__->make_manager_methods;
14

  
15
1;
SL/DB/MetaSetup/RequirementSpecPart.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::RequirementSpecPart;
4

  
5
use strict;
6

  
7
use base qw(SL::DB::Object);
8

  
9
__PACKAGE__->meta->table('requirement_spec_parts');
10

  
11
__PACKAGE__->meta->columns(
12
  id                  => { type => 'serial', not_null => 1 },
13
  description         => { type => 'text', not_null => 1 },
14
  part_id             => { type => 'integer', not_null => 1 },
15
  position            => { type => 'integer', not_null => 1 },
16
  qty                 => { type => 'numeric', not_null => 1, precision => 15, scale => 5 },
17
  requirement_spec_id => { type => 'integer', not_null => 1 },
18
  unit_id             => { type => 'integer', not_null => 1 },
19
);
20

  
21
__PACKAGE__->meta->primary_key_columns([ 'id' ]);
22

  
23
__PACKAGE__->meta->foreign_keys(
24
  part => {
25
    class       => 'SL::DB::Part',
26
    key_columns => { part_id => 'id' },
27
  },
28

  
29
  requirement_spec => {
30
    class       => 'SL::DB::RequirementSpec',
31
    key_columns => { requirement_spec_id => 'id' },
32
  },
33

  
34
  unit => {
35
    class       => 'SL::DB::Unit',
36
    key_columns => { unit_id => 'id' },
37
  },
38
);
39

  
40
1;
41
;
SL/DB/RequirementSpec.pm
43 43
    class          => 'SL::DB::RequirementSpecOrder',
44 44
    column_map     => { id => 'requirement_spec_id' },
45 45
  },
46
  parts            => {
47
    type           => 'one to many',
48
    class          => 'SL::DB::RequirementSpecPart',
49
    column_map     => { id => 'requirement_spec_id' },
50
  },
46 51
);
47 52

  
48 53
__PACKAGE__->meta->initialize;
......
119 124
  return \@copies;
120 125
}
121 126

  
127
sub parts_sorted {
128
  my ($self, @rest) = @_;
129

  
130
  croak "This sub is not a writer" if @rest;
131

  
132
  return [ sort { $a->position <=> $b->position } @{ $self->parts } ];
133
}
134

  
122 135
sub create_copy {
123 136
  my ($self, %params) = @_;
124 137

  
......
519 532
given then only the text blocks belonging to that C<output_position>
520 533
are returned.
521 534

  
535
=item C<parts_sorted>
536

  
537
Returns an array reference of additional parts sorted by their
538
positional column in ascending order.
539

  
522 540
=item C<validate>
523 541

  
524 542
Validate values before saving. Returns list or human-readable error
SL/DB/RequirementSpecPart.pm
1
package SL::DB::RequirementSpecPart;
2

  
3
use strict;
4

  
5
use SL::DB::MetaSetup::RequirementSpecPart;
6
use SL::DB::Manager::RequirementSpecPart;
7
use SL::DB::Helper::ActsAsList;
8

  
9
__PACKAGE__->meta->initialize;
10

  
11
1;
js/locale/de.js
7 7
"Add section":"Abschnitt hinzufügen",
8 8
"Add sub function block":"Unterfunktionsblock hinzufügen",
9 9
"Add text block":"Textblock erfassen",
10
"Additional articles actions":"Aktionen zu zusätzlichen Artikeln",
10 11
"Are you sure?":"Sind Sie sicher?",
11 12
"Basic settings actions":"Aktionen zu Grundeinstellungen",
12 13
"Cancel":"Abbrechen",
......
44 45
"Paste template":"Vorlage einfügen",
45 46
"Project link actions":"Projektverknüpfungs-Aktionen",
46 47
"Quotations/Orders actions":"Aktionen für Angebote/Aufträge",
48
"Remove article":"Artikel entfernen",
47 49
"Requirement spec actions":"Pflichtenheftaktionen",
48 50
"Requirement spec template actions":"Pflichtenheftvorlagen-Aktionen",
49 51
"Revert to version":"Auf Version zurücksetzen",
js/requirement_spec.js
644 644
  return true;
645 645
};
646 646

  
647
// -------------------------------------------------------------------------
648
// -------------------------- time/cost estimate ---------------------------
649
// -------------------------------------------------------------------------
650

  
651
ns.standard_time_cost_estimate_ajax_call = function(key, opt) {
652
  if (key == 'cancel') {
653
    if (confirm(kivi.t8('Do you really want to cancel?'))) {
654
      $('#time_cost_estimate').show();
655
      $('#time_cost_estimate_form_container').remove();
656
    }
657
    return true;
658
  }
659

  
660
  var add_data = '';
661
  if (key == 'save_keep_open') {
662
    key      = 'save';
663
    add_data = 'keep_open=1&';
664
  }
665

  
666
  var data = "action=RequirementSpec/ajax_" + key + "_time_and_cost_estimate&" + add_data;
667

  
668
  if (key == 'save')
669
    data += $('#edit_time_cost_estimate_form').serialize()
670
         +  '&' + $('#current_content_type').serialize()
671
         +  '&' + $('#current_content_id').serialize();
672
  else
673
    data += 'id=' + encodeURIComponent($('#requirement_spec_id').val());
674

  
675
  $.post("controller.pl", data, kivi.eval_json_result);
676

  
677
  return true;
678
};
679

  
680
ns.time_cost_estimate_input_key_down = function(event) {
681
  if(event.keyCode == 13) {
682
    event.preventDefault();
683
    ns.standard_time_cost_estimate_ajax_call('save');
684
    return false;
685
  }
686
};
687

  
688
// -------------------------------------------------------------------------
689
// -------------------------- additional parts -----------------------------
690
// -------------------------------------------------------------------------
691

  
692
ns.standard_additional_parts_ajax_call = function(key, opt) {
693
  var add_data = '';
694
  if (key == 'save_keep_open') {
695
    key      = 'save';
696
    add_data = 'keep_open=1&';
697
  }
698

  
699
  var data = "action=RequirementSpecPart/ajax_" + key + "&" + add_data + 'requirement_spec_id=' + encodeURIComponent($('#requirement_spec_id').val()) + '&';
700

  
701
  if (key == 'save')
702
    data += $('#edit_additional_parts_form').serialize();
703

  
704
  $.post("controller.pl", data, kivi.eval_json_result);
705

  
706
  return true;
707
};
708

  
709
ns.prepare_edit_additional_parts_form = function() {
710
  $("#edit_additional_parts_list tbody").sortable({
711
    distance: 5,
712
    handle:   '.dragdrop',
713
    helper:   function(event, ui) {
714
      ui.children().each(function() {
715
        $(this).width($(this).width());
716
      });
717
      return ui;
718
    }
719

  
720
  });
721
};
722

  
723
ns.cancel_edit_additional_parts_form = function() {
724
  if (confirm(kivi.t8('Do you really want to cancel?'))) {
725
    $('#additional_parts_list_container').show();
726
    $('#additional_parts_form_container').remove();
727
  }
728
  return true;
729
};
730

  
731
ns.additional_parts_input_key_down = function(event) {
732
  if(event.keyCode == 13) {
733
    event.preventDefault();
734
    ns.standard_additional_parts_ajax_call('save');
735
    return false;
736
  }
737
};
738

  
739
ns.add_additional_part = function() {
740
  var part_id = $('#additional_parts_add_part_id').val();
741
  if (!part_id || (part_id == ''))
742
    return false;
743

  
744
  var rspec_id = $('#requirement_spec_id').val();
745
  var data     = 'action=RequirementSpecPart/ajax_add&requirement_spec_id=' + encodeURIComponent(rspec_id) + '&part_id=' + encodeURIComponent(part_id);
746

  
747
  $.post("controller.pl", data, kivi.eval_json_result);
748

  
749
  return true;
750
};
751

  
752
ns.delete_additional_part = function(key, opt) {
753
  opt.$trigger.remove();
754
  if (!$('#edit_additional_parts_list tbody tr').size()) {
755
   $('#edit_additional_parts_list_empty').show();
756
   $('#edit_additional_parts_list').hide();
757
  }
758

  
759
  return true;
760
};
761

  
647 762
// -------------------------------------------------------------------------
648 763
// ------------------------------- tab widget ------------------------------
649 764
// -------------------------------------------------------------------------
......
651 766
    'tab-header-function-block':     'function-blocks-tab'
652 767
  , 'tab-header-basic-settings':     'ui-tabs-1'
653 768
  , 'tab-header-time-cost-estimate': 'ui-tabs-2'
654
  , 'tab-header-versions':           'ui-tabs-3'
655
  , 'tab-header-quotations-orders':  'ui-tabs-4'
769
  , 'tab-header-additional-parts':   'ui-tabs-3'
770
  , 'tab-header-versions':           'ui-tabs-4'
771
  , 'tab-header-quotations-orders':  'ui-tabs-5'
656 772
};
657 773

  
658 774
ns.tabs_before_activate = function(event, ui) {
......
804 920
    }, general_actions)
805 921
  });
806 922

  
923
  $.contextMenu({
924
    selector: '.additional-parts-context-menu',
925
    items:    $.extend({
926
        heading: { name: kivi.t8('Additional articles actions'), className: 'context-menu-heading' }
927
      , edit:    { name: kivi.t8('Edit'), icon: "edit", callback: kivi.requirement_spec.standard_additional_parts_ajax_call }
928
    }, general_actions)
929
  });
930

  
931
  var additional_parts_actions = {
932
      save:           { name: kivi.t8('Save'),               icon: "save",  callback: kivi.requirement_spec.standard_additional_parts_ajax_call }
933
    , save_keep_open: { name: kivi.t8('Save and keep open'), icon: "save",  callback: kivi.requirement_spec.standard_additional_parts_ajax_call }
934
    , cancel:         { name: kivi.t8('Cancel'),             icon: "close",  callback: kivi.requirement_spec.cancel_edit_additional_parts_form }
935
  };
936

  
937
  $.contextMenu({
938
    selector: '.edit-additional-parts-context-menu',
939
    items:    $.extend({
940
        heading:        { name: kivi.t8('Additional articles actions'), className: 'context-menu-heading' }
941
    }, additional_parts_actions, general_actions)
942
  });
943

  
944
  $.contextMenu({
945
    selector: '.edit-additional-parts-row-context-menu',
946
    items:    $.extend({
947
        heading:        { name: kivi.t8('Additional articles actions'), className: 'context-menu-heading' }
948
      , delete:         { name: kivi.t8('Remove article'),     icon: "delete", callback: kivi.requirement_spec.delete_additional_part }
949
    }, additional_parts_actions, general_actions)
950
  });
951

  
807 952
  $.contextMenu({
808 953
    selector: '.quotations-and-orders-context-menu,.quotations-and-orders-order-context-menu',
809 954
    items:    $.extend({
locale/de/all
176 176
  'Add new currency'            => 'Neue Währung hinzufügen',
177 177
  'Add new custom variable'     => 'Neue benutzerdefinierte Variable erfassen',
178 178
  'Add note'                    => 'Notiz erfassen',
179
  'Add part'                    => 'Artikel hinzufügen',
179 180
  'Add picture'                 => 'Bild hinzufügen',
180 181
  'Add picture to text block'   => 'Bild dem Textblock hinzufügen',
181 182
  'Add section'                 => 'Abschnitt hinzufügen',
......
185 186
  'Add unit'                    => 'Einheit hinzuf&uuml;gen',
186 187
  'Added sections and function blocks: #1' => 'Hinzugefügte Abschnitte und Funktionsblöcke: #1',
187 188
  'Added text blocks: #1'       => 'Hinzugefügte Textblöcke: #1',
189
  'Additional articles'         => 'Zusätzliche Artikel',
190
  'Additional articles actions' => 'Aktionen zu zusätzlichen Artikeln',
188 191
  'Address'                     => 'Adresse',
189 192
  'Admin'                       => 'Administration',
190 193
  'Administration'              => 'Administration',
......
933 936
  'Edit Vendor Invoice'         => 'Einkaufsrechnung bearbeiten',
934 937
  'Edit Warehouse'              => 'Lager bearbeiten',
935 938
  'Edit acceptance status'      => 'Abnahmestatus bearbeiten',
939
  'Edit additional articles'    => 'Zusätzliche Artikel bearbeiten',
936 940
  'Edit article/section assignments' => 'Zuweisung Artikel/Abschnitte bearbeiten',
937 941
  'Edit assignment of articles to sections' => 'Zuweisung Artikel zu Abschnitten bearbeiten',
938 942
  'Edit background job'         => 'Hintergrund-Job bearbeiten',
......
1520 1524
  'No Vendor was found matching the search parameters.' => 'Zu dem Suchbegriff wurde kein Händler gefunden',
1521 1525
  'No acceptance statuses has been created yet.' => 'Es wurde noch kein Abnahmestatus angelegt.',
1522 1526
  'No action defined.'          => 'Keine Aktion definiert.',
1527
  'No articles have been added yet.' => 'Es wurden noch keine Artikel hinzugefügt.',
1523 1528
  'No background job has been created yet.' => 'Es wurden noch keine Hintergrund-Jobs angelegt.',
1524 1529
  'No bank information has been entered in this customer\'s master data entry. You cannot create bank collections unless you enter bank information.' => 'Für diesen Kunden wurden in seinen Stammdaten keine Kontodaten hinterlegt. Solange dies nicht geschehen ist, können Sie keine Überweisungen für den Lieferanten anlegen.',
1525 1530
  'No bank information has been entered in this vendor\'s master data entry. You cannot create bank transfers unless you enter bank information.' => 'Für diesen Lieferanten wurden in seinen Stammdaten keine Kontodaten hinterlegt. Solange dies nicht geschehen ist, können Sie keine Überweisungen für den Lieferanten anlegen.',
......
1938 1943
  'Removal qty'                 => 'Entnahmemenge',
1939 1944
  'Remove'                      => 'Entfernen',
1940 1945
  'Remove Draft'                => 'Entwurf l&ouml;schen',
1946
  'Remove article'              => 'Artikel entfernen',
1941 1947
  'Remove draft when posting'   => 'Entwurf beim Buchen l&ouml;schen',
1942 1948
  'Removed sections and function blocks: #1' => 'Entfernte Abschnitte und Funktionsblöcke: #1',
1943 1949
  'Removed spoolfiles!'         => 'Druckdateien entfernt!',
sql/Pg-upgrade2/requirement_spec_parts.sql
1
-- @tag: requirement_spec_parts
2
-- @description: Artikelzuweisung zu Pflichtenheften
3
-- @depends: release_3_1_0
4
CREATE TABLE requirement_spec_parts (
5
  id                  SERIAL         NOT NULL,
6
  requirement_spec_id INTEGER        NOT NULL,
7
  part_id             INTEGER        NOT NULL,
8
  unit_id             INTEGER        NOT NULL,
9
  qty                 NUMERIC(15, 5) NOT NULL,
10
  description         TEXT           NOT NULL,
11
  position            INTEGER        NOT NULL,
12

  
13
  PRIMARY KEY (id),
14
  FOREIGN KEY (requirement_spec_id) REFERENCES requirement_specs (id),
15
  FOREIGN KEY (part_id)             REFERENCES parts             (id),
16
  FOREIGN KEY (unit_id)             REFERENCES units             (id)
17
);
templates/webpages/requirement_spec/show.html
12 12
  <li id="tab-header-function-block"><a href="#function-blocks-tab">[%- LxERP.t8("Content") %]</a></li>
13 13
  <li id="tab-header-basic-settings"><a href="controller.pl?action=RequirementSpec/ajax_show_basic_settings&id=[% HTML.url(SELF.requirement_spec.id) %]">[%- LxERP.t8("Basic settings") %]</a></li>
14 14
  <li id="tab-header-time-cost-estimate"><a href="controller.pl?action=RequirementSpec/ajax_show_time_and_cost_estimate&id=[% HTML.url(SELF.requirement_spec.id) %]">[%- LxERP.t8("Time and cost estimate") %]</a></li>
15
  <li id="tab-header-additional-parts"><a href="controller.pl?action=RequirementSpecPart/show&requirement_spec_id=[% HTML.url(SELF.requirement_spec.id) %]">[%- LxERP.t8("Additional articles") %]</a></li>
15 16
  [%- UNLESS SELF.requirement_spec.is_template %]
16 17
   <li id="tab-header-versions"><a href="controller.pl?action=RequirementSpecVersion/list&requirement_spec_id=[% HTML.url(SELF.requirement_spec.id) %]">[%- LxERP.t8("Versions") %]</a></li>
17 18
   <li id="tab-header-quotations-orders"><a href="[% SELF.url_for(controller='RequirementSpecOrder', action='list', requirement_spec_id=SELF.requirement_spec.id) %]">[%- LxERP.t8("Quotations and orders") %]</a></li>
templates/webpages/requirement_spec_part/_edit.html
1
[%- USE LxERP -%][%- USE L -%][%- USE P -%]
2
[% SET parts = SELF.requirement_spec.parts_sorted %]
3

  
4
<div id="additional_parts_form_container" class="edit-additional-parts-context-menu">
5

  
6
 <h2>[% LxERP.t8("Edit additional articles") %]</h2>
7

  
8
 <div>
9
  [% LxERP.t8("Add part") %]:
10
  [% P.part_picker('additional_parts_add_part_id', '', style="width: 300px") %]
11
  [% L.button_tag('kivi.requirement_spec.add_additional_part()', LxERP.t8('Add part')) %]
12
 </div>
13

  
14
 <form method="post" id="edit_additional_parts_form">
15
  <div id="edit_additional_parts_list_empty"[% IF parts.size %] style="display: none;"[% END %]>
16
   [% LxERP.t8("No articles have been added yet.") %]
17
  </div>
18

  
19
  <table id="edit_additional_parts_list"[% IF !parts.size %] style="display: none;"[% END %]>
20
   <thead>
21
    <tr class="listheading">
22
     <th></th>
23
     <th>[%- LxERP.t8("Part Number") %]</th>
24
     <th>[%- LxERP.t8("Description") %]</th>
25
     <th>[%- LxERP.t8("Qty") %]</th>
26
    </tr>
27
   </thead>
28

  
29
   <tbody>
30
    [%- FOREACH part = parts %]
31
     [%- INCLUDE 'requirement_spec_part/_part.html' part=part %]
32
    [%- END %]
33
   </tbody>
34
  </table>
35

  
36
   [% L.button_tag("kivi.requirement_spec.standard_additional_parts_ajax_call('save')", LxERP.t8("Save")) %]
37
  </form>
38
</div>
templates/webpages/requirement_spec_part/_part.html
1
[%- USE HTML -%][%- USE L -%][%- USE LxERP -%]
2
<tr class="listrow edit-additional-parts-row-context-menu">
3
 <td align="center">
4
  [% L.hidden_tag("additional_parts[+].part_id", part.part.id) %]
5
  [% L.hidden_tag("additional_parts[].id", part.id) %]
6
  [% L.img_tag(src="image/updown.png", alt=LxERP.t8("reorder item"), class="dragdrop") %]
7
 </td>
8
 <td>[% HTML.escape(part.part.partnumber) %]</td>
9
 <td>[% L.input_tag("additional_parts[].description", part.description, size="30") %]</td>
10
 <td>
11
  [% L.input_tag("additional_parts[].qty_as_number", part.qty_as_number, size="10") %]
12
  [% L.select_tag("additional_parts[].unit_id", part.unit.convertible_units, title_key="name", default=part.unit.id) %]
13
 </td>
14
</tr>
templates/webpages/requirement_spec_part/show.html
1
[%- USE LxERP -%][%- USE L -%][%- USE P -%][%- USE HTML -%]
2
[% SET parts = SELF.requirement_spec.parts_sorted %]
3

  
4
<div id="additional_parts_list_container" class="additional-parts-context-menu"[% IF initially_hidden %] style="display: none;"[% END %]>
5

  
6
 <h2>[% LxERP.t8("Additional articles") %]</h2>
7

  
8
 <div id="additional_parts_list_empty"[% IF parts.size %] style="display: none;"[% END %]>
9
  [% LxERP.t8("No articles have been added yet.") %]
10
 </div>
11

  
12
 <table id="additional_parts_list"[% IF !parts.size %] style="display: none;"[% END %]>
13
  <thead>
14
   <tr class="listheading">
15
    <th>[%- LxERP.t8("Part Number") %]</th>
16
    <th>[%- LxERP.t8("Description") %]</th>
17
    <th>[%- LxERP.t8("Qty") %]</th>
18
   </tr>
19
  </thead>
20

  
21
  <tbody>
22
   [% FOREACH part = parts %]
23
    <tr class="listrow">
24
     <td>[% HTML.escape(part.part.partnumber) %]</td>
25
     <td>[% HTML.escape(part.description) %]</td>
26
     <td valign="right">[% HTML.escape(part.qty_as_number) %] [% HTML.escape(part.unit.name) %]</td>
27
    </tr>
28
   [% END %]
29
  </tbody>
30
 </table>
31
</div>

Auch abrufbar als: Unified diff