Gefertigte Erzeugnisse wieder zerlegen
authorJan Büren <jan@kivitendo.de>
Sat, 15 May 2021 09:45:20 +0000 (11:45 +0200)
committerJan Büren <jan@kivitendo.de>
Sat, 15 May 2021 09:45:20 +0000 (11:45 +0200)
1 Ebene und Prüfung auf transfer_undo Intervall

SL/WH.pm
bin/mozilla/wh.pl
doc/changelog
locale/de/all
locale/en/all
templates/webpages/wh/report_bottom.html [new file with mode: 0644]
templates/webpages/wh/report_top.html [new file with mode: 0644]

index d923d18..1519d6f 100644 (file)
--- a/SL/WH.pm
+++ b/SL/WH.pm
@@ -519,6 +519,7 @@ sub get_warehouse_journal {
      "comment"              => "i1.comment",
      "trans_type"           => "tt.description",
      "trans_id"             => "i1.trans_id",
+     "id"                   => "i1.id",
      "oe_id"                => "COALESCE(i1.oe_id, i2.oe_id)",
      "invoice_id"           => "COALESCE(i1.invoice_id, i2.invoice_id)",
      "date"                 => "i1.shippingdate",
@@ -539,6 +540,7 @@ sub get_warehouse_journal {
      };
 
   $form->{l_classification_id}  = 'Y';
+  $form->{l_id}                 = 'Y';
   $form->{l_part_type}          = 'Y';
   $form->{l_itime}              = 'Y';
   $form->{l_invoice_id} = $form->{l_oe_id} if $form->{l_oe_id};
index 2e812f3..26986c7 100644 (file)
@@ -41,13 +41,17 @@ use SL::User;
 use SL::AM;
 use SL::CVar;
 use SL::CT;
+use SL::Helper::Flash qw(flash_later);
 use SL::IC;
 use SL::WH;
 use SL::OE;
+# use SL::Helper::Inventory qw(produce_assembly);
 use SL::Locale::String qw(t8);
 use SL::ReportGenerator;
+use SL::Presenter::Tag qw(checkbox_tag);
 use SL::Presenter::Part;
 
+use SL::DB::AssemblyInventoryPart;
 use SL::DB::Part;
 
 use Data::Dumper;
@@ -547,6 +551,50 @@ sub remove_parts {
   $main::lxdebug->leave_sub();
 }
 
+sub disassemble_assembly {
+  $main::lxdebug->enter_sub();
+
+  $main::auth->assert('warehouse_management');
+
+  my $form = $main::form;
+
+  croak("No assembly ids") unless scalar @{ $form->{ids}} > 0;
+
+  # fail safe, only allow disassemble in certain intervals
+  my $undo_date  = DateTime->today->subtract(days => $::instance_conf->get_undo_transfer_interval);
+
+  foreach my $assembly_id (@{ $::form->{ids}} )  {
+    my $assembly_parts;
+    $assembly_parts  = SL::DB::Manager::AssemblyInventoryPart->get_all(where => [ inventory_assembly_id => $assembly_id ]);
+    $form->show_generic_error(t8('No relations found for #1', $assembly_id)) unless $assembly_parts;
+    # check first entry for insertdate
+    # everything in one transaction
+    my $db = SL::DB::Inventory->new->db;
+    $db->with_transaction(sub {
+      my ($assembly_entry, $part_entry);
+      foreach my $assembly_part (@{ $assembly_parts }) {
+        die("No valid entry found") unless (ref($assembly_part)  eq 'SL::DB::AssemblyInventoryPart');
+        # fail safe undo date
+        die("Invalid time interval") unless DateTime->compare($assembly_part->itime, $undo_date);
+
+        $assembly_entry //= $assembly_part->assembly;
+        $part_entry       = $assembly_part->part;
+        $assembly_part->delete;
+        $part_entry->delete;
+      }
+      flash_later('info', t8("Disassembly successful for #1",  $assembly_entry->part->partnumber));
+
+      $assembly_entry->delete;
+
+      1;
+
+    }) || die t8('error while disassembling assembly #1 : #2', $assembly_id)  . $db->error . "\n";
+
+  }
+  $main::lxdebug->leave_sub();
+  $form->redirect;
+}
+
 # --------------------------------------------------------------------
 # Journal
 # --------------------------------------------------------------------
@@ -583,13 +631,14 @@ sub generate_journal {
   my %myconfig = %main::myconfig;
   my $locale   = $main::locale;
 
+  setup_wh_journal_list_all_action_bar();
   $form->{title}   = $locale->text("WHJournal");
   $form->{sort}  ||= 'date';
 
   $form->{report_generator_output_format} = 'HTML' if !$form->{report_generator_output_format};
 
   my %filter;
-  my @columns = qw(trans_id date warehouse_from bin_from warehouse_to bin_to partnumber type_and_classific partdescription chargenumber bestbefore trans_type comment qty unit partunit employee oe_id projectnumber);
+  my @columns = qw(ids trans_id date warehouse_from bin_from warehouse_to bin_to partnumber type_and_classific partdescription chargenumber bestbefore trans_type comment qty unit partunit employee oe_id projectnumber);
 
   # filter stuff
   map { $filter{$_} = $form->{$_} if ($form->{$_}) } qw(warehouse_id bin_id classification_id partnumber description chargenumber bestbefore transtype_id transtype_ids comment projectnumber);
@@ -634,6 +683,7 @@ sub generate_journal {
   push @hidden_variables, qw(classification_id);
 
   my %column_defs = (
+    'ids'             => { raw_header_data => checkbox_tag("", id => "check_all", checkall  => "[data-checkall=1]") },
     'date'            => { 'text' => $locale->text('Date'), },
     'trans_id'        => { 'text' => $locale->text('Trans Id'), },
     'trans_type'      => { 'text' => $locale->text('Trans Type'), },
@@ -674,6 +724,7 @@ sub generate_journal {
   $column_defs{partunit}->{visible} = 1;
   $column_defs{type_and_classific}->{visible} = 1;
   $column_defs{type_and_classific}->{link} ='';
+  $column_defs{ids}->{visible} = 1;
 
   $report->set_columns(%column_defs);
   $report->set_column_order(@columns);
@@ -706,8 +757,8 @@ sub generate_journal {
     $entry->{type_and_classific} = SL::Presenter::Part::type_abbreviation($entry->{part_type}) .
                                    SL::Presenter::Part::classification_abbreviation($entry->{classification_id});
     $entry->{qty}        = $form->format_amount(\%myconfig, $entry->{qty});
+    $entry->{assembled} = $entry->{trans_type} eq 'assembled' ? 1 : '';
     $entry->{trans_type} = $locale->text($entry->{trans_type});
-
     my $row = { };
 
     foreach my $column (@columns) {
@@ -717,8 +768,9 @@ sub generate_journal {
       };
     }
 
-    $row->{trans_type}->{raw_data} = $entry->{trans_type};
+    $row->{ids}->{raw_data} = checkbox_tag("ids[]", value => $entry->{id}, "data-checkall" => 1) if $entry->{assembled};
 
+    $row->{trans_type}->{raw_data} = $entry->{trans_type};
     if ($form->{l_oe_id}) {
       $row->{oe_id}->{data} = '';
       my $info              = $entry->{oe_id_info};
@@ -735,12 +787,17 @@ sub generate_journal {
     $idx++;
   }
 
+
+    $report->set_options(
+      raw_top_info_text     => $form->parse_html_template('wh/report_top'),
+      raw_bottom_info_text  => $form->parse_html_template('wh/report_bottom', { callback => $href }),
+    );
   if ( ! $allrows ) {
       $pages->{max}  = SL::DB::Helper::Paginated::ceil($form->{maxrows}, $pages->{per_page}) || 1;
       $pages->{page} = $page < 1 ? 1: $page > $pages->{max} ? $pages->{max}: $page;
       $pages->{common} = [ grep { $_->{visible} } @{ SL::DB::Helper::Paginated::make_common_pages($pages->{page}, $pages->{max}) } ];
 
-      $report->set_options('raw_bottom_info_text' => $form->parse_html_template('common/paginate',
+      $report->set_options('raw_bottom_info_text' =>  $form->parse_html_template('wh/report_bottom', { callback => $href }) . $form->parse_html_template('common/paginate',
                                                             { 'pages' => $pages , 'base_url' => $href.'&sort='.$form->{sort}.'&order='.$form->{order}}) );
   }
   $report->generate_with_headers();
@@ -1190,6 +1247,22 @@ sub setup_wh_journal_action_bar {
     );
   }
 }
+sub setup_wh_journal_list_all_action_bar {
+  my ($action) = @_;
+  for my $bar ($::request->layout->get('actionbar')) {
+    $bar->add(
+      combobox => [
+        action => [ t8('Actions') ],
+        action => [
+          t8('Disassemble Assembly'),
+            submit => [ '#form', { action => 'disassemble_assembly' } ],
+            checks => [ [ 'kivi.check_if_entries_selected', '[name="ids[]"]' ] ],
+          ],
+        ],
+    );
+  }
+}
+
 
 1;
 
index e47f57e..4d530eb 100644 (file)
@@ -36,6 +36,8 @@ Mittelgroße neue Features:
      Mahnung
 
 Kleinere neue Features und Detailverbesserungen:
+  - Gefertigte Erzeugnisse können innerhalb des Zurücklagerungszeitraums
+    wieder zerlegt werden. Die Aktion befindet sich im Lagerbuchungsbericht
   - E-Mail-Versand: Neben dem Freitext CC-Feld kann jetzt auch ein
     kivitendo Benutzer mittels einer Auswahlliste in CC gesetzt werden
   - Falls der Mandant zu jeder Buchung einen Beleg hinzufügen möchte,
index aa18fb0..fabf8f1 100755 (executable)
@@ -519,6 +519,7 @@ $self->{texts} = {
   'CANCELED'                    => 'Storniert',
   'CB Transaction'              => 'SB-Buchung',
   'CB Transactions'             => 'SB-Buchungen',
+  'CC to Employee'              => 'CC an Mitarbeiter',
   'CN'                          => 'Kd-Nr.',
   'CR'                          => 'H',
   'CSS style for pictures'      => 'CSS Style für Bilder',
@@ -1063,6 +1064,8 @@ $self->{texts} = {
   'Direct debit revoked'        => 'Die Einzugsermächtigung wird widerrufen',
   'Directory'                   => 'Verzeichnis',
   'Disabled Price Sources'      => 'Deaktivierte Preisquellen',
+  'Disassemble Assembly'        => 'Erzeugnis zerlegen',
+  'Disassembly successful for #1' => 'Erzeugnis #1 erfolgreich zerlegt',
   'Discard duplicate entries in CSV file' => 'Doppelte Einträge in CSV-Datei verwerfen',
   'Discard entries with duplicates in database or CSV file' => 'Einträge aus CSV-Datei verwerfen, die es bereits in der Datenbank oder der CSV-Datei gibt',
   'Discount'                    => 'Rabatt',
@@ -1764,6 +1767,8 @@ $self->{texts} = {
   'Introduction of clients'     => 'Einführung von Mandanten',
   'Inv. Duedate'                => 'Rg. Fälligkeit',
   'Invalid'                     => 'Ungültig',
+  'Invalid assembly'            => 'Ungültiges Erzeugnis',
+  'Invalid bin'                 => '',
   'Invalid charge number: #1'   => 'Ungültige Chargennummer: #1',
   'Invalid combination of ledger account number length. Mismatch length of #1 with length of #2. Please check your account settings. ' => 'Ungültige Kombination der Nummernkreislänge der Sachkonten. Kann nicht eine Länge von #1 und eine Länge von #2 verarbeiten. Bitte entsprechend die Konteneinstellungen überprüfen.',
   'Invalid duration format'     => 'Falsches Format für Zeitdauer',
@@ -2145,6 +2150,7 @@ $self->{texts} = {
   'No profit and loss carried forward chart configured!' => 'Kein Verlustvortragskonto konfiguriert!',
   'No profit carried forward chart configured!' => 'Kein Gewinnvortragskonto konfiguriert!',
   'No quotations or orders have been created yet.' => 'Es wurden noch keine Angebote oder Aufträge angelegt.',
+  'No relations found for #1'   => 'Keine Relation für #1 gefunden',
   'No report with id #1'        => 'Es gibt keinen Report mit der Id #1',
   'No requirement spec templates have been created yet.' => 'Es wurden noch keine Pflichtenheftvorlagen angelegt.',
   'No results.'                 => 'Keine Artikel',
@@ -4248,6 +4254,7 @@ $self->{texts} = {
   'ea'                          => 'St.',
   'emailed to'                  => 'gemailt an',
   'empty'                       => 'leer',
+  'error while disassembling assembly #1 : #2' => 'Fehler beim Zerlegen von Erzeugnis #1: #2',
   'error while paying invoice #1 : ' => 'Fehler beim Bezahlen von Rechnung #1 : ',
   'error while unlinking payment #1 : ' => 'Fehler beim Zurücksetzen von Zahlung #1:',
   'every third month'           => 'vierteljährlich',
index 86c8695..cf87738 100644 (file)
@@ -519,6 +519,7 @@ $self->{texts} = {
   'CANCELED'                    => '',
   'CB Transaction'              => '',
   'CB Transactions'             => '',
+  'CC to Employee'              => '',
   'CN'                          => '',
   'CR'                          => '',
   'CSS style for pictures'      => '',
@@ -1063,6 +1064,8 @@ $self->{texts} = {
   'Direct debit revoked'        => '',
   'Directory'                   => '',
   'Disabled Price Sources'      => '',
+  'Disassemble Assembly'        => '',
+  'Disassembly successful for #1' => '',
   'Discard duplicate entries in CSV file' => '',
   'Discard entries with duplicates in database or CSV file' => '',
   'Discount'                    => '',
@@ -1764,6 +1767,8 @@ $self->{texts} = {
   'Introduction of clients'     => '',
   'Inv. Duedate'                => '',
   'Invalid'                     => '',
+  'Invalid assembly'            => '',
+  'Invalid bin'                 => '',
   'Invalid charge number: #1'   => '',
   'Invalid combination of ledger account number length. Mismatch length of #1 with length of #2. Please check your account settings. ' => '',
   'Invalid duration format'     => '',
@@ -2145,6 +2150,7 @@ $self->{texts} = {
   'No profit and loss carried forward chart configured!' => '',
   'No profit carried forward chart configured!' => '',
   'No quotations or orders have been created yet.' => '',
+  'No relations found for #1'   => '',
   'No report with id #1'        => '',
   'No requirement spec templates have been created yet.' => '',
   'No results.'                 => '',
@@ -4247,6 +4253,7 @@ $self->{texts} = {
   'ea'                          => '',
   'emailed to'                  => '',
   'empty'                       => '',
+  'error while disassembling assembly #1 : #2' => '',
   'error while paying invoice #1 : ' => '',
   'error while unlinking payment #1 : ' => '',
   'every third month'           => '',
diff --git a/templates/webpages/wh/report_bottom.html b/templates/webpages/wh/report_bottom.html
new file mode 100644 (file)
index 0000000..106943e
--- /dev/null
@@ -0,0 +1,3 @@
+[%- USE HTML %]
+ <input type="hidden" name="callback" value="[% HTML.escape(callback) %]">
+</form>
diff --git a/templates/webpages/wh/report_top.html b/templates/webpages/wh/report_top.html
new file mode 100644 (file)
index 0000000..6198bd9
--- /dev/null
@@ -0,0 +1 @@
+<form method="post" action="wh.pl" id="form">