use List::MoreUtils qw(any);
use Carp;
+use Data::Dumper;
+
use SL::AM;
use SL::ARAP;
use SL::CVar;
use SL::Common;
use SL::DATEV qw(:CONSTANTS);
+use SL::Util qw(trim);
use SL::DBUtils;
use SL::DO;
use SL::GenericTranslations;
use SL::HTML::Restrict;
+use SL::Locale::String qw(t8);
use SL::MoreCommon;
use SL::IC;
use SL::IO;
use SL::TransNumber;
use SL::DB::Chart;
+use SL::DB::Customer;
use SL::DB::Default;
use SL::DB::Draft;
use SL::DB::Tax;
use SL::DB::TaxZone;
+use SL::DB::ValidityToken;
use SL::TransNumber;
use SL::DB;
use SL::Presenter::Part qw(type_abbreviation classification_abbreviation);
-use Data::Dumper;
-
+use SL::Helper::QrBillFunctions qw(get_qrbill_account assemble_ref_number);
+use SL::Helper::ISO3166;
use strict;
use constant PCLASS_OK => 0;
use constant PCLASS_NOTFORSALE => 1;
$form->{iap_final_amount_nofmt} = $form->{invtotal_nofmt} - $form->{iap_amount_nofmt};
$form->{iap_final_amount} = $form->format_amount($myconfig, $form->{iap_final_amount_nofmt}, 2);
+ # set variables for swiss QR bill, if feature enabled
+ # handling errors gracefully (don't die if undef)
+ my $create_qrbill_invoices = $::instance_conf->get_create_qrbill_invoices;
+ if ($::instance_conf->get_create_qrbill_invoices && $form->{formname} eq 'invoice') {
+ my ($qr_account, $error) = get_qrbill_account();
+
+ # case 1: QR-Reference number and QR-IBAN
+ # case 2: without reference number and regular IBAN
+ if ($create_qrbill_invoices == 1) {
+ $form->{qrbill_iban} = $qr_account->{qr_iban};
+ } elsif ($create_qrbill_invoices == 2) {
+ $form->{qrbill_iban} = $qr_account->{iban};
+ }
+
+ my $biller_country = $::instance_conf->get_address_country() || 'CH';
+ my $biller_countrycode = SL::Helper::ISO3166::map_name_to_alpha_2_code($biller_country);
+ $form->{qrbill_biller_countrycode} = $biller_countrycode;
+
+ my $customer_country = $form->{billing_address_id} ?
+ $form->{billing_address_country} || 'CH' :
+ $form->{country} || 'CH';
+ my $customer_countrycode = SL::Helper::ISO3166::map_name_to_alpha_2_code($customer_country);
+ $form->{qrbill_customer_countrycode} = $customer_countrycode;
+
+ $form->{qrbill_amount} = sprintf("%.2f", $form->parse_amount($myconfig, $form->{'total'}));
+ }
$main::lxdebug->leave_sub();
}
sub _post_invoice {
my ($self, $myconfig, $form, $provided_dbh, %params) = @_;
+ my $validity_token;
+ if (!$form->{id}) {
+ $validity_token = SL::DB::Manager::ValidityToken->fetch_valid_token(
+ scope => SL::DB::ValidityToken::SCOPE_SALES_INVOICE_POST(),
+ token => $form->{form_validity_token},
+ );
+
+ die $::locale->text('The form is not valid anymore.') if !$validity_token;
+ }
+
my $payments_only = $params{payments_only};
my $dbh = $provided_dbh || SL::DB->client->dbh;
my $restricter = SL::HTML::Restrict->create;
if ($form->{currency} eq $defaultcurrency) {
$form->{exchangerate} = 1;
} else {
- $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{invdate}, 'buy');
+ $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{invdate}, 'buy');
+ $form->{exchangerate} = $form->parse_amount($myconfig, $form->{exchangerate}, 5);
+
+ # if default exchangerate is not defined, define one
+ unless ($exchangerate) {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{invdate}, $form->{exchangerate}, 0);
+ # delete records exchangerate -> if user sets new invdate for record
+ $query = qq|UPDATE ar set exchangerate = NULL where id = ?|;
+ do_query($form, $dbh, $query, $form->{"id"});
+ }
+ # update record exchangerate, if the default is set and differs from current
+ if ($exchangerate && ($form->{exchangerate} != $exchangerate)) {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{invdate},
+ $form->{exchangerate}, 0, $form->{id}, 'ar');
+ }
}
- $form->{exchangerate} =
- ($exchangerate)
- ? $exchangerate
- : $form->parse_amount($myconfig, $form->{exchangerate});
-
$form->{expense_inventory} = "";
my %baseunits;
next if $payments_only;
- if ($form->{"inventory_accno_$i"} || $form->{"part_type_$i"} eq 'assembly') {
+
+
+ # do cogs only if inventory_sytem perpetual is active
+ if ($::instance_conf->get_inventory_system eq 'perpetual'
+ && $form->{"inventory_accno_$i"} || $form->{"part_type_$i"} eq 'assembly') {
if ($form->{"part_type_$i"} eq 'assembly') {
# record assembly item as allocated
$form->{"sellprice_$i"}, $fxsellprice,
$form->{"discount_$i"}, $allocated, 'f',
$form->{"unit_$i"}, conv_date($form->{"reqdate_$i"}), conv_i($form->{"project_id_$i"}),
- $form->{"serialnumber_$i"}, $pricegroup_id,
+ trim($form->{"serialnumber_$i"}), $pricegroup_id,
$baseqty, $form->{"subtotal_$i"} ? 't' : 'f',
$form->{"marge_percent_$i"}, $form->{"marge_absolut_$i"},
$form->{"lastcost_$i"},
dbh => $dbh);
}
# link previous items with invoice items
- foreach (qw(delivery_order_items orderitems invoice)) {
+ foreach (qw(delivery_order_items orderitems invoice reclamation_items)) {
if (!$form->{useasnew} && $form->{"converted_from_${_}_id_$i"}) {
RecordLinks->create_links('dbh' => $dbh,
'mode' => 'ids',
# reverse AR
$form->{amount}{ $form->{id} }{ $form->{AR} } *= -1;
- # update exchangerate
- if (($form->{currency} ne $defaultcurrency) && !$exchangerate) {
- $form->update_exchangerate($dbh, $form->{currency}, $form->{invdate},
- $form->{exchangerate}, 0);
- }
-
$project_id = conv_i($form->{"globalproject_id"});
# entsprechend auch beim Bestimmen des Steuerschlüssels in Taxkey.pm berücksichtigen
my $taxdate = $form->{tax_point} ||$form->{deliverydate} || $form->{invdate};
}
# no tax, no prob
if ($tax and $tax->rate != 0) {
+ die "Need a valid chart id for table defaults column advance_payment_taxable_7" if $tax->taxkey == 2 && ! $::instance_conf->get_advance_payment_taxable_7_id;
+ die "Need a valid chart id for table defaults column advance_payment_taxable_19" if $tax->taxkey == 3 && ! $::instance_conf->get_advance_payment_taxable_19_id;
my $transfer_chart = $tax->taxkey == 2 ? SL::DB::Chart->new(id => $::instance_conf->get_advance_payment_taxable_7_id)->load
: $tax->taxkey == 3 ? SL::DB::Chart->new(id => $::instance_conf->get_advance_payment_taxable_19_id)->load
: undef;
$diff = 0;
- # update exchange rate
+ # update exchange rate for PAYMENTS
+ # exchangerate contains a new exchangerate of the payment date
if (($form->{currency} ne $defaultcurrency) && !$exchangerate) {
+ $form->{script} = 'is.pl';
$form->update_exchangerate($dbh, $form->{currency},
$form->{"datepaid_$i"},
$form->{"exchangerate_$i"}, 0);
$amount = $form->round_amount( $netamount + $tax, 2, 1);
+ # qr reference
+ my $qr_reference;
+ if ($form->{has_qr_reference}) {
+ # (re-)generate reference number
+
+ # get qr-account data
+ my ($qr_account, $error) = get_qrbill_account();
+ die $error if !$qr_account;
+
+ # get customer object
+ my $customer_obj = SL::DB::Customer->load_cached(conv_i($form->{customer_id}));
+
+ # assemble reference number with check digit
+ ($qr_reference, $error) = assemble_ref_number($qr_account->{bank_account_id},
+ $customer_obj->{customernumber},
+ $form->{invnumber});
+ die $error if !$qr_reference;
+ } else {
+ # if the reference number has been previously defined keep it
+ if (defined $form->{qr_reference}) {
+ $qr_reference = $form->{qr_reference};
+ } else {
+ $qr_reference = undef;
+ }
+ }
+
+ # add invoice number to unstructured message if feature enabled in client config
+ my $qr_unstructured_message = $form->{"qr_unstructured_message"};
+ if ($::instance_conf->get_qrbill_copy_invnumber && $form->{formname} eq 'invoice') {
+ my $invnumber = $form->{"invnumber"};
+ if ($qr_unstructured_message eq '') {
+ $qr_unstructured_message = $invnumber;
+ } elsif (rindex($qr_unstructured_message, $invnumber) == -1) {
+ $qr_unstructured_message .= '; ' . $invnumber;
+ }
+ }
+
# save AR record
#erweiterung fuer lieferscheinnummer (donumber) 12.02.09 jb
globalproject_id = ?, delivery_customer_id = ?,
transaction_description = ?, delivery_vendor_id = ?,
donumber = ?, invnumber_for_credit_note = ?, direct_debit = ?, qrbill_without_amount = ?,
- delivery_term_id = ?
+ qr_reference = ?, qr_unstructured_message = ?, delivery_term_id = ?
WHERE id = ?|;
@values = ( $form->{"invnumber"}, $form->{"ordnumber"}, $form->{"quonumber"}, $form->{"cusordnumber"},
conv_date($form->{"invdate"}), conv_date($form->{"orddate"}), conv_date($form->{"quodate"}), conv_date($form->{tax_point}), conv_i($form->{"customer_id"}),
conv_i($form->{"globalproject_id"}), conv_i($form->{"delivery_customer_id"}),
$form->{transaction_description}, conv_i($form->{"delivery_vendor_id"}),
$form->{"donumber"}, $form->{"invnumber_for_credit_note"}, $form->{direct_debit} ? 't' : 'f', $form->{qrbill_without_amount} ? 't' : 'f',
- conv_i($form->{delivery_term_id}),
+ $qr_reference, $qr_unstructured_message, conv_i($form->{delivery_term_id}),
conv_i($form->{"id"}));
do_query($form, $dbh, $query, @values);
WHERE id = ?!;
do_query($form, $dbh, $query, "Rechnung storniert am $form->{invdate} ", conv_i($form->{"storno_id"}));
do_query($form, $dbh, qq|UPDATE ar SET paid = amount WHERE id = ?|, conv_i($form->{"id"}));
+
+ $query = <<SQL;
+ UPDATE orderitems
+ SET recurring_billing_invoice_id = NULL
+ WHERE recurring_billing_invoice_id = ?
+SQL
+
+ do_query($form, $dbh, $query, conv_i($form->{"storno_id"}));
}
# maybe we are in a larger transaction and the current
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.
- if ($form->{convert_from_oe_ids}) {
- RecordLinks->create_links('dbh' => $dbh,
- 'mode' => 'ids',
- 'from_table' => 'oe',
- 'from_ids' => $form->{convert_from_oe_ids},
- 'to_table' => 'ar',
- 'to_id' => $form->{id},
+ foreach (qw(oe ar reclamations)) {
+ if ($form->{"convert_from_${_}_ids"}) {
+ RecordLinks->create_links('dbh' => $dbh,
+ 'mode' => 'ids',
+ 'from_table' => $_,
+ 'from_ids' => $form->{"convert_from_${_}_ids"},
+ 'to_table' => 'ar',
+ 'to_id' => $form->{id},
);
- delete $form->{convert_from_oe_ids};
+ delete $form->{"convert_from_${_}_ids"};
+ }
}
my @convert_from_do_ids = map { $_ * 1 } grep { $_ } split m/\s+/, $form->{convert_from_do_ids};
$shop->connector->set_orderstatus($shop_order->shop_trans_id, "completed");
}
+ $validity_token->delete if $validity_token;
+ delete $form->{form_validity_token};
+
return 1;
}
my ($err, $qty, $wh_id, $bin_id, $chargenumber);
if ($::instance_conf->get_sales_serial_eq_charge && $form->{"serialnumber_$i"}) {
- my @serials = split(" ", $form->{"serialnumber_$i"});
+ my @serials = split(" ", trim($form->{"serialnumber_$i"}));
if (scalar @serials != $form->{"qty_$i"}) {
push @errors, $::locale->text("Cannot transfer #1 qty with #2 serial number(s)", $form->{"qty_$i"}, scalar @serials);
last;
a.mtime, a.itime,
a.language_id, a.delivery_customer_id, a.delivery_vendor_id, a.type,
a.transaction_description, a.donumber, a.invnumber_for_credit_note,
- a.marge_total, a.marge_percent, a.direct_debit, a.qrbill_without_amount, a.delivery_term_id,
+ a.marge_total, a.marge_percent, a.direct_debit, a.qrbill_without_amount, a.qr_reference, a.qr_unstructured_message, a.delivery_term_id,
dc.dunning_description,
e.name AS employee
FROM ar a
$form->{mtime} = $form->{itime} if !$form->{mtime};
$form->{lastmtime} = $form->{mtime};
- $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate}, "buy");
+ ($form->{exchangerate}, $form->{record_forex}) = $form->check_exchangerate($myconfig, $form->{currency}, $form->{invdate}, "buy", $id, 'ar');
foreach my $vc (qw(customer vendor)) {
next if !$form->{"delivery_${vc}_id"};
- ($form->{"delivery_${vc}_string"}) = selectrow_query($form, $dbh, qq|SELECT name FROM customer WHERE id = ?|, $id);
+ ($form->{"delivery_${vc}_string"}) = selectrow_query($form, $dbh, qq|SELECT name FROM customer WHERE id = ?|,
+ $form->{"delivery_${vc}_id"});
}
# get shipto
LEFT JOIN currencies cu ON (c.currency_id=cu.id)
WHERE 1 = 1 $where|;
$ref = selectfirst_hashref_query($form, $dbh, $query, @values);
-
+ die t8("Cannot find a single customer. Maybe there is no customer yet?") unless $ref;
delete $ref->{salesman_id} if !$ref->{salesman_id};
delete $ref->{payment_id} if !$ref->{payment_id};
AND e.transdate = o.transdate)
FROM oe o
WHERE o.customer_id = ?
- AND o.quotation = '0'
+ AND o.record_type = 'sales_order'
AND o.closed = '0'|;
my $sth = prepare_execute_query($form, $dbh, $query, $cid);