Pflichtenheft-Angebot/Auftrag: Liste in Tab anzeigen
authorMoritz Bunkus <m.bunkus@linet-services.de>
Tue, 9 Jul 2013 09:59:11 +0000 (11:59 +0200)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Tue, 1 Apr 2014 11:03:25 +0000 (13:03 +0200)
SL/Controller/RequirementSpecOrder.pm [new file with mode: 0644]
SL/DB/RequirementSpec.pm
js/locale/de.js
js/requirement_spec.js
locale/de/all
templates/webpages/requirement_spec/show.html
templates/webpages/requirement_spec_order/list.html [new file with mode: 0644]

diff --git a/SL/Controller/RequirementSpecOrder.pm b/SL/Controller/RequirementSpecOrder.pm
new file mode 100644 (file)
index 0000000..67b780f
--- /dev/null
@@ -0,0 +1,61 @@
+package SL::Controller::RequirementSpecOrder;
+
+use strict;
+use utf8;
+
+use parent qw(SL::Controller::Base);
+
+use SL::ClientJS;
+use SL::DB::RequirementSpec;
+use SL::DB::RequirementSpecOrder;
+use SL::Helper::Flash;
+use SL::Locale::String;
+
+use Rose::Object::MakeMethods::Generic
+(
+  'scalar --get_set_init' => [ qw(requirement_spec js) ],
+);
+
+__PACKAGE__->run_before('setup');
+
+#
+# actions
+#
+
+
+sub action_list {
+  my ($self) = @_;
+
+  $::lxdebug->dump(0, "hmm", $self->requirement_spec->sections_sorted);
+  $self->render('requirement_spec_order/list', { layout => 0 });
+}
+
+#
+# filters
+#
+
+sub setup {
+  my ($self) = @_;
+
+  $::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);
+
+  return 1;
+}
+
+sub init_requirement_spec {
+  my ($self) = @_;
+  $self->requirement_spec(SL::DB::RequirementSpec->new(id => $::form->{requirement_spec_id})->load) if $::form->{requirement_spec_id};
+}
+
+sub init_js {
+  my ($self) = @_;
+  $self->js(SL::ClientJS->new);
+}
+
+#
+# helpers
+#
+
+1;
index cd1c837..72651a3 100644 (file)
@@ -27,6 +27,11 @@ __PACKAGE__->meta->add_relationship(
     class          => 'SL::DB::RequirementSpec',
     column_map     => { id => 'working_copy_id' },
   },
+  orders           => {
+    type           => 'one to many',
+    class          => 'SL::DB::RequirementSpecOrder',
+    column_map     => { id => 'requirement_spec_id' },
+  },
 );
 
 __PACKAGE__->meta->initialize;
