Dieses neue Attribut an Artikelklassifizierung erlaubt in Aufträgen und Rechnungen
bestimmte Artikel extra auszuweisen.
Dazu werden diese als extra Variable der Dokumentengeneierung zur Verfügung gestellt.
Siehe neue Dokumentation Kapitel 3.7
Hintergrund:
Preise von Artikeln wie "Verpackung" oder "Transport" müssen
oftmals separat ausgewiesen werden, genauso wie der reine Warenwert
$::form->{part_classification}->{used_for_purchase} = 0 if ! $::form->{part_classification}->{used_for_purchase};
$::form->{part_classification}->{used_for_sale} = 0 if ! $::form->{part_classification}->{used_for_sale};
+ $::form->{part_classification}->{report_separate} = 0 if ! $::form->{part_classification}->{report_separate};
my $params = delete($::form->{part_classification}) || { };
__PACKAGE__->make_manager_methods;
-#
-# get the one/two character shortcut of the parts classification
-#
-sub get_abbreviation {
- my ($class,$id) = @_;
- my $obj = $class->get_first(query => [ id => $id ]);
- return '' unless $obj;
- return $obj->abbreviation?$obj->abbreviation:'';
-}
-
1;
SL::DB::Manager::PartClassification
-
-=head1 SYNOPSIS
-
-This class has wrapper methodes to get the shortcuts
-
-=head1 METHODS
-
-=head2 get_abbreviation
-
- $class->get_abbreviation($classification_id);
-
-get the one/two character shortcut of the parts classification
-
-=head2 get_separate_abbreviation
-
- $class->get_separate_abbreviation($classification_id);
-
-get the one/two character shortcut of the parts classification if it is a separate article
-
-=head1 AUTHOR
-
-Martin Helmling E<lt>martin.helmling@opendynamic.deE<gt>
-
=cut
abbreviation => { type => 'text' },
description => { type => 'text' },
id => { type => 'serial', not_null => 1 },
+ report_separate => { type => 'boolean', default => 'false' },
used_for_purchase => { type => 'boolean', default => 'true' },
used_for_sale => { type => 'boolean', default => 'true' },
);
The primary attributes are the rule
of the article as "used_for_sales" or "used_for_purchase".
+Another attribute is "report_separate". This attribute may be used for some additional costs like
+transport, packaging. These article are reported separate in the list of an invoice if
+the print template is using the variables <%separate_XXX_subtotal%> and XXX is the shortcut of the parts classification.
+The variables <%non_separate_subtotal%> has the sum of all other parts of an invoice.
+(See also LaTeX Documentation).
+
Additional other attributes may follow
To see this attributes in a short way there are shortcuts of one (or two characters, if needed for compare )
my $type_abbr = $::request->presenter->type_abbreviation($prt->part_type);
push @{ $template_arrays{part_type} }, $type_abbr;
push @{ $template_arrays{type_and_classific}}, $type_abbr.$::request->presenter->classification_abbreviation($prt->classification_id);
+ push @{ $template_arrays{separate} }, $::request->presenter->separate_abbreviation($prt->classification_id);
}
$main::lxdebug->leave_sub();
# so that they can be sorted in later
my %prepared_template_arrays = IC->prepare_parts_for_printing(myconfig => $myconfig, form => $form);
my @prepared_arrays = keys %prepared_template_arrays;
+ my @separate_totals = qw(non_separate_subtotal);
my $ic_cvar_configs = CVar->get_configs(module => 'IC');
my $project_cvar_configs = CVar->get_configs(module => 'Projects');
push @{ $form->{TEMPLATE_ARRAYS}->{discount_nofmt} }, ($discount != 0) ? $discount * -1 : '';
push @{ $form->{TEMPLATE_ARRAYS}->{p_discount} }, $form->{"discount_$i"};
+ if ( $prepared_template_arrays{separate}[$i - 1] ) {
+ my $pabbr = $prepared_template_arrays{separate}[$i - 1];
+ if ( ! $form->{"separate_${pabbr}_subtotal"} ) {
+ push @separate_totals , "separate_${pabbr}_subtotal";
+ $form->{"separate_${pabbr}_subtotal"} = 0;
+ }
+ $form->{"separate_${pabbr}_subtotal"} += $linetotal;
+ } else {
+ $form->{non_separate_subtotal} += $linetotal;
+ }
+
$form->{total} += $linetotal;
$form->{nodiscount_total} += $nodiscount_linetotal;
$form->{discount_total} += $discount;
$form->{delivery_term}->description_long($form->{delivery_term}->translated_attribute('description_long', $form->{language_id})) if $form->{delivery_term} && $form->{language_id};
$form->{username} = $myconfig->{name};
+ $form->{$_} = $form->format_amount($myconfig, $form->{$_}, 2) for @separate_totals;
$main::lxdebug->leave_sub();
}
# so that they can be sorted in later
my %prepared_template_arrays = IC->prepare_parts_for_printing(myconfig => $myconfig, form => $form);
my @prepared_arrays = keys %prepared_template_arrays;
+ my @separate_totals = qw(non_separate_subtotal);
$form->{TEMPLATE_ARRAYS} = { };
push @{ $form->{TEMPLATE_ARRAYS}->{discount_nofmt} }, ($discount != 0) ? $discount * -1 : '';
push @{ $form->{TEMPLATE_ARRAYS}->{p_discount} }, $form->{"discount_$i"};
+ if ( $prepared_template_arrays{separate}[$i - 1] ) {
+ my $pabbr = $prepared_template_arrays{separate}[$i - 1];
+ if ( ! $form->{"separate_${pabbr}_subtotal"} ) {
+ push @separate_totals , "separate_${pabbr}_subtotal";
+ $form->{"separate_${pabbr}_subtotal"} = 0;
+ }
+ $form->{"separate_${pabbr}_subtotal"} += $linetotal;
+ } else {
+ $form->{non_separate_subtotal} += $linetotal;
+ }
+
$form->{ordtotal} += $linetotal;
$form->{nodiscount_total} += $nodiscount_linetotal;
$form->{discount_total} += $discount;
$form->{delivery_term}->description_long($form->{delivery_term}->translated_attribute('description_long', $form->{language_id})) if $form->{delivery_term} && $form->{language_id};
$form->{order} = SL::DB::Manager::Order->find_by(id => $form->{id}) if $form->{id};
+ $form->{$_} = $form->format_amount($myconfig, $form->{$_}, 2) for @separate_totals;
$main::lxdebug->leave_sub();
}
#
sub type_abbreviation {
my ($self, $part_type) = @_;
- $main::lxdebug->message(LXDebug->DEBUG2(),"parttype=".$part_type);
return $::locale->text('Assembly (typeabbreviation)') if $part_type eq 'assembly';
return $::locale->text('Part (typeabbreviation)') if $part_type eq 'part';
return $::locale->text('Assortment (typeabbreviation)') if $part_type eq 'assortment';
$obj && $obj->abbreviation ? t8($obj->abbreviation) : '';
}
+#
+# shortcut for article type
+#
+sub separate_abbreviation {
+ my ($self, $id) = @_;
+ SL::DB::Manager::PartClassification->cache_all();
+ my $obj = SL::DB::PartClassification->load_cached($id);
+ $obj && $obj->abbreviation && $obj->report_separate ? t8($obj->abbreviation) : '';
+}
+
#
# generate selection tag
#
=over 2
+=item C<separate_abbreviation $classification_id>
+
+Returns the shortcut of the classification if the classifiaction has the separate flag set.
+
+=back
+
+=over 2
+
=item C<select_classification $name,%params>
Returns a HTML Select Tag with all available Classifications
'If enabled a warning will be shown in sales and purchase orders if there are two or more positions of the same part (new controller only).' => 'Falls eingeschaltet, wird eine Warnung angezeigt, wenn der Auftrag mehrere gleiche Artikel enthält (nur neuer Controller).',
'If enabled only those projects that are assigned to the currently selected customer are offered for selection in sales records.' => 'Wenn eingeschaltet, so werden in Verkaufsbelegen nur diejenigen Projekte zur Auswahl angeboten, die dem aktuell ausgewählten Kunden zugewiesen wurden.',
'If enabled purchase and sales records cannot be saved if no transaction description has been entered.' => 'Wenn angeschaltet, so können Einkaufs- und Verkaufsbelege nicht gespeichert werden, solange keine Vorgangsbezeichnung eingegeben wurde.',
+ 'If item not found, allow creation of new item' => 'Falls Artikel nicht gefunden, erlaube Erfassen eines Neuen',
'If left empty the default sender from the kivitendo configuration will be used (key \'email_from\' in section \'periodic_invoices\'; current value: #1).' => 'Falls leer, so wird der Standardabsender aus der kivitendo-Konfiguration genutzt (Schlüssel »email_from« in Abschnitt »periodic_invoices«; aktueller Wert: #1).',
'If missing then the start date will be used.' => 'Falls es fehlt, so wird die erste Rechnung für das Startdatum erzeugt.',
+ 'If searching a part from a document and no part is found then offer to create a new part.' => 'Wenn bei der Artikelsuche aus einem Dokument heraus kein Artikel gefunden wird, dann wird ermöglicht, von dort aus einen neuen Artikel anzulegen.',
'If the article type is set to \'mixed\' then a column called \'part_type\' or called \'pclass\' must be present.' => 'Falls der Rtikeltyp auf \'mixed\' gesetzt ist muss entweder eine Spalte \'part_type\' oder \'pclass\' im Import vorhanden sein',
'If the automatic creation of invoices for fees and interest is switched on for a dunning level then the following accounts will be used for the invoice.' => 'Wenn das automatische Erstellen einer Rechnung über Mahngebühren und Zinsen für ein Mahnlevel aktiviert ist, so werden die folgenden Konten für die Rechnung benutzt.',
'If the database user listed above does not have the right to create a database then enter the name and password of the superuser below:' => 'Falls der oben genannte Datenbankbenutzer nicht die Berechtigung zum Anlegen neuer Datenbanken hat, so können Sie hier den Namen und das Passwort des Datenbankadministratoraccounts angeben:',
'POSTED' => 'Gebucht',
'POSTED AS NEW' => 'Als neu gebucht',
'PRINTED' => 'Gedruckt',
- 'PType' => 'Typ',
'Package name' => 'Paketname',
'Packing Lists' => 'Lieferschein',
'Page' => 'Seite',
'Report and misc. Preferences' => 'Sonstige Einstellungen',
'Report date' => 'Berichtsdatum',
'Report for' => 'Bericht für',
+ 'Report separately' => 'Preis separat ausweisen',
'Reports' => 'Berichte',
'Representative' => 'Vertreter',
'Representative for Customer' => 'Vertreter für Kunden',
'Weight unit' => 'Gewichtseinheit',
'What <b>term</b> you are looking for?' => 'Nach welchem <b>Begriff</b> wollen Sie suchen?',
'What this template contains' => 'Was diese Vorlage enthält',
+ 'What type of item is this?' => 'Was ist dieser Artikel?',
'When converting a requirement spec into a quotation or an oder each section gets converted into a line position in the new record. This is the article used by default for this conversion.' => 'Wenn ein Pflichtenheft in ein Angebot oder Auftrag umgewandelt wird, wird für jeden Abschnitt eine Position im neuen Beleg angelegt. Dies ist der Artikel, der standardmäßig bei dieser Umwandlung genutzt wird.',
'Which is located at doc/kivitendo-Dokumentation.pdf. Click here: ' => 'Diese befindet sich unter doc/kivitendo-Dokumentation.pdf. Klicken Sie hier:',
'With Attachments' => 'Journal mit Anhängen',
--- /dev/null
+-- @tag: part_classification_report_separate
+-- @description: "Artikelklassifikation mit weiterer boolschen Variable für separat ausweisen"
+-- @depends: part_classifications
+ALTER TABLE part_classifications ADD COLUMN report_separate BOOLEAN DEFAULT 'f' NOT NULL;
<td>[% LxERP.t8('Used for Sale') %]</td>
<td>[% L.checkbox_tag("part_classification.used_for_sale", checked=(SELF.part_classification.used_for_sale ? 1:'')) %]</td>
</tr>
+ <tr>
+ <td>[% LxERP.t8('Report separately') %]</td>
+ <td>[% L.checkbox_tag("part_classification.report_separate", checked=(SELF.part_classification.report_separate ? 1:'')) %]</td>
+ </tr>
</table>
<p>
<th>[%- LxERP.t8('TypeAbbreviation') %]</th>
<th>[%- LxERP.t8('Used for Purchase') %]</th>
<th>[%- LxERP.t8('Used for Sale') %]</th>
+ <th>[%- LxERP.t8('Report separately') %]</th>
</tr>
</thead>
<td>[%- HTML.escape(LxERP.t8(part_classification.abbreviation)) %]</td>
<td>[% IF part_classification.used_for_purchase %][% LxERP.t8('Yes') %][% ELSE %][% LxERP.t8('No') %][% END %]</td>
<td>[% IF part_classification.used_for_sale %][% LxERP.t8('Yes') %][% ELSE %][% LxERP.t8('No') %][% END %]</td>
+ <td>[% IF part_classification.report_separate %][% LxERP.t8('Yes') %][% ELSE %][% LxERP.t8('No') %][% END %]</td>
</tr>
[%- END %]
</tbody>