$form->{amount} = {};
$form->{amount_cogs} = {};
+ my @processed_invoice_ids;
+
foreach my $i (1 .. $form->{rowcount}) {
if ($form->{type} eq "credit_note") {
$form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"}) * -1;
$pricegroup_id *= 1;
$pricegroup_id = undef if !$pricegroup_id;
- my ($invoice_id) = selectfirst_array_query($form, $dbh, qq|SELECT nextval('invoiceid')|);
+ if (!$form->{"invoice_id_$i"}) {
+ # there is no persistent id, therefore create one with all necessary constraints
+ my $q_invoice_id = qq|SELECT nextval('invoiceid')|;
+ my $h_invoice_id = prepare_query($form, $dbh, $q_invoice_id);
+ do_statement($form, $h_invoice_id, $q_invoice_id);
+ $form->{"invoice_id_$i"} = $h_invoice_id->fetchrow_array();
+ my $q_create_invoice_id = qq|INSERT INTO invoice (id, trans_id, parts_id) values (?, ?, ?)|;
+ do_query($form, $dbh, $q_create_invoice_id, conv_i($form->{"invoice_id_$i"}), conv_i($form->{id}), conv_i($form->{"id_$i"}));
+ $h_invoice_id->finish();
+ }
# save detail record in invoice table
- $query =
- qq|INSERT INTO invoice (id, trans_id, parts_id, description, longdescription, qty,
- sellprice, fxsellprice, discount, allocated, assemblyitem,
- unit, deliverydate, project_id, serialnumber, pricegroup_id,
- ordnumber, donumber, transdate, cusordnumber, base_qty, subtotal,
- marge_percent, marge_total, lastcost,
- price_factor_id, price_factor, marge_price_factor)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
- (SELECT factor FROM price_factors WHERE id = ?), ?)|;
-
- @values = ($invoice_id, conv_i($form->{id}), conv_i($form->{"id_$i"}),
+ $query = <<SQL;
+ UPDATE invoice SET trans_id = ?, parts_id = ?, description = ?, longdescription = ?, qty = ?,
+ sellprice = ?, fxsellprice = ?, discount = ?, allocated = ?, assemblyitem = ?,
+ unit = ?, deliverydate = ?, project_id = ?, serialnumber = ?, pricegroup_id = ?,
+ ordnumber = ?, donumber = ?, transdate = ?, cusordnumber = ?, base_qty = ?, subtotal = ?,
+ marge_percent = ?, marge_total = ?, lastcost = ?, active_price_source = ?, active_discount_source = ?,
+ price_factor_id = ?, price_factor = (SELECT factor FROM price_factors WHERE id = ?), marge_price_factor = ?
+ WHERE id = ?
+SQL
+
+ @values = (conv_i($form->{id}), conv_i($form->{"id_$i"}),
$form->{"description_$i"}, $restricter->process($form->{"longdescription_$i"}), $form->{"qty_$i"},
$form->{"sellprice_$i"}, $fxsellprice,
$form->{"discount_$i"}, $allocated, 'f',
$form->{"cusordnumber_$i"}, $baseqty, $form->{"subtotal_$i"} ? 't' : 'f',
$form->{"marge_percent_$i"}, $form->{"marge_absolut_$i"},
$form->{"lastcost_$i"},
+ $form->{"active_price_source_$i"}, $form->{"active_discount_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($form->{"marge_price_factor_$i"}),
+ conv_i($form->{"invoice_id_$i"}));
do_query($form, $dbh, $query, @values);
+ push @processed_invoice_ids, $form->{"invoice_id_$i"};
CVar->save_custom_variables(module => 'IC',
sub_module => 'invoice',
- trans_id => $invoice_id,
+ trans_id => $form->{"invoice_id_$i"},
configs => $ic_cvar_configs,
variables => $form,
name_prefix => 'ic_',
Common::webdav_folder($form);
+ if ($form->{convert_from_ar_ids}) {
+ RecordLinks->create_links('dbh' => $dbh,
+ 'mode' => 'ids',
+ 'from_table' => 'ar',
+ 'from_ids' => $form->{convert_from_ar_ids},
+ 'to_table' => 'ar',
+ 'to_id' => $form->{id},
+ );
+ delete $form->{convert_from_ar_ids};
+ }
+
# Link this record to the records it was created from.
RecordLinks->create_links('dbh' => $dbh,
'mode' => 'ids',
'arap_id' => $form->{id},
'table' => 'ar',);
+ # search for orphaned invoice items
+ $query = sprintf 'SELECT id FROM invoice WHERE trans_id = ? AND NOT id IN (%s)', join ', ', ("?") x scalar @processed_invoice_ids;
+ @values = (conv_i($form->{id}), map { conv_i($_) } @processed_invoice_ids);
+ my @orphaned_ids = map { $_->{id} } selectall_hashref_query($form, $dbh, $query, @values);
+ if (scalar @orphaned_ids) {
+ # clean up invoice items
+ $query = sprintf 'DELETE FROM invoice WHERE id IN (%s)', join ', ', ("?") x scalar @orphaned_ids;
+ do_query($form, $dbh, $query, @orphaned_ids);
+ }
+
# safety check datev export
if ($::instance_conf->get_datev_check_on_sales_invoice) {
my $transdate = $::form->{invdate} ? DateTime->from_lxoffice($::form->{invdate}) : undef;
# delete acc_trans
my @values = (conv_i($form->{id}));
do_query($form, $dbh, qq|DELETE FROM acc_trans WHERE trans_id = ?|, @values);
- do_query($form, $dbh, qq|DELETE FROM invoice WHERE trans_id = ?|, @values);
do_query($form, $dbh, qq|DELETE FROM shipto WHERE (trans_id = ?) AND (module = 'AR')|, @values);
$main::lxdebug->leave_sub();
my @queries = (
qq|DELETE FROM status WHERE trans_id = ?|,
qq|DELETE FROM periodic_invoices WHERE ar_id = ?|,
+ qq|DELETE FROM invoice WHERE trans_id = ?|,
qq|DELETE FROM ar WHERE id = ?|,
);
i.id AS invoice_id,
i.description, i.longdescription, i.qty, i.fxsellprice AS sellprice, i.discount, i.parts_id AS id, i.unit, i.deliverydate AS reqdate,
- i.project_id, i.serialnumber, i.id AS invoice_pos, i.pricegroup_id, i.ordnumber, i.donumber, i.transdate, i.cusordnumber, i.subtotal, i.lastcost,
- i.price_factor_id, i.price_factor, i.marge_price_factor,
+ i.project_id, i.serialnumber, i.pricegroup_id, i.ordnumber, i.donumber, i.transdate, i.cusordnumber, i.subtotal, i.lastcost,
+ i.price_factor_id, i.price_factor, i.marge_price_factor, i.active_price_source, i.active_discount_source,
p.partnumber, p.assembly, p.notes AS partnotes, p.inventory_accno_id AS part_inventory_accno_id, p.formel, p.listprice,
pr.projectnumber, pg.partsgroup, prg.pricegroup
trans_id => $ref->{invoice_id},
);
map { $ref->{"ic_cvar_$_->{name}"} = $_->{value} } @{ $cvars };
- delete $ref->{invoice_id};
map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid)) if !$ref->{"part_inventory_accno_id"};
delete($ref->{"part_inventory_accno_id"});
push @values, '%' . $form->{"${field}_${i}"} . '%';
}
- #Es soll auch nach EAN gesucht werden, ohne Einschränkung durch Beschreibung
+ my (%mm_by_id);
if ($form->{"partnumber_$i"} && !$form->{"description_$i"}) {
$where .= qq| OR (NOT p.obsolete = '1' AND p.ean = ? )|;
push @values, $form->{"partnumber_$i"};
+
+ # also search hits in makemodels, but only cache the results by id and merge later
+ my $mm_query = qq|
+ SELECT parts_id, model FROM makemodel LEFT JOIN parts ON parts.id = parts_id WHERE NOT parts.obsolete AND model ILIKE ?;
+ |;
+ my $mm_results = selectall_hashref_query($::form, $dbh, $mm_query, '%' . $form->{"partnumber_$i"} . '%');
+ my @mm_ids = map { $_->{parts_id} } @$mm_results;
+ push @{$mm_by_id{ $_->{parts_id} } ||= []}, $_ for @$mm_results;
+
+ if (@mm_ids) {
+ $where .= qq| OR p.id IN (| . join(',', ('?') x @mm_ids) . qq|)|;
+ push @values, @mm_ids;
+ }
}
# Search for part ID overrides all other criteria.
qq|SELECT
p.id, p.partnumber, p.description, p.sellprice,
p.listprice, p.inventory_accno_id, p.lastcost,
+ p.ean,
c1.accno AS inventory_accno,
c1.new_chart_id AS inventory_new_chart,
while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
+ if ($mm_by_id{$ref->{id}}) {
+ $ref->{makemodels} = $mm_by_id{$ref->{id}};
+ push @{ $ref->{matches} ||= [] }, $::locale->text('Model') . ': ' . join ', ', map { $_->{model} } @{ $mm_by_id{$ref->{id}} };
+ }
+
+ if ($ref->{ean} eq $::form->{"partnumber_$i"}) {
+ push @{ $ref->{matches} ||= [] }, $::locale->text('EAN') . ': ' . $ref->{ean};
+ }
+
# In der Buchungsgruppe ist immer ein Bestandskonto verknuepft, auch wenn
# es sich um eine Dienstleistung handelt. Bei Dienstleistungen muss das
# Buchungskonto also aus dem Ergebnis rausgenommen werden.
$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();