@@ -71,6 +76,13 @@ sub sections_sorted {
 
 sub sections { &sections_sorted; }
 
+sub orders_sorted {
+  my ($self, %params) = _hashify(1, @_);
+  my $by              = $params{by} || 'itime';
+
+  return [ sort { $a->$by cmp $b->$by } @{ $self->orders } ];
+}
+
 sub displayable_name {
   my ($self) = @_;
 
index c38b793..6e2aa8e 100644 (file)
@@ -9,9 +9,11 @@ namespace("kivi").setupLocale({
 "Copy requirement spec":"Pflichtenheft kopieren",
 "Copy template":"Vorlage kopieren",
 "Create PDF":"PDF erzeugen",
+"Create new qutoation/order":"",
 "Create new version":"Neue Version anlegen",
 "Database Connection Test":"Test der Datenbankverbindung",
 "Delete":"Löschen",
+"Delete quotation/order":"",
 "Delete requirement spec":"Pflichtenheft löschen",
 "Delete template":"Vorlage löschen",
 "Delete text block":"Textblock löschen",
@@ -19,10 +21,12 @@ namespace("kivi").setupLocale({
 "Do you really want to revert to this version?":"Wollen Sie wirklich auf diese Version zurücksetzen?",
 "Do you want to set the account number \"#1\" to \"#2\" and the name \"#3\" to \"#4\"?":"Soll die Kontonummer \"#1\" zu \"#2\" und den Name \"#3\" zu \"#4\" geändert werden?",
 "Edit":"Bearbeiten",
+"Edit article/section assignments":"",
 "Edit text block":"Textblock bearbeiten",
 "Enter longdescription":"Langtext eingeben",
 "Function block actions":"Funktionsblockaktionen",
 "Map":"Karte",
+"Orders/Quotations actions":"",
 "Part picker":"Artikelauswahl",
 "Paste":"Einfügen",
 "Paste template":"Vorlage einfügen",
@@ -39,5 +43,6 @@ 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 quotation/order":"",
 "Version actions":"Aktionen für Versionen"
 });
index effcf3d..9b68bc7 100644 (file)
@@ -317,6 +317,36 @@ ns.standard_time_cost_estimate_ajax_call = function(key, opt) {
   return true;
 };
 
+// -------------------------------------------------------------------------
+// --------------------------- quotations/orders ---------------------------
+// -------------------------------------------------------------------------
+
+ns.find_quotation_order_id = function(clicked_elt) {
+  return $(clicked_elt).find('>[name=order_id]').val();
+};
+
+ns.standard_quotation_order_ajax_call = function(key, opt, other_data) {
+  var data = {
+    action:              "RequirementSpecOrder/" + key,
+    requirement_spec_id: $('#requirement_spec_id').val(),
+    id:                  ns.find_quotation_order_id(opt.$trigger)
+  };
+
+  // console.log("I would normally POST the following now:");
+  // console.log(data);
+  $.post("controller.pl", $.extend(data, other_data || {}), kivi.eval_json_result);
+
+  return true;
+};
+
+ns.disable_edit_quotation_order_commands = function(key, opt) {
+  return ns.find_quotation_order_id(opt.$trigger) == undefined;
+};
+
+ns.disable_create_quotation_order_commands = function(key, opt) {
+  return !$('#quotations_and_orders_sections');
+};
+
 // -------------------------------------------------------------------------
 // ---------------------------- general actions ----------------------------
 // -------------------------------------------------------------------------
@@ -474,6 +504,19 @@ ns.create_context_menus = function(is_template) {
     }, general_actions)
   });
 
+  $.contextMenu({
+    selector: '.quotations-and-orders-context-menu,.quotations-and-orders-order-context-menu',
+    items:    $.extend({
+        heading:            { name: kivi.t8('Orders/Quotations actions'), className: 'context-menu-heading' }
+      , edit:               { name: kivi.t8('Edit article/section assignments'), icon: "edit",   callback: ns.standard_quotation_order_ajax_call }
+      , sep1:               "---------"
+      , new:                { name: kivi.t8('Create new qutoation/order'),       icon: "add",    callback: ns.standard_quotation_order_ajax_call, disabled: ns.disable_create_quotation_order_commands}
+      , update:             { name: kivi.t8('Update quotation/order'),           icon: "update", callback: ns.standard_quotation_order_ajax_call, disabled: ns.disable_edit_quotation_order_commands }
+      , sep2:               "---------"
+      , delete:             { name: kivi.t8('Delete quotation/order'),           icon: "delete", callback: ns.ask_delete_quotation_order,         disabled: ns.disable_edit_quotation_order_commands }
+    }, general_actions)
+  });
+
   $.contextMenu({
     selector: '#content',
     items:    general_actions
index a6ea88c..b6528d7 100755 (executable)
@@ -243,6 +243,7 @@ $self->{texts} = {
   'Are you sure you want to remove the marked entries from the queue?' => 'Sind Sie sicher, dass die markierten Einträge von der Warteschlange gelöscht werden sollen?',
   'Are you sure you want to update the prices' => 'Sind Sie sicher, dass Sie die Preise aktualisieren wollen?',
   'Are you sure?'               => 'Sind Sie sicher?',
+  'Article'                     => '',
   'Article Code'                => 'Artikelkürzel',
   'Article Code missing!'       => 'Artikelkürzel fehlt',
   'Article type (see below)'    => 'Artikeltyp (siehe unten)',
@@ -254,6 +255,7 @@ $self->{texts} = {
   'Assembly Number missing!'    => 'Erzeugnisnummer fehlt!',
   'Asset'                       => 'Aktiva/Mittelverwendung',
   'Assets'                      => 'Aktiva',
+  'Assignment of articles to sections' => '',
   'Assistant for general ledger corrections' => 'Assistent für die Korrektur von Hauptbucheinträgen',
   'Assume Tax Consultant Data in Tax Computation?' => 'Beraterdaten in UStVA übernehmen?',
   'At least'                    => 'Mindestens',
@@ -588,6 +590,7 @@ $self->{texts} = {
   'Create new department'       => 'Neue Abteilung erfassen',
   'Create new payment term'     => 'Neue Zahlungsbedingung anlegen',
   'Create new project type'     => 'Neuen Projekttypen anlegen',
+  'Create new qutoation/order'  => '',
   'Create new templates from master templates' => 'Neue Druckvorlagen aus Vorlagensatz erstellen',
   'Create new version'          => 'Neue Version anlegen',
   'Create one from the context menu by right-clicking on this text.' => 'Erstellen Sie einen aus dem Kontextmenü, indem Sie auf diesen Text rechtsklicken.',
@@ -716,7 +719,7 @@ $self->{texts} = {
   'Default client'              => 'Standardmandant',
   'Default currency'            => 'Standardwährung',
   'Default currency missing!'   => 'Standardwährung fehlt!',
-  'Default hourly rate for new customers' => '',
+  'Default hourly rate for new customers' => 'Standard-Stundensatz für neue Kunden',
   'Default output medium'       => 'Standardausgabekanal',
   'Default printer'             => 'Standarddrucker',
   'Default template format'     => 'Standardvorlagenformat',
@@ -730,6 +733,7 @@ $self->{texts} = {
   'Delete drafts'               => 'Entwürfe löschen',
   'Delete links'                => 'Verknüpfungen löschen',
   'Delete profile'              => 'Profil löschen',
+  'Delete quotation/order'      => '',
   'Delete requirement spec'     => 'Pflichtenheft löschen',
   'Delete template'             => 'Vorlage löschen',
   'Delete text block'           => 'Textblock löschen',
@@ -895,6 +899,7 @@ $self->{texts} = {
   'Edit Vendor Invoice'         => 'Einkaufsrechnung bearbeiten',
   'Edit Warehouse'              => 'Lager bearbeiten',
   'Edit acceptance status'      => 'Abnahmestatus bearbeiten',
+  'Edit article/section assignments' => '',
   'Edit background job'         => 'Hintergrund-Job bearbeiten',
   'Edit bank account'           => 'Bankkonto bearbeiten',
   'Edit business'               => 'Kunden-/Lieferantentyp bearbeiten',
@@ -1481,6 +1486,7 @@ $self->{texts} = {
   'No printers have been created yet.' => 'Es wurden noch keine Drucker angelegt.',
   'No problems were recognized.' => 'Es wurden keine Probleme gefunden.',
   'No project type has been created yet.' => 'Es wurden noch keine Projekttypen angelegt.',
+  'No quotations or orders have been created yet.' => '',
   'No report with id #1'        => 'Es gibt keinen Report mit der Id #1',
   'No requirement spec statuses has been created yet.' => 'Es wurden noch keine Pflichtenheftstatus angelegt.',
   'No requirement spec templates have been created yet.' => 'Es wurden noch keine Pflichtenheftvorlangen angelegt.',
@@ -1488,6 +1494,7 @@ $self->{texts} = {
   'No risks level has been created yet.' => 'Es wurden noch keine Risikograde angelegt.',
   'No sections created yet'     => 'Keine Abschnitte erstellt',
   'No sections have been created so far.' => 'Bisher wurden noch keine Abschnitte angelegt.',
+  'No sections have been created yet.' => '',
   'No shipto selected to delete' => 'Keine Lieferadresse zum Löschen ausgewählt',
   'No summary account'          => 'Kein Sammelkonto',
   'No text blocks have been created for this position.' => 'Für diese Position wurden noch keine Textblöcke angelegt.',
@@ -1574,6 +1581,7 @@ $self->{texts} = {
   'Ordered'                     => 'Von Kunden bestellt',
   'Orders'                      => 'Aufträge',
   'Orders / Delivery Orders deleteable' => 'Aufträge / Lieferscheine löschbar',
+  'Orders/Quotations actions'   => '',
   'Orientation'                 => 'Seitenformat',
   'Orphaned'                    => 'Nie benutzt',
   'Orphaned currencies'         => 'Verwaiste Währungen',
@@ -1807,6 +1815,7 @@ $self->{texts} = {
   'Quotation Number missing!'   => 'Angebotsnummer fehlt!',
   'Quotation deleted!'          => 'Angebot wurde gelöscht.',
   'Quotations'                  => 'Angebote',
+  'Quotations and orders'       => '',
   'Quote character'             => 'Anführungszeichen-Symbol',
   'Quote chararacter'           => 'Anf&uuml;hrungszeichen',
   'Quoted'                      => 'Angeboten',
@@ -1827,6 +1836,7 @@ $self->{texts} = {
   'Reconciliation'              => 'Kontenabgleich',
   'Record Vendor Invoice'       => 'Einkaufsrechnung erfassen',
   'Record in'                   => 'Buchen auf',
+  'Record number'               => '',
   'Recorded Tax'                => 'Gespeicherte Steuern',
   'Recorded taxkey'             => 'Gespeicherter Steuerschlüssel',
   'Reference'                   => 'Referenz',
@@ -1875,6 +1885,7 @@ $self->{texts} = {
   'Requirement Spec Templates'  => 'Pflichtenheftvorlagen',
   'Requirement Spec Type'       => 'Pflichtenhefttyp',
   'Requirement Spec Types'      => 'Pflichtenhefttypen',
+  'Requirement Spec Version'    => '',
   'Requirement Specs'           => 'Pflichtenhefte',
   'Requirement spec actions'    => 'Pflichtenheftaktionen',
   'Requirement spec function block #1 with #2 sub function blocks; description: "#3"' => 'Pflichtenheft-Funktionsblock #1 mit #2 Unterfunktionsblöcken; Beschreibung: "#3"',
@@ -1932,6 +1943,7 @@ $self->{texts} = {
   'Sales margin'                => 'Marge',
   'Sales margin %'              => 'Marge prozentual',
   'Sales net amount'            => 'VK-Betrag',
+  'Sales order'                 => '',
   'Sales price'                 => 'VK-Preis',
   'Sales price total'           => 'VK-Betrag',
   'Sales quotation'             => 'Angebot',
@@ -2537,6 +2549,7 @@ $self->{texts} = {
   'Transaction'                 => 'Buchung',
   'Transaction %d cancelled.'   => 'Buchung %d erfolgreich storniert.',
   'Transaction Date missing!'   => 'Buchungsdatum fehlt!',
+  'Transaction Description'     => '',
   'Transaction ID missing.'     => 'Die Buchungs-ID fehlt.',
   'Transaction deleted!'        => 'Buchung gelöscht!',
   'Transaction description'     => 'Vorgangsbezeichnung',
@@ -2602,6 +2615,7 @@ $self->{texts} = {
   'Update prices'               => 'Preise aktualisieren',
   'Update prices of existing entries' => 'Preise von vorhandenen Artikeln aktualisieren',
   'Update properties of existing entries' => 'Eigenschaften von existierenden Einträgen aktualisieren',
+  'Update quotation/order'      => '',
   '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',
@@ -2868,6 +2882,7 @@ $self->{texts} = {
   'new Window'                  => 'neues Fenster',
   'next'                        => 'vor',
   'no'                          => 'nein',
+  'no article assigned yet'     => '',
   'no bestbefore'               => 'keine Mindesthaltbarkeit',
   'no chargenumber'             => 'keine Chargennummer',
   'none (pricegroup)'           => 'keine',
@@ -2965,6 +2980,7 @@ $self->{texts} = {
   'vendor_list'                 => 'lieferantenliste',
   'warehouse_journal_list'      => 'lagerbuchungsliste',
   'warehouse_report_list'       => 'lagerbestandsliste',
+  'working copy'                => '',
   'wrongformat'                 => 'Falsches Format',
   'yearly'                      => 'jährlich',
   'yes'                         => 'ja',
index 072c625..f532118 100644 (file)
@@ -13,6 +13,7 @@
   <li><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>
   [%- UNLESS SELF.requirement_spec.is_template %]
    <li><a href="controller.pl?action=RequirementSpecVersion/list&requirement_spec_id=[% HTML.url(SELF.requirement_spec.id) %]">[%- LxERP.t8("Versions") %]</a></li>
+   <li><a href="[% SELF.url_for(controller='RequirementSpecOrder', action='list', requirement_spec_id=SELF.requirement_spec.id) %]">[%- LxERP.t8("Quotations and orders") %]</a></li>
   [%- END %]
  </ul>
 
diff --git a/templates/webpages/requirement_spec_order/list.html b/templates/webpages/requirement_spec_order/list.html
new file mode 100644 (file)
index 0000000..fb86baf
--- /dev/null
@@ -0,0 +1,77 @@
+[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE P -%]
+<div id="quotations_and_orders" class="quotations-and-orders-context-menu">
+ <h2>[% LxERP.t8("Assignment of articles to sections") %]</h2>
+ [% SET sections = SELF.requirement_spec.sections_sorted %]
+ [% IF !sections.size %]
+ <div>
+  [% LxERP.t8("No sections have been created yet.") %]
+ </div>
+ [% ELSE %]
+ <table id="quotations_and_orders_sections" style="width: 100%">
+  <thead>
+   <tr class="listheading">
+    <th>[% LxERP.t8("Number") %]</th>
+    <th>[% LxERP.t8("Title") %]</th>
+    <th>[% LxERP.t8("Description") %]</th>
+    <th>[% LxERP.t8("Article") %]</th>
+   </tr>
+  </thead>
+
+  <tbody>
+   [% FOREACH section = sections %]
+    <tr class="listrow">
+     <td>[% HTML.escape(section.fb_number) %]</td>
+     <td>[% HTML.escape(section.title) %]</td>
+     <td>[% HTML.escape(P.truncate(section.description)) %]</td>
+     <td>
+      [% IF section.order_part %]
+       [% HTML.escape(section.order_part.partnumber) %] [% HTML.escape(section.order_part.description) %]
+      [% ELSE %]
+       [% LxERP.t8("no article assigned yet") %]
+      [% END %]
+     </td>
+    </tr>
+   [% END %]
+  </tbody>
+ </table>
+ [% END %]
+
+ <h2>[% LxERP.t8("Quotations and orders") %]</h2>
+
+ [% SET orders = SELF.requirement_spec.orders_sorted %]
+ [% IF !orders.size %]
+  <div>[% LxERP.t8("No quotations or orders have been created yet.") %]</div>
+ [% ELSE %]
+
+  <table style="width:100%">
+   <thead>
+    <tr class="listheading">
+     <th>[% LxERP.t8("Type") %]</th>
+     <th>[% LxERP.t8("Requirement Spec Version") %]</th>
+     <th>[% LxERP.t8("Record number") %]</th>
+     <th>[% LxERP.t8("Transaction Description") %]</th>
+     <th>[% LxERP.t8("Date") %]</th>
+    </tr>
+   </thead>
+
+   <tbody>
+    [% FOREACH rs_order = orders %]
+    <tr class="listrow quotations-and-orders-order-context-menu">
+     [% L.hidden_tag('order_id', rs_order.id, no_id=1) %]
+     <td>[% rs_order.order.type == 'sales_quotation' ? LxERP.t8('Sales quotation') : LxERP.t8('Sales order') %]</td>
+     <td>
+      [% IF rs_order.version %]
+       [% HTML.escape(rs_order.version.version_number) %]
+      [% ELSE %]
+       [% LxERP.t8("working copy") %]
+      [% END %]
+     </td>
+     <td>[% HTML.escape(rs_order.order.quotation ? rs_order.order.quonumber : rs_order.order.ordnumber) %]</td>
+     <td>[% HTML.escape(rs_order.order.transaction_description) %]</td>
+     <td>[% rs_order.itime.to_kivitendo(precision='day') %]</td>
+    </tr>
+    [%- END %]
+   </tbody>
+  </table>
+ [% END %]
+</div>