use strict;
use parent qw(Exporter);
-our @EXPORT = qw(calculate_prices_and_taxes);
+our @EXPORT = qw(calculate_prices_and_taxes _calculate_item);
use Carp;
use List::Util qw(sum min max);
my ($self, $item, $idx, $data, %params) = @_;
my $part = SL::DB::Part->load_cached($item->parts_id);
+ return unless $item->part;
+
my $part_unit = $data->{units_by_name}->{ $part->unit };
my $item_unit = $data->{units_by_name}->{ $item->unit };
__PACKAGE__->meta->table('delivery_order_items');
__PACKAGE__->meta->columns(
- base_qty => { type => 'float', scale => 4 },
- cusordnumber => { type => 'text' },
- delivery_order_id => { type => 'integer', not_null => 1 },
- description => { type => 'text' },
- discount => { type => 'float', scale => 4 },
- id => { type => 'integer', not_null => 1, sequence => 'delivery_order_items_id' },
- itime => { type => 'timestamp', default => 'now()' },
- lastcost => { type => 'numeric', precision => 15, scale => 5 },
- longdescription => { type => 'text' },
- marge_price_factor => { type => 'numeric', default => 1, precision => 15, scale => 5 },
- mtime => { type => 'timestamp' },
- ordnumber => { type => 'text' },
- parts_id => { type => 'integer', not_null => 1 },
- price_factor => { type => 'numeric', default => 1, precision => 15, scale => 5 },
- price_factor_id => { type => 'integer' },
- pricegroup_id => { type => 'integer' },
- project_id => { type => 'integer' },
- qty => { type => 'numeric', precision => 25, scale => 5 },
- reqdate => { type => 'date' },
- sellprice => { type => 'numeric', precision => 15, scale => 5 },
- serialnumber => { type => 'text' },
- transdate => { type => 'text' },
- unit => { type => 'varchar', length => 20 },
+ base_qty => { type => 'float', scale => 4 },
+ cusordnumber => { type => 'text' },
+ delivery_order_id => { type => 'integer', not_null => 1 },
+ description => { type => 'text' },
+ discount => { type => 'float', scale => 4 },
+ id => { type => 'integer', not_null => 1, sequence => 'delivery_order_items_id' },
+ itime => { type => 'timestamp', default => 'now()' },
+ lastcost => { type => 'numeric', precision => 15, scale => 5 },
+ longdescription => { type => 'text' },
+ marge_price_factor => { type => 'numeric', default => 1, precision => 15, scale => 5 },
+ mtime => { type => 'timestamp' },
+ ordnumber => { type => 'text' },
+ parts_id => { type => 'integer', not_null => 1 },
+ price_factor => { type => 'numeric', default => 1, precision => 15, scale => 5 },
+ price_factor_id => { type => 'integer' },
+ pricegroup_id => { type => 'integer' },
+ project_id => { type => 'integer' },
+ qty => { type => 'numeric', precision => 25, scale => 5 },
+ reqdate => { type => 'date' },
+ sellprice => { type => 'numeric', precision => 15, scale => 5 },
+ serialnumber => { type => 'text' },
+ transdate => { type => 'text' },
+ unit => { type => 'varchar', length => 20 },
+ active_price_source => { type => 'text', default => '', not_null => 1 },
);
__PACKAGE__->meta->primary_key_columns([ 'id' ]);
__PACKAGE__->meta->table('invoice');
__PACKAGE__->meta->columns(
- allocated => { type => 'float', scale => 4 },
- assemblyitem => { type => 'boolean', default => 'false' },
- base_qty => { type => 'float', scale => 4 },
- cusordnumber => { type => 'text' },
- deliverydate => { type => 'date' },
- description => { type => 'text' },
- discount => { type => 'float', scale => 4 },
- donumber => { type => 'text' },
- fxsellprice => { type => 'numeric', precision => 15, scale => 5 },
- id => { type => 'integer', not_null => 1, sequence => 'invoiceid' },
- itime => { type => 'timestamp', default => 'now()' },
- lastcost => { type => 'numeric', precision => 15, scale => 5 },
- longdescription => { type => 'text' },
- marge_percent => { type => 'numeric', precision => 15, scale => 5 },
- marge_price_factor => { type => 'numeric', default => 1, precision => 15, scale => 5 },
- marge_total => { type => 'numeric', precision => 15, scale => 5 },
- mtime => { type => 'timestamp' },
- ordnumber => { type => 'text' },
- parts_id => { type => 'integer' },
- price_factor => { type => 'numeric', default => 1, precision => 15, scale => 5 },
- price_factor_id => { type => 'integer' },
- pricegroup_id => { type => 'integer' },
- project_id => { type => 'integer' },
- qty => { type => 'float', scale => 4 },
- sellprice => { type => 'numeric', precision => 15, scale => 5 },
- serialnumber => { type => 'text' },
- subtotal => { type => 'boolean', default => 'false' },
- trans_id => { type => 'integer' },
- transdate => { type => 'text' },
- unit => { type => 'varchar', length => 20 },
+ allocated => { type => 'float', scale => 4 },
+ assemblyitem => { type => 'boolean', default => 'false' },
+ base_qty => { type => 'float', scale => 4 },
+ cusordnumber => { type => 'text' },
+ deliverydate => { type => 'date' },
+ description => { type => 'text' },
+ discount => { type => 'float', scale => 4 },
+ donumber => { type => 'text' },
+ fxsellprice => { type => 'numeric', precision => 15, scale => 5 },
+ id => { type => 'integer', not_null => 1, sequence => 'invoiceid' },
+ itime => { type => 'timestamp', default => 'now()' },
+ lastcost => { type => 'numeric', precision => 15, scale => 5 },
+ longdescription => { type => 'text' },
+ marge_percent => { type => 'numeric', precision => 15, scale => 5 },
+ marge_price_factor => { type => 'numeric', default => 1, precision => 15, scale => 5 },
+ marge_total => { type => 'numeric', precision => 15, scale => 5 },
+ mtime => { type => 'timestamp' },
+ ordnumber => { type => 'text' },
+ parts_id => { type => 'integer' },
+ price_factor => { type => 'numeric', default => 1, precision => 15, scale => 5 },
+ price_factor_id => { type => 'integer' },
+ pricegroup_id => { type => 'integer' },
+ project_id => { type => 'integer' },
+ qty => { type => 'float', scale => 4 },
+ sellprice => { type => 'numeric', precision => 15, scale => 5 },
+ serialnumber => { type => 'text' },
+ subtotal => { type => 'boolean', default => 'false' },
+ trans_id => { type => 'integer' },
+ transdate => { type => 'text' },
+ unit => { type => 'varchar', length => 20 },
+ active_price_source => { type => 'text', default => '', not_null => 1 },
);
__PACKAGE__->meta->primary_key_columns([ 'id' ]);
__PACKAGE__->meta->table('orderitems');
__PACKAGE__->meta->columns(
- base_qty => { type => 'float', scale => 4 },
- cusordnumber => { type => 'text' },
- description => { type => 'text' },
- discount => { type => 'float', scale => 4 },
- id => { type => 'integer', not_null => 1, sequence => 'orderitemsid' },
- itime => { type => 'timestamp', default => 'now()' },
- lastcost => { type => 'numeric', precision => 15, scale => 5 },
- longdescription => { type => 'text' },
- marge_percent => { type => 'numeric', precision => 15, scale => 5 },
- marge_price_factor => { type => 'numeric', default => 1, precision => 15, scale => 5 },
- marge_total => { type => 'numeric', precision => 15, scale => 5 },
- mtime => { type => 'timestamp' },
- ordnumber => { type => 'text' },
- parts_id => { type => 'integer' },
- price_factor => { type => 'numeric', default => 1, precision => 15, scale => 5 },
- price_factor_id => { type => 'integer' },
- pricegroup_id => { type => 'integer' },
- project_id => { type => 'integer' },
- qty => { type => 'float', scale => 4 },
- reqdate => { type => 'date' },
- sellprice => { type => 'numeric', precision => 15, scale => 5 },
- serialnumber => { type => 'text' },
- ship => { type => 'float', scale => 4 },
- subtotal => { type => 'boolean', default => 'false' },
- trans_id => { type => 'integer' },
- transdate => { type => 'text' },
- unit => { type => 'varchar', length => 20 },
+ base_qty => { type => 'float', scale => 4 },
+ cusordnumber => { type => 'text' },
+ description => { type => 'text' },
+ discount => { type => 'float', scale => 4 },
+ id => { type => 'integer', not_null => 1, sequence => 'orderitemsid' },
+ itime => { type => 'timestamp', default => 'now()' },
+ lastcost => { type => 'numeric', precision => 15, scale => 5 },
+ longdescription => { type => 'text' },
+ marge_percent => { type => 'numeric', precision => 15, scale => 5 },
+ marge_price_factor => { type => 'numeric', default => 1, precision => 15, scale => 5 },
+ marge_total => { type => 'numeric', precision => 15, scale => 5 },
+ mtime => { type => 'timestamp' },
+ ordnumber => { type => 'text' },
+ parts_id => { type => 'integer' },
+ price_factor => { type => 'numeric', default => 1, precision => 15, scale => 5 },
+ price_factor_id => { type => 'integer' },
+ pricegroup_id => { type => 'integer' },
+ project_id => { type => 'integer' },
+ qty => { type => 'float', scale => 4 },
+ reqdate => { type => 'date' },
+ sellprice => { type => 'numeric', precision => 15, scale => 5 },
+ serialnumber => { type => 'text' },
+ ship => { type => 'float', scale => 4 },
+ subtotal => { type => 'boolean', default => 'false' },
+ trans_id => { type => 'integer' },
+ transdate => { type => 'text' },
+ unit => { type => 'varchar', length => 20 },
+ active_price_source => { type => 'text', default => '', not_null => 1 },
);
__PACKAGE__->meta->primary_key_columns([ 'id' ]);
id, delivery_order_id, parts_id, description, longdescription, qty, base_qty,
sellprice, discount, unit, reqdate, project_id, serialnumber,
ordnumber, transdate, cusordnumber,
- lastcost, price_factor_id, price_factor, marge_price_factor, pricegroup_id)
+ lastcost, price_factor_id, price_factor, marge_price_factor, pricegroup_id,
+ active_price_source)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
- (SELECT factor FROM price_factors WHERE id = ?), ?, ?)|;
+ (SELECT factor FROM price_factors WHERE id = ?), ?, ?, ?)|;
my $h_item = prepare_query($form, $dbh, $q_item);
my $q_item_stock =
$form->{"lastcost_$i"},
conv_i($form->{"price_factor_id_$i"}), conv_i($form->{"price_factor_id_$i"}),
conv_i($form->{"marge_price_factor_$i"}),
- $pricegroup_id);
+ $pricegroup_id,
+ $form->{"active_price_source_$i"});
do_statement($form, $h_item, $q_item, @values);
my $stock_info = DO->unpack_stock_information('packed' => $form->{"stock_${in_out}_$i"});
doi.reqdate, doi.project_id, doi.serialnumber, doi.lastcost,
doi.ordnumber, doi.transdate, doi.cusordnumber, doi.longdescription,
doi.price_factor_id, doi.price_factor, doi.marge_price_factor, doi.pricegroup_id,
+ doi.active_price_source,
pr.projectnumber, dord.transdate AS dord_transdate, dord.donumber,
pg.partsgroup
FROM delivery_order_items doi
$main::lxdebug->leave_sub();
}
-##########################
-# get pricegroups from database
-# build up selected pricegroup
-# if an exchange rate - change price
-# for each part
-#
-sub get_pricegroups_for_parts {
-
- $main::lxdebug->enter_sub();
-
- my ($self, $myconfig, $form) = @_;
-
- my $dbh = $form->get_standard_dbh;
-
- $form->{"PRICES"} = {};
-
- my $i = 1;
- my $id = 0;
- my $all_units = AM->retrieve_units($myconfig, $form);
- while (($form->{"id_$i"}) or ($form->{"new_id_$i"})) {
- $form->{"PRICES"}{$i} = [];
-
- $id = $form->{"id_$i"};
-
- if (!($form->{"id_$i"}) and $form->{"new_id_$i"}) {
- $id = $form->{"new_id_$i"};
- }
-
- my ($price, $selectedpricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
-
- my $pricegroup_old = $form->{"pricegroup_old_$i"};
-
- # sellprice has format 13,0000 or 0,00000, can't check for 0 numerically
- my $sellprice = $form->{"sellprice_$i"};
- my $pricegroup_id = $form->{"pricegroup_id_$i"};
- $form->{"new_pricegroup_$i"} = $selectedpricegroup_id;
- $form->{"old_pricegroup_$i"} = $pricegroup_old;
-
- my $price_new = $form->{"price_new_$i"};
- my $price_old = $form->{"price_old_$i"};
-
- if (!$form->{"unit_old_$i"}) {
- # Neue Ware aus der Datenbank. In diesem Fall ist unit_$i die
- # Einheit, wie sie in den Stammdaten hinterlegt wurde.
- # Es sollte also angenommen werden, dass diese ausgewaehlt war.
- $form->{"unit_old_$i"} = $form->{"unit_$i"};
- }
-
- # Die zuletzt ausgewaehlte mit der aktuell ausgewaehlten Einheit
- # vergleichen und bei Unterschied den Preis entsprechend umrechnen.
- $form->{"selected_unit_$i"} = $form->{"unit_$i"} unless ($form->{"selected_unit_$i"});
-
- if (!$all_units->{$form->{"selected_unit_$i"}} ||
- ($all_units->{$form->{"selected_unit_$i"}}->{"base_unit"} ne
- $all_units->{$form->{"unit_old_$i"}}->{"base_unit"})) {
- # Die ausgewaehlte Einheit ist fuer diesen Artikel nicht gueltig
- # (z.B. Dimensionseinheit war ausgewaehlt, es handelt sich aber
- # um eine Dienstleistung). Dann keinerlei Umrechnung vornehmen.
- $form->{"unit_old_$i"} = $form->{"selected_unit_$i"} = $form->{"unit_$i"};
- }
-
- my $basefactor = 1;
-
- if ($form->{"unit_old_$i"} ne $form->{"selected_unit_$i"}) {
- if (defined($all_units->{$form->{"unit_old_$i"}}->{"factor"}) &&
- $all_units->{$form->{"unit_old_$i"}}->{"factor"}) {
- $basefactor = $all_units->{$form->{"selected_unit_$i"}}->{"factor"} /
- $all_units->{$form->{"unit_old_$i"}}->{"factor"};
- }
- }
-
- if (!$form->{"basefactor_$i"}) {
- $form->{"basefactor_$i"} = 1;
- }
-
- my $query =
- qq|SELECT
- 0 as pricegroup_id,
- sellprice AS default_sellprice,
- '' AS pricegroup,
- sellprice AS price,
- 'selected' AS selected
- FROM parts
- WHERE id = ?
- UNION ALL
- SELECT
- pricegroup_id,
- parts.sellprice AS default_sellprice,
- pricegroup.pricegroup,
- price,
- '' AS selected
- FROM prices
- LEFT JOIN parts ON parts.id = parts_id
- LEFT JOIN pricegroup ON pricegroup.id = pricegroup_id
- WHERE parts_id = ?
- ORDER BY pricegroup|;
- my @values = (conv_i($id), conv_i($id));
- my $pkq = prepare_execute_query($form, $dbh, $query, @values);
-
- while (my $pkr = $pkq->fetchrow_hashref('NAME_lc')) {
- $pkr->{id} = $id;
- $pkr->{selected} = '';
-
- # if there is an exchange rate change price
- if (($form->{exchangerate} * 1) != 0) {
- $pkr->{price} /= $form->{exchangerate};
- }
-
- $pkr->{price} *= $form->{"basefactor_$i"};
- $pkr->{price} *= $basefactor;
- $pkr->{price_ufmt} = $pkr->{price};
- $pkr->{price} = $form->format_amount($myconfig, $pkr->{price}, 5);
-
- if (!defined $selectedpricegroup_id) {
- # new entries in article list, either old invoice was loaded (edit) or a new article was added
- # Case A: open old invoice, no pricegroup selected
- # Case B: add new article to invoice, no pricegroup selected
-
- # to distinguish case A and B the variable pricegroup_id_$i is used
- # for new articles this variable isn't defined, for loaded articles it is
- # sellprice can't be used, as it already has 0,00 set
-
- if ($pkr->{pricegroup_id} eq $form->{"pricegroup_id_$i"} and defined $form->{"pricegroup_id_$i"}) {
- # Case A
- $pkr->{selected} = ' selected';
- } elsif ($pkr->{pricegroup_id} eq $form->{customer_klass}
- and not defined $form->{"pricegroup_id_$i"}
- and $pkr->{price_ufmt} != 0 # only use customer pricegroup price if it has a value, else use default_sellprice
- # for the case where pricegroup prices haven't been set
- ) {
- # Case B: use default pricegroup of customer
-
- $pkr->{selected} = ' selected'; # unless $form->{selected};
- # no customer pricesgroup set
- if ($pkr->{price_ufmt} == $pkr->{default_sellprice}) {
-
- $pkr->{price} = $form->{"sellprice_$i"};
-
- } else {
-
-# this sub should not set anything and only return. --sschoeling, 20090506
-# is this correct? put in again... -- grichardson 20110119
- $form->{"sellprice_$i"} = $pkr->{price};
- }
-
- } elsif ($pkr->{price_ufmt} == $pkr->{default_sellprice} and $pkr->{default_sellprice} != 0) {
- $pkr->{price} = $form->{"sellprice_$i"};
- $pkr->{selected} = ' selected';
- }
- }
-
- # existing article: pricegroup or price changed
- if ($selectedpricegroup_id or $selectedpricegroup_id == 0) {
- if ($selectedpricegroup_id ne $pricegroup_old) {
- # pricegroup has changed
- if ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
- $pkr->{selected} = ' selected';
- }
- } elsif ( ($form->parse_amount($myconfig, $price_new)
- != $form->parse_amount($myconfig, $form->{"sellprice_$i"}))
- and ($price_new ne 0) and defined $price_new) {
- # sellprice has changed
- # when loading existing invoices $price_new is NULL
- if ($pkr->{pricegroup_id} == 0) {
- $pkr->{price} = $form->{"sellprice_$i"};
- $pkr->{selected} = ' selected';
- }
- } elsif ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
- # neither sellprice nor pricegroup changed
- $pkr->{selected} = ' selected';
- if ( ($pkr->{pricegroup_id} == 0) and ($pkr->{price} == $form->{"sellprice_$i"})) {
- # $pkr->{price} = $form->{"sellprice_$i"};
- } else {
- $pkr->{price} = $form->{"sellprice_$i"};
- }
- }
- }
- push @{ $form->{PRICES}{$i} }, $pkr;
-
- }
- $form->{"basefactor_$i"} *= $basefactor;
-
- $i++;
-
- $pkq->finish;
- }
-
- $main::lxdebug->leave_sub();
-}
-
sub has_storno {
$main::lxdebug->enter_sub();
sellprice = ?, discount = ?, unit = ?, reqdate = ?, project_id = ?, serialnumber = ?, ship = ?,
pricegroup_id = ?, ordnumber = ?, transdate = ?, cusordnumber = ?, subtotal = ?,
marge_percent = ?, marge_total = ?, lastcost = ?, price_factor_id = ?,
+ active_price_source = ?,
price_factor = (SELECT factor FROM price_factors WHERE id = ?), marge_price_factor = ?
WHERE id = ?
SQL
$form->{"cusordnumber_$i"}, $form->{"subtotal_$i"} ? 't' : 'f',
$form->{"marge_percent_$i"}, $form->{"marge_absolut_$i"},
$form->{"lastcost_$i"},
+ $form->{"active_price_source_$i"},
conv_i($form->{"price_factor_id_$i"}), conv_i($form->{"price_factor_id_$i"}),
conv_i($form->{"marge_price_factor_$i"}),
conv_i($orderitems_id),
o.sellprice, o.parts_id AS id, o.unit, o.discount, p.notes AS partnotes, p.inventory_accno_id AS part_inventory_accno_id,
o.reqdate, o.project_id, o.serialnumber, o.ship, o.lastcost,
o.ordnumber, o.transdate, o.cusordnumber, o.subtotal, o.longdescription,
- o.price_factor_id, o.price_factor, o.marge_price_factor,
+ o.price_factor_id, o.price_factor, o.marge_price_factor, o.active_price_source,
pr.projectnumber, p.formel,
pg.partsgroup, o.pricegroup_id, (SELECT pricegroup FROM pricegroup WHERE id=o.pricegroup_id) as pricegroup
FROM orderitems o
--- /dev/null
+package SL::PriceSource;
+
+use strict;
+use parent 'SL::DB::Object';
+use Rose::Object::MakeMethods::Generic (
+ scalar => [ qw(record_item) ],
+);
+
+use List::UtilsBy qw(min_by);
+use SL::PriceSource::ALL;
+use SL::PriceSource::Price;
+use SL::Locale::String;
+
+sub all_price_sources {
+ my ($self) = @_;
+
+ return map {
+ $_->new(record_item => $self->record_item)
+ } SL::PriceSource::ALL->all_price_sources
+}
+
+sub price_from_source {
+ my ($self, $source) = @_;
+ my ($source_name, $spec) = split m{/}, $source, 2;
+
+ my $class = SL::PriceSource::ALL->price_source_class_by_name($source_name);
+
+ return $class
+ ? $class->new(record_item => $self->record_item)->price_from_source($source, $spec)
+ : empty_price();
+}
+
+sub available_prices {
+ map { $_->available_prices } $_[0]->all_price_sources;
+}
+
+sub best_price {
+ min_by { $_->price } map { $_->best_price } $_[0]->all_price_sources;
+}
+
+sub empty_price {
+ SL::PriceSource::Price->new(
+ source => '',
+ description => t8('None (PriceSource)'),
+ );
+}
+
+1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::PriceSource - mixin for price_sources in record items
+
+=head1 SYNOPSIS
+
+ # in record item class
+
+ use SL::PriceSource;
+
+ # later on:
+
+ $record_item->all_price_sources
+ $record_item->price_source # get
+ $record_item->price_source($c) # set
+
+ $record_item->update_price_source # set price to calculated
+
+=head1 DESCRIPTION
+
+This mixin provides a way to use price_source objects from within a record item.
+Record items in this contest mean OrderItems, InvoiceItems and
+DeliveryOrderItems.
+
+=head1 FUNCTIONS
+
+price_sources
+
+returns a list of price_source objects which are created with the current record
+item.
+
+active_price_source
+
+returns the object representing the currently chosen price_source method or
+undef if custom price is chosen. Note that this must not necessarily be the
+active price, if something affecting the price_source has changed, the price
+calculated can differ from the price in the record. It is the responsibility of
+the implementing code to decide what to do in this case.
+
+=head1 BUGS
+
+None yet. :)
+
+=head1 AUTHOR
+
+Sven Schoeling E<lt>s.schoeling@linet-services.deE<gt>
+
+=cut
--- /dev/null
+package SL::PriceSource::ALL;
+
+use strict;
+use SL::PriceSource::Pricegroup;
+use SL::PriceSource::MasterData;
+
+my %price_sources_by_name = (
+ master_data => 'SL::PriceSource::MasterData',
+ pricegroup => 'SL::PriceSource::Pricegroup',
+);
+
+my @price_sources_order = qw(
+ master_data
+ pricegroup
+);
+
+sub all_price_sources {
+ map { $price_sources_by_name{$_} } @price_sources_order;
+}
+
+sub price_source_class_by_name {
+ $price_sources_by_name{$_[1]};
+}
+
+1;
--- /dev/null
+package SL::PriceSource::Base;
+
+use strict;
+
+use parent qw(SL::DB::Object);
+use Rose::Object::MakeMethods::Generic (
+ scalar => [ qw(record_item record) ],
+);
+
+sub name { die 'name needs to be implemented' }
+
+sub description { die 'description needs to be implemented' }
+
+sub available_prices { die 'available_prices needs to be implemented' }
+
+sub best_price { die 'best_price needs to be implemented' }
+
+sub price_from_source { die 'price_from_source needs to be implemented:' . "@_" }
+
+sub part {
+ $_[0]->record_item->part;
+}
+
+1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::PriceSource::Base - <oneliner description>
+
+=head1 SYNOPSIS
+
+ # in consuming module
+# TODO: thats bullshit, theres no need to have this pollute the namespace
+# make a manager that handles this
+
+ my @list_of_price_sources = $record_item->price_sources;
+ for (@list_of_price_sources) {
+ my $internal_name = $_->name;
+ my $translated_name = $_->description;
+ my $price = $_->price;
+ }
+
+ $record_item->set_active_price_source($price_source) # equivalent to:
+ $record_item->active_price_source($price_source->name);
+ $record_item->sellprice($price_source->price);
+
+ # for finer control
+ $price_source->needed_params
+ $price_source->supported_params
+
+=head1 DESCRIPTION
+
+PriceSource is an interface that allows generic algorithms to be used, to
+calculate a price for a position in a record.
+
+If any such price_source algorithm is known to the system, a user can chose
+which of them should be used to claculate the price displayed in the record.
+
+The algorithm is saved togetherwith the target price, so that changes in the
+record can recalculate the price accordingly, and otherwise manual changes to
+the price can reset the price_source used to custom (aka no price_source).
+
+=head1 INTERFACE METHODS
+
+=over 4
+
+=item C<name>
+
+Should return a unique internal name. Should be entered in
+L<SL::PriceSource::ALL> so that a name_to_class lookup works.
+
+=item C<description>
+
+Should return a translated name.
+
+=item C<needed_params>
+
+Should return a list of elements that a record_item NEEDS to be used with this calulation.
+
+Both C<needed_params> nad C<supported_params> are purely informational at this point.
+
+=item C<supported_params>
+
+Should return a list of elements that a record_item MAY HAVE to be used with this calulation.
+
+Both C<needed_params> nad C<supported_params> are purely informational at this point.
+
+=item C<price>
+
+Calculate a price and return. Do not mutate the record_item. Should will return
+undef if price is not applicable to the current record_item.
+
+=back
+
+=head1 BUGS
+
+None yet. :)
+
+=head1 AUTHOR
+
+Sven Schoeling E<lt>s.schoeling@linet-services.deE<gt>
+
+=cut
--- /dev/null
+package SL::PriceSource::MasterData;
+
+use strict;
+use parent qw(SL::PriceSource::Base);
+
+use SL::PriceSource::Price;
+use SL::Locale::String;
+
+sub name { 'master_data' }
+
+sub description { t8('Master Data') }
+
+sub available_prices {
+ my ($self, %params) = @_;
+
+ my $part = $self->part;
+
+ return () unless $part;
+
+ # TODO: sellprice only in sales, lastcost in purchase
+ return $self->make_sellprice($part);
+}
+
+sub price_from_source {
+ my ($self, $source, $spec) = @_;
+
+ if ($spec eq 'sellprice') {
+ return $self->make_sellprice($self->part);
+ }
+}
+
+sub make_sellprice {
+ my ($self, $part) = @_;
+
+ return SL::PriceSource::Price->new(
+ price => $part->sellprice,
+ source => 'master_data/sellprice',
+ description => t8('Sellprice'),
+ price_source => $self,
+ );
+}
+
+1;
--- /dev/null
+package SL::PriceSource::Price;
+
+use strict;
+
+use parent 'SL::DB::Object';
+use Rose::Object::MakeMethods::Generic (
+ scalar => [ qw(price description source price_source) ],
+ array => [ qw(depends_on) ]
+);
+
+sub full_description {
+ my ($self) = @_;
+
+ $self->price_source
+ ? $self->price_source->description . ': ' . $self->description
+ : $self->description
+}
+
+1;
--- /dev/null
+package SL::PriceSource::Pricegroup;
+
+use strict;
+use parent qw(SL::PriceSource::Base);
+
+use SL::PriceSource::Price;
+use SL::Locale::String;
+
+sub name { 'pricegroup' }
+
+sub description { t8('Pricegroup') }
+
+sub available_prices {
+ my ($self, %params) = @_;
+
+ my $item = $self->record_item;
+
+ my $prices = SL::DB::Manager::Price->get_all(
+ query => [ parts_id => $item->parts_id, price => { gt => 0 } ],
+ with_objects => 'pricegroup',
+ order_by => 'pricegroun.id',
+ );
+
+ return () unless @$prices;
+
+ return map {
+ $self->make_price($_);
+ } @$prices;
+}
+
+sub price_from_source {
+ my ($self, $source, $spec) = @_;
+
+ my $price = SL::DB::Manager::Price->find_by(id => $spec);
+
+ return $self->make_price($price);
+}
+
+sub make_price {
+ my ($self, $price_obj) = @_;
+
+ SL::PriceSource::Price->new(
+ price => $price_obj->price,
+ source => 'pricegroup/' . $price_obj->id,
+ description => $price_obj->pricegroup->pricegroup,
+ price_source => $self,
+ )
+}
+
+1;
# Kunde mit Rabatt 20 -> Rabatt 5,5 i.O.
$form->{payment_id} = $payment_id if $form->{payment_id} eq "";
- # for pricegroups
my $i = $form->{rowcount};
if ( ($form->{"partnumber_$i"} eq "")
$form->{"sellprice_$i"} = $form->format_amount(\%myconfig, $form->{"sellprice_$i"} * (1 - $form->{tradediscount}));
$form->{"lastcost_$i"} = $form->format_amount(\%myconfig, $form->{"lastcost_$i"});
$form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
-
- # get pricegroups for parts
- IS->get_pricegroups_for_parts(\%myconfig, \%$form);
-
- # build up html code for prices_$i
- &set_pricegroup($i);
}
display_form();
}
- # show pricegroup in newly loaded invoice when creating invoice from delivery order
- for my $i (1 .. $form->{rowcount}) {
- $form->{"sellprice_pg_$i"} = join '--', $form->{"sellprice_$i"}, $form->{"pricegroup_id_$i"};
- }
- IS->get_pricegroups_for_parts(\%myconfig, \%$form);
- set_pricegroup($form->{rowcount});
-
display_form();
$main::lxdebug->leave_sub();
invoice_links();
prepare_invoice();
- # show pricegroup in newly loaded invoice when creating invoice from delivery order
- for my $i (1 .. $form->{rowcount}) {
- $form->{"sellprice_pg_$i"} = join '--', $form->{"sellprice_$i"}, $form->{"pricegroup_id_$i"};
- }
- IS->get_pricegroups_for_parts(\%myconfig, \%$form);
- set_pricegroup($_) for 1 .. $form->{rowcount};
-
display_form();
$main::lxdebug->leave_sub();
use SL::AM;
use Data::Dumper;
-sub set_pricegroup {
- $main::lxdebug->enter_sub();
-
- my $form = $main::form;
- my %myconfig = %main::myconfig;
- my $locale = $main::locale;
-
- my $rowcount = shift;
- for my $j (1 .. $rowcount) {
- my $pricegroup_old = $form->{"pricegroup_old_$j"};
- if ($form->{PRICES}{$j}) {
- my $len = 0;
- my $prices = '<option value="--">' . $locale->text("none (pricegroup)") . '</option>';
- my $price = 0;
- foreach my $item (@{ $form->{PRICES}{$j} }) {
-
- #$price = $form->round_amount($myconfig, $item->{price}, 5);
- #$price = $form->format_amount($myconfig, $item->{price}, 2);
- my $price = $item->{price};
- my $pricegroup_id = $item->{pricegroup_id};
- my $pricegroup = $item->{pricegroup};
-
- # build drop down list for pricegroups
- $prices .=
- qq|<option value="$price--$pricegroup_id"$item->{selected}>$pricegroup</option>\n|;
-
- $len += 1;
-
- # map {
- # $form->{"${_}_$j"} =
- # $form->format_amount(\%myconfig, $form->{"${_}_$j"})
- # } qw(sellprice price_new price_old);
-
- # set new selectedpricegroup_id and prices for "Preis"
- if ($item->{selected} && ($pricegroup_id != 0)) {
- $form->{"pricegroup_old_$j"} = $pricegroup_id;
- $form->{"price_new_$j"} = $price;
- # edit: don't change the sellprice here
- # $form->{"sellprice_$j"} = $price; # this must only be updated for existing articles, not new ones
- }
- if ($pricegroup_id == 0) {
- $form->{"price_new_$j"} = $form->{"sellprice_$j"};
- }
- }
- $form->{"prices_$j"} = $prices;
- }
- }
- $main::lxdebug->leave_sub();
-}
-
sub display_form {
$main::lxdebug->enter_sub();
# $form->{rowcount}--;
# my $rowcount = $form->{rowcount};
#
- # # get pricegroups for parts
- # IS->get_pricegroups_for_parts(\%myconfig, \%$form);
- #
- # # build up html code for prices_$i
- # set_pricegroup($rowcount);
- #
# $form->{resubmit} = 1;
#
# }
use Carp;
use CGI;
-use List::MoreUtils qw(any uniq);
+use List::MoreUtils qw(any uniq apply);
use List::Util qw(min max first);
use SL::CVar;
use SL::CT;
use SL::IC;
use SL::IO;
+use SL::PriceSource;
use SL::DB::Customer;
use SL::DB::Default;
}
# column_index
- my @header_sort = qw(runningnumber partnumber description ship qty unit weight sellprice_pg sellprice discount linetotal);
+ my @header_sort = qw(runningnumber partnumber description ship qty unit weight sellprice discount linetotal);
my @HEADER = (
{ id => 'runningnumber', width => 5, value => $locale->text('No.'), display => 1, },
{ id => 'partnumber', width => 8, value => $locale->text('Number'), display => 1, },
{ id => 'serialnr', width => 10, value => $locale->text('Serial No.'), display => 0, },
{ id => 'projectnr', width => 10, value => $locale->text('Project'), display => 0, },
{ id => 'sellprice', width => 15, value => $locale->text('Price'), display => !$is_delivery_order, },
- { id => 'sellprice_pg', width => 8, value => $locale->text('Pricegroup'), display => !$is_delivery_order && !$is_purchase, },
+ { id => 'price_source', width => 5, value => $locale->text('Price Source'), display => !$is_delivery_order, },
{ id => 'discount', width => 5, value => $locale->text('Discount'), display => !$is_delivery_order, },
{ id => 'linetotal', width => 10, value => $locale->text('Extended'), display => !$is_delivery_order, },
{ id => 'bin', width => 10, value => $locale->text('Bin'), display => 0, },
my $deliverydate = $locale->text('Required by');
# special alignings
- my %align = map { $_ => 'right' } qw(qty ship right sellprice_pg discount linetotal stock_in_out weight);
+ my %align = map { $_ => 'right' } qw(qty ship right discount linetotal stock_in_out weight);
my %nowrap = map { $_ => 1 } qw(description unit);
$form->{marge_total} = 0;
$form->{"sellprice_$i"} = $form->{"price_new_$i"};
}
+ my $record_item = _make_record_item($i);
+
# unit begin
$form->{"unit_old_$i"} ||= $form->{"unit_$i"};
$form->{"selected_unit_$i"} ||= $form->{"unit_$i"};
|| !AM->convert_unit($form->{"selected_unit_$i"}, $form->{"unit_old_$i"}, $all_units)) { # (z.B. Dimensionseinheit war ausgewaehlt, es handelt sich aber
$form->{"unit_old_$i"} = $form->{"selected_unit_$i"} = $form->{"unit_$i"}; # um eine Dienstleistung). Dann keinerlei Umrechnung vornehmen.
}
- # adjust prices by unit, ignore if pricegroup changed
- if ((!$form->{"prices_$i"}) || ($form->{"new_pricegroup_$i"} == $form->{"old_pricegroup_$i"})) {
- $form->{"sellprice_$i"} *= AM->convert_unit($form->{"selected_unit_$i"}, $form->{"unit_old_$i"}, $all_units) || 1;
- $form->{"lastcost_$i"} *= AM->convert_unit($form->{"selected_unit_$i"}, $form->{"unit_old_$i"}, $all_units) || 1;
- $form->{"unit_old_$i"} = $form->{"selected_unit_$i"};
- }
+
+ $form->{"sellprice_$i"} *= AM->convert_unit($form->{"selected_unit_$i"}, $form->{"unit_old_$i"}, $all_units) || 1;
+ $form->{"lastcost_$i"} *= AM->convert_unit($form->{"selected_unit_$i"}, $form->{"unit_old_$i"}, $all_units) || 1;
+ $form->{"unit_old_$i"} = $form->{"selected_unit_$i"};
+
my $this_unit = $form->{"unit_$i"};
$this_unit = $form->{"selected_unit_$i"} if AM->convert_unit($this_unit, $form->{"selected_unit_$i"}, $all_units);
$column_data{ship} = $form->format_amount(\%myconfig, $form->round_amount($ship_qty, 2) * 1) . ' ' . $form->{"unit_$i"};
}
- # build in drop down list for pricesgroups
- # $sellprice_value setzt den Wert etwas unabhängiger von der Darstellung.
- # Hintergrund: Preisgruppen werden hier überprüft und neu berechnet.
- # Vorher wurde der ganze cgi->textfield Block zweimal identisch eingebaut, dass passiert
- # jetzt nach der Abfrage.
- my $sellprice_value;
- if ($form->{"prices_$i"}) {
- $column_data{sellprice_pg} = qq|<select name="sellprice_pg_$i" style="width: 8em">$form->{"prices_$i"}</select>|;
- $sellprice_value =($form->{"new_pricegroup_$i"} != $form->{"old_pricegroup_$i"})
- ? $form->format_amount(\%myconfig, $form->{"price_new_$i"}, $decimalplaces)
- : $form->format_amount(\%myconfig, $form->{"sellprice_$i"}, $decimalplaces);
- } else {
- # for last row and report
- # set pricegroup drop down list from report menu
- if ($form->{"sellprice_$i"} != 0) {
- # remember the pricegroup_id in pricegroup_old
- # but don't overwrite it
- $form->{"pricegroup_old_$i"} = $form->{"pricegroup_id_$i"};
- my $default_option = $form->{"sellprice_$i"}.'--'.$form->{"pricegroup_id_$i"};
- $column_data{sellprice_pg} = NTI($cgi->popup_menu("sellprice_pg_$i", [ $default_option ], $default_option, { $default_option => $form->{"pricegroup_$i"} || '' }));
- } else {
- $column_data{sellprice_pg} = qq| |;
- }
- $sellprice_value = $form->format_amount(\%myconfig, $form->{"sellprice_$i"}, $decimalplaces);
-
- }
- # Falls der Benutzer die Preise nicht anpassen sollte, wird das entsprechende
- # Textfield auf readonly gesetzt. Anm. von Sven: Manipulation der Preise ist
- # immer noch möglich, konsequenterweise sollten diese NUR aus der Datenbank
- # geholt werden.
- my $edit_prices = $main::auth->assert('edit_prices', 1);
- $column_data{sellprice} = (!$edit_prices)
- ? $cgi->textfield(-readonly => "readonly",
- -name => "sellprice_$i", -size => 10, -onBlur => "check_right_number_format(this)", -value => $sellprice_value)
- : $cgi->textfield(-name => "sellprice_$i", -size => 10, -onBlur => "check_right_number_format(this)", -value => $sellprice_value);
+ my $sellprice_value = $form->format_amount(\%myconfig, $form->{"sellprice_$i"}, $decimalplaces);
+ my $edit_prices = $main::auth->assert('edit_prices', 1) && !$::form->{"active_price_source_$i"};
+ $column_data{sellprice} = (!$edit_prices)
+ ? $cgi->hidden( -name => "sellprice_$i", -id => "sellprice_$i", -value => $sellprice_value) . $sellprice_value
+ : $cgi->textfield(-name => "sellprice_$i", -id => "sellprice_$i", -size => 10, -onBlur => "check_right_number_format(this)", -value => $sellprice_value);
$column_data{discount} = (!$edit_prices)
? $cgi->textfield(-readonly => "readonly",
-name => "discount_$i", -size => 3, -value => $form->format_amount(\%myconfig, $form->{"discount_$i"}))
$column_data{weight} = $form->format_amount(\%myconfig, $form->{"qty_$i"} * $form->{"weight_$i"}, 3) . ' ' . $defaults->{weightunit} if $defaults->{show_weight};
+ if ($form->{"id_${i}"}) {
+ my $price_source = SL::PriceSource->new(record_item => $record_item);
+ my $price = $price_source->price_from_source($::form->{"active_price_source_$i"});
+ $::form->{price_sources}[$i] = $price_source;
+ $column_data{price_source} .= $cgi->button(-value => $price->full_description, -onClick => "toggle_price_source($i)");
+ }
+
if ($is_delivery_order) {
$column_data{stock_in_out} = calculate_stock_in_out($i);
}
if ($is_delivery_order) {
map { $form->{"${_}_${i}"} = $form->format_amount(\%myconfig, $form->{"${_}_${i}"}) } qw(sellprice discount lastcost);
- $form->{"pricegroup_id_$i"} = $form->{"pricegroup_old_$i"} if $form->{"pricegroup_old_$i"};
- $form->{"sellprice_pg_$i"} = $form->{"hidden_prices_$i"} if $form->{"hidden_prices_$i"};
- push @hidden_vars, grep { defined $form->{"${_}_${i}"} } qw(sellprice discount not_discountable price_factor_id lastcost pricegroup_id sellprice_pg);
+ push @hidden_vars, grep { defined $form->{"${_}_${i}"} } qw(sellprice discount not_discountable price_factor_id lastcost);
push @hidden_vars, "stock_${stock_in_out}_sum_qty", "stock_${stock_in_out}";
}
$cgi->hidden("-name" => "unit_old_$i", "-value" => $form->{"selected_unit_$i"}),
$cgi->hidden("-name" => "price_new_$i", "-value" => $form->format_amount(\%myconfig, $form->{"price_new_$i"})),
map { ($cgi->hidden("-name" => $_, "-id" => $_, "-value" => $form->{$_})); } map { $_."_$i" }
- (qw(orderitems_id bo pricegroup_old price_old id inventory_accno bin partsgroup partnotes
+ (qw(orderitems_id bo price_old id inventory_accno bin partsgroup partnotes active_price_source
income_accno expense_accno listprice assembly taxaccounts ordnumber donumber transdate cusordnumber
longdescription basefactor marge_absolut marge_percent marge_price_factor weight), @hidden_vars)
);
# Benutzerdefinierte Variablen für Waren/Dienstleistungen/Erzeugnisse
_render_custom_variables_inputs(ROW2 => \@ROW2, row => $i, part_id => $form->{"id_$i"});
- push @ROWS, { ROW1 => \@ROW1, ROW2 => \@ROW2, HIDDENS => \@HIDDENS, colspan => $colspan, error => $form->{"row_error_$i"}, };
+ push @ROWS, { ROW1 => \@ROW1, ROW2 => \@ROW2, HIDDENS => \@HIDDENS, colspan => $colspan, error => $form->{"row_error_$i"}, obj => $record_item };
}
$form->{totalweight} = $totalweight;
$main::lxdebug->leave_sub();
}
-##################################################
-# build html-code for pricegroups in variable $form->{prices_$j}
-
-sub set_pricegroup {
- $main::lxdebug->enter_sub();
-
- my $form = $main::form;
- my $locale = $main::locale;
- my $cgi = $::request->{cgi};
-
- _check_io_auth();
-
- my $rowcount = shift;
- for my $j (1 .. $rowcount) {
- next unless $form->{PRICES}{$j};
- # build drop down list for pricegroups
- my $option_tmpl = qq|<option value="%s--%s" %s>%s</option>|;
- $form->{"prices_$j"} = join '', map { sprintf $option_tmpl, @$_{qw(price pricegroup_id selected pricegroup)} }
- (+{ pricegroup => $locale->text("none (pricegroup)") }, @{ $form->{PRICES}{$j} });
-
- foreach my $item (@{ $form->{PRICES}{$j} }) {
- # set new selectedpricegroup_id and prices for "Preis"
- $form->{"pricegroup_old_$j"} = $item->{pricegroup_id} if $item->{selected} && $item->{pricegroup_id};
- $form->{"sellprice_$j"} = $item->{price} if $item->{selected} && $item->{pricegroup_id};
- $form->{"price_new_$j"} = $form->{"sellprice_$j"} if $item->{selected} || !$item->{pricegroup_id};
- }
-
- # save hidden pricegroups for delivery_orders
- next unless my @selected_prices = grep { $_->{selected} } @{ $form->{PRICES}{$j} };
- $form->{"hidden_prices_$j"} = $selected_prices[-1]{price} . "--" . $selected_prices[-1]{pricegroup_id};
- }
- $main::lxdebug->leave_sub();
-}
-
sub select_item {
$main::lxdebug->enter_sub();
$form->format_amount(\%myconfig, $form->{"${_}_$i"}, $decimalplaces)
} qw(sellprice listprice lastcost) if $form->{item} ne 'assembly';
- # get pricegroups for parts
- IS->get_pricegroups_for_parts(\%myconfig, \%$form);
-
- # build up html code for prices_$i
- set_pricegroup($form->{rowcount});
-
&display_form;
$main::lxdebug->leave_sub();
or (($form->{level} eq undef) and ($form->{type} =~ /invoice/))
or ($form->{type} =~ /sales_order/)) {
- # get pricegroups for parts
- IS->get_pricegroups_for_parts(\%myconfig, \%$form);
-
- # build up html code for prices_$i
- set_pricegroup($form->{rowcount});
-
}
&display_form;
taxaccounts bin assembly weight projectnumber project_id
oldprojectnumber runningnumber serialnumber partsgroup payment_id
not_discountable shop ve gv buchungsgruppen_id language_values
- sellprice_pg pricegroup_old price_old price_new unit_old ordnumber donumber
+ price_old price_new unit_old ordnumber donumber
transdate longdescription basefactor marge_total marge_percent
marge_price_factor lastcost price_factor_id partnotes
stock_out stock_in has_sernumber reqdate orderitems_id);
# get details for customer/vendor
call_sub($::form->{vc} . "_details", qw(name department_1 department_2 street zipcode city country contact email phone fax), $::form->{vc} . "number");
- # get pricegroups for parts
- IS->get_pricegroups_for_parts(\%::myconfig, \%$::form);
-
- # build up html code for prices_$i
- set_pricegroup($::form->{rowcount});
-
$::form->{rowcount}--;
my @shipto_vars = qw(shiptoname shiptostreet shiptozipcode shiptocity shiptocountry
$::form->redo_rows(\@fields, \@new_rows, scalar(@new_rows), $::form->{rowcount});
$::form->{rowcount} -= $removed_rows;
}
+
+sub _make_record_item {
+ my ($row) = @_;
+
+ my $class = {
+ sales_order => 'OrderItem',
+ purchase_oder => 'OrderItem',
+ sales_quotation => 'OrderItem',
+ request_quotation => 'OrderItem',
+ invoice => 'InvoiceItem',
+ purchase_invoice => 'InvoiceItem',
+ purchase_delivery_order => 'DeliveryOrderItem',
+ sales_delivery_order => 'DeliveryOrderItem',
+ }->{$::form->{type}};
+
+ return unless $class;
+
+ $class = 'SL::DB::' . $class;
+
+ eval "require $class";
+
+ my $obj = $::form->{"orderitems_id_$row"}
+ ? $class->meta->convention_manager->auto_manager_class_name->find_by(id => $::form->{"orderitems_id_$row"})
+ : $class->new;
+
+ for my $method (apply { s/_$row$// } grep { /_$row$/ } keys %$::form) {
+ next unless $obj->meta->column($method);
+ if ($obj->meta->column($method)->isa('Rose::DB::Object::Metadata::Column::Date')) {
+ $obj->${\"$method\_as_date"}($::form->{"$method\_$row"});
+ } else {
+ $obj->$method($::form->{"$method\_$row"});
+ }
+ }
+
+ if ($::form->{"id_$row"}) {
+ $obj->part(SL::DB::Part->load_cached($::form->{"id_$row"}));
+ }
+
+ return $obj;
+}
$form->{rowcount} = $i;
}
-
- # get pricegroups for parts
- IS->get_pricegroups_for_parts(\%myconfig, \%$form);
-
- # Problem: set_pricegroup resets the sellprice of old invoices to the price
- # currently defined in the pricegroup, which is a problem if the price has
- # changed, as the old invoice gets the new price
- # set_pricegroup must never be called, when an old invoice is initially loaded
-
- # set_pricegroup($_) for 1 .. $form->{rowcount};
}
$main::lxdebug->leave_sub();
}
map { $form->{"${_}_$i"} = $form->format_amount(\%myconfig, $form->{"${_}_$i"}, $decimalplaces) } qw(sellprice lastcost);
$form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
-
- # get pricegroups for parts
- IS->get_pricegroups_for_parts(\%myconfig, \%$form);
-
- # build up html code for prices_$i
- &set_pricegroup($i);
}
&display_form;
$form->{forex} = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{invdate}, 'buy');
$form->{exchangerate} = $form->{forex} if $form->{forex};
- # remember pricegroups for "use as new"
- IS->get_pricegroups_for_parts(\%myconfig, \%$form);
- set_pricegroup($_) for 1 .. $form->{rowcount};
-
&display_form;
$main::lxdebug->leave_sub();
check_oe_access();
+ my $order = _make_record();
+
set_headings($form->{"id"} ? "edit" : "add");
$form->{update} = 1;
$form->{"sellprice_$i"} = $form->format_amount(\%myconfig, $form->{"sellprice_$i"}, $decimalplaces);
$form->{"lastcost_$i"} = $form->format_amount(\%myconfig, $form->{"lastcost_$i"}, $decimalplaces);
$form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"}, $dec_qty);
-
- # get pricegroups for parts
- IS->get_pricegroups_for_parts(\%myconfig, \%$form);
-
- # build up html code for prices_$i
- &set_pricegroup($i);
}
display_form();
$form->format_amount(\%myconfig, $form->{"qty_$i"}, $dec_qty);
}
- # show pricegroup in newly loaded invoice when creating invoice from quotation/order
- IS->get_pricegroups_for_parts(\%myconfig, \%$form);
- set_pricegroup($_) for 1 .. $form->{rowcount};
-
&display_form;
$main::lxdebug->leave_sub();
$::form->error($::locale->text('No action defined.'));
}
+
+sub _make_record {
+ my $obj = SL::DB::Order->new;
+
+ for my $method (keys %$::form) {
+ next unless $obj->can($method);
+ next unless $obj->meta->column($method);
+
+ if ($obj->meta->column($method)->isa('Rose::DB::Object::Metadata::Column::Date')) {
+ $obj->${\"$method\_as_date"}($::form->{$method});
+ } elsif ((ref $obj->meta->column($method)) =~ /^Rose::DB::Object::Metadata::Column::(?:Integer|Numeric|Float|DoublePrecsion)$/) {
+ $obj->$method($::form->{$method});
+ }
+ }
+
+ my @items;
+ for my $i (1 .. $::form->{rowcount}) {
+ next unless $::form->{"id_$i"};
+ push @items, _make_record_item($i)
+ }
+
+ $obj->orderitems(@items);
+
+ return $obj;
+}
+
'No.' => 'Position',
'No/individual shipping address' => 'Keine/individuelle Lieferadresse',
'None' => 'Kein',
+ 'None (PriceSource)' => 'Freier Preis',
'Normal users cannot log in.' => 'Normale Benutzer können sich nicht anmelden.',
'Normalize Customer / Vendor names' => 'Normalisierung Kunden- / Lieferantennamen',
'Normalize part description and part notes' => 'Normalisierung Artikelbeschreibung und Artikellangtext (Bemerkung)',
'Price' => 'Preis',
'Price Factor' => 'Preisfaktor',
'Price Factors' => 'Preisfaktoren',
+ 'Price Source' => 'Preisquelle',
'Price factor (database ID)' => 'Preisfaktor (Datenbank-ID)',
'Price factor (name)' => 'Preisfaktor (Name)',
'Price factor deleted!' => 'Preisfaktor gelöscht.',
'no article assigned yet' => 'noch kein Artikel zugewiesen',
'no bestbefore' => 'keine Mindesthaltbarkeit',
'no chargenumber' => 'keine Chargennummer',
- 'none (pricegroup)' => 'keine',
'not configured' => 'nicht konfiguriert',
'not delivered' => 'nicht geliefert',
'not executed' => 'nicht ausgeführt',
--- /dev/null
+-- @tag: recorditem_active_price_source
+-- @description: Preisquelle in Belegpositionen
+-- @depends: release_2_6_2
+-- @encoding: utf-8
+
+ALTER TABLE orderitems ADD COLUMN active_price_source TEXT NOT NULL DEFAULT '';
+ALTER TABLE delivery_order_items ADD COLUMN active_price_source TEXT NOT NULL DEFAULT '';
+ALTER TABLE invoice ADD COLUMN active_price_source TEXT NOT NULL DEFAULT '';
--- /dev/null
+[%- USE T8 %]
+[%- USE HTML %]
+[%- USE L %]
+[%- USE LxERP %]
+<tr class="listrow[% i % 2 %]" id="row[% i %]_3" style='display:none'>
+ <td colspan="[% row.colspan %]">
+ <span class="[% IF !row.obj.active_price_source %]bold[% END %]">
+ [% L.radio_button_tag('active_price_source_' _ i, label=LxERP.t8('None (PriceSource)'), checked=!row.obj.active_price_source, value='', onChange='update_price_source(' _ i _ ', \'\')') %]
+ </span>
+ [%- FOREACH price IN price_sources.$i.available_prices %]
+ <div class="[% IF price.source == row.obj.active_price_source %]bold[% END %]">
+ [% L.radio_button_tag('active_price_source_' _ i, value=price.source, checked=price.source == row.obj.active_price_source, label=LxERP.format_amount(price.price, 2) _ ' (' _ price.full_description _ ')', onChange='update_price_source(' _ i _ ', \'' _ price.source _ '\', \'' _ LxERP.format_amount(price.price, -2) _ '\')' ) %]
+ </div>
+ [%- END %]
+ </td>
+</tr>
[%- USE T8 %]
[%- USE HTML %]
-
+[%- USE L %]
+[%- USE LxERP %]
[%- PROCESS 'amcvar/render_inputs_block.html' %]
<tr>
<td>
</td>
</tr>
+ [% PROCESS 'oe/_price_sources_row.html' i = loop.count %]
[%- END %]
</table>
[% END %]
}, 1);
});
+ function toggle_price_source(row) {
+ $('#row' + row + '_3').toggle();
+ }
+ function update_price_source(row, source, price_str){
+ $('#active_price_source_' + row).val(source);
+ if (price_str) $('#sellprice_' + row).val(price_str);
+ $('#update_button').click();
+ }
</script>
</td>