qq| a.shippingpoint, a.storno, a.storno_id, a.globalproject_id, | .
qq| a.marge_total, a.marge_percent, | .
qq| a.transaction_description, a.direct_debit, | .
+ qq| a.type, | .
qq| pr.projectnumber AS globalprojectnumber, | .
qq| c.name, c.customernumber, c.country, c.ustid, b.description as customertype, | .
qq| c.id as customer_id, | .
from acc_trans ac left join ar on (ac.trans_id = ar.id)
WHERE ac.chart_link like 'AR_amount%'
AND ac.transdate >= ? AND ac.transdate <= ?
+ AND ar.type = 'invoice'
group by invnumber,netamount having sum(ac.amount) <> ar.netamount|;
my $ar_amount_not_ac_amount = selectall_hashref_query($::form, $self->dbh, $query, $self->fromdate, $self->todate);
# model: base name of the rose model
# right: access right used for import
my %file_types = (
- 'sales_quotation' => { gen => 1, gltype => '', dir =>'SalesQuotation', model => 'Order', right => 'import_ar' },
- 'sales_order' => { gen => 5, gltype => '', dir =>'SalesOrder', model => 'Order', right => 'import_ar' },
- 'sales_delivery_order' => { gen => 1, gltype => '', dir =>'SalesDeliveryOrder', model => 'DeliveryOrder', right => 'import_ar' },
- 'invoice' => { gen => 1, gltype => 'ar', dir =>'SalesInvoice', model => 'Invoice', right => 'import_ar' },
- 'credit_note' => { gen => 1, gltype => '', dir =>'CreditNote', model => 'Invoice', right => 'import_ar' },
- 'request_quotation' => { gen => 7, gltype => '', dir =>'RequestForQuotation', model => 'Order', right => 'import_ap' },
- 'purchase_order' => { gen => 7, gltype => '', dir =>'PurchaseOrder', model => 'Order', right => 'import_ap' },
- 'purchase_delivery_order' => { gen => 7, gltype => '', dir =>'PurchaseDeliveryOrder',model => 'DeliveryOrder', right => 'import_ap' },
- 'purchase_invoice' => { gen => 6, gltype => 'ap', dir =>'PurchaseInvoice', model => 'PurchaseInvoice',right => 'import_ap' },
- 'vendor' => { gen => 0, gltype => '', dir =>'Vendor', model => 'Vendor', right => 'xx' },
- 'customer' => { gen => 1, gltype => '', dir =>'Customer', model => 'Customer', right => 'xx' },
- 'project' => { gen => 0, gltype => '', dir =>'Project', model => 'Project', right => 'xx' },
- 'part' => { gen => 0, gltype => '', dir =>'Part', model => 'Part', right => 'xx' },
- 'gl_transaction' => { gen => 6, gltype => 'gl', dir =>'GeneralLedger', model => 'GLTransaction', right => 'import_ap' },
- 'draft' => { gen => 0, gltype => '', dir =>'Draft', model => 'Draft', right => 'xx' },
- 'csv_customer' => { gen => 1, gltype => '', dir =>'Reports', model => 'Customer', right => 'xx' },
- 'csv_vendor' => { gen => 1, gltype => '', dir =>'Reports', model => 'Vendor', right => 'xx' },
- 'shop_image' => { gen => 0, gltype => '', dir =>'ShopImages', model => 'Part', right => 'xx' },
- 'letter' => { gen => 7, gltype => '', dir =>'Letter', model => 'Letter', right => 'sales_letter_edit | purchase_letter_edit' },
+ 'sales_quotation' => { gen => 1, gltype => '', dir =>'SalesQuotation', model => 'Order', right => 'import_ar' },
+ 'sales_order' => { gen => 5, gltype => '', dir =>'SalesOrder', model => 'Order', right => 'import_ar' },
+ 'sales_delivery_order' => { gen => 1, gltype => '', dir =>'SalesDeliveryOrder', model => 'DeliveryOrder', right => 'import_ar' },
+ 'invoice' => { gen => 1, gltype => 'ar', dir =>'SalesInvoice', model => 'Invoice', right => 'import_ar' },
+ 'invoice_for_advance_payment' => { gen => 1, gltype => 'ar', dir =>'SalesInvoice', model => 'Invoice', right => 'import_ar' },
+ 'final_invoice' => { gen => 1, gltype => 'ar', dir =>'SalesInvoice', model => 'Invoice', right => 'import_ar' },
+ 'credit_note' => { gen => 1, gltype => '', dir =>'CreditNote', model => 'Invoice', right => 'import_ar' },
+ 'request_quotation' => { gen => 7, gltype => '', dir =>'RequestForQuotation', model => 'Order', right => 'import_ap' },
+ 'purchase_order' => { gen => 7, gltype => '', dir =>'PurchaseOrder', model => 'Order', right => 'import_ap' },
+ 'purchase_delivery_order' => { gen => 7, gltype => '', dir =>'PurchaseDeliveryOrder',model => 'DeliveryOrder', right => 'import_ap' },
+ 'purchase_invoice' => { gen => 6, gltype => 'ap', dir =>'PurchaseInvoice', model => 'PurchaseInvoice',right => 'import_ap' },
+ 'vendor' => { gen => 0, gltype => '', dir =>'Vendor', model => 'Vendor', right => 'xx' },
+ 'customer' => { gen => 1, gltype => '', dir =>'Customer', model => 'Customer', right => 'xx' },
+ 'project' => { gen => 0, gltype => '', dir =>'Project', model => 'Project', right => 'xx' },
+ 'part' => { gen => 0, gltype => '', dir =>'Part', model => 'Part', right => 'xx' },
+ 'gl_transaction' => { gen => 6, gltype => 'gl', dir =>'GeneralLedger', model => 'GLTransaction', right => 'import_ap' },
+ 'draft' => { gen => 0, gltype => '', dir =>'Draft', model => 'Draft', right => 'xx' },
+ 'csv_customer' => { gen => 1, gltype => '', dir =>'Reports', model => 'Customer', right => 'xx' },
+ 'csv_vendor' => { gen => 1, gltype => '', dir =>'Reports', model => 'Vendor', right => 'xx' },
+ 'shop_image' => { gen => 0, gltype => '', dir =>'ShopImages', model => 'Part', right => 'xx' },
+ 'letter' => { gen => 7, gltype => '', dir =>'Letter', model => 'Letter', right => 'sales_letter_edit | purchase_letter_edit' },
);
#--- 4 locale ---#
__PACKAGE__->run_before('check_auth');
__PACKAGE__->run_before('recalc',
- only => [ qw(save save_as_new save_and_delivery_order save_and_invoice save_and_ap_transaction
+ only => [ qw(save save_as_new save_and_delivery_order save_and_invoice save_and_invoice_for_advance_payment save_and_final_invoice save_and_ap_transaction
print send_email) ]);
__PACKAGE__->run_before('get_unalterable_data',
- only => [ qw(save save_as_new save_and_delivery_order save_and_invoice save_and_ap_transaction
+ only => [ qw(save save_as_new save_and_delivery_order save_and_invoice save_and_invoice_for_advance_payment save_and_final_invoice save_and_ap_transaction
print send_email) ]);
#
);
}
+sub action_save_and_invoice_for_advance_payment {
+ my ($self) = @_;
+
+ $self->save_and_redirect_to(
+ controller => 'oe.pl',
+ action => 'oe_invoice_from_order',
+ new_invoice_type => 'invoice_for_advance_payment',
+ );
+}
+
+sub action_save_and_final_invoice {
+ my ($self) = @_;
+
+ $self->save_and_redirect_to(
+ controller => 'oe.pl',
+ action => 'oe_invoice_from_order',
+ new_invoice_type => 'final_invoice',
+ );
+}
+
# workflow from sales order to sales quotation
sub action_sales_quotation {
$_[0]->workflow_sales_or_request_for_quotation();
my @req_trans_cost_art = qw(kivi.Order.check_transport_cost_article_presence) x!!$::instance_conf->get_transport_cost_reminder_article_number_id;
my @req_cusordnumber = qw(kivi.Order.check_cusordnumber_presence) x($self->type eq sales_order_type() && $::instance_conf->get_order_warn_no_cusordnumber);
+ my $has_invoice_for_advance_payment;
+ if ($self->order->id && $self->type eq sales_order_type()) {
+ my $lr = $self->order->linked_records(direction => 'to', to => ['Invoice']);
+ $has_invoice_for_advance_payment = any {'SL::DB::Invoice' eq ref $_ && "invoice_for_advance_payment" eq $_->type} @$lr;
+ }
+
+ my $has_final_invoice;
+ if ($self->order->id && $self->type eq sales_order_type()) {
+ my $lr = $self->order->linked_records(direction => 'to', to => ['Invoice']);
+ $has_final_invoice = any {'SL::DB::Invoice' eq ref $_ && "final_invoice" eq $_->type} @$lr;
+ }
+
for my $bar ($::request->layout->get('actionbar')) {
$bar->add(
combobox => [
@req_trans_cost_art, @req_cusordnumber,
],
],
+ action => [
+ ($has_invoice_for_advance_payment ? t8('Save and Further Invoice for Advance Payment') : t8('Save and Invoice for Advance Payment')),
+ call => [ 'kivi.Order.save', 'save_and_invoice_for_advance_payment', $::instance_conf->get_order_warn_duplicate_parts ],
+ checks => [ 'kivi.Order.check_save_active_periodic_invoices',
+ @req_trans_cost_art, @req_cusordnumber,
+ ],
+ disabled => $has_final_invoice ? t8('This order has already a final invoice.')
+ : undef,
+ only_if => (any { $self->type eq $_ } (sales_order_type())),
+ ],
+ action => [
+ t8('Save and Final Invoice'),
+ call => [ 'kivi.Order.save', 'save_and_final_invoice', $::instance_conf->get_order_warn_duplicate_parts ],
+ checks => [ 'kivi.Order.check_save_active_periodic_invoices',
+ @req_trans_cost_art, @req_cusordnumber,
+ ],
+ disabled => $has_final_invoice ? t8('This order has already a final invoice.')
+ : undef,
+ only_if => (any { $self->type eq $_ } (sales_order_type())) && $has_invoice_for_advance_payment,
+ ],
action => [
t8('Save and AP Transaction'),
call => [ 'kivi.Order.save', 'save_and_ap_transaction', $::instance_conf->get_order_warn_duplicate_parts ],
sales_quotation => 'OrderItem',
request_quotation => 'OrderItem',
invoice => 'InvoiceItem',
+ invoice_for_advance_payment => 'InvoiceItem',
+ final_invoice => 'InvoiceItem',
purchase_invoice => 'InvoiceItem',
credit_note => 'InvoiceItem',
purchase_delivery_order => 'DeliveryOrderItem',
};
# currency is either passed or use the invoice currency if it differs from the default currency
+ # TODO remove
my ($exchangerate,$currency);
if ($params{currency} || $params{currency_id} || $self->currency_id != $::instance_conf->get_currency_id) {
if ($params{currency} || $params{currency_id} ) { # currency was specified
$arap_booking->save;
push @new_acc_ids, $arap_booking->acc_trans_id;
+ # hook for invoice_for_advance_payment DATEV always pairs, acc_trans_id has to be higher than arap_booking ;-)
+ if ($self->invoice_type eq 'invoice_for_advance_payment') {
+ my $clearing_chart = SL::DB::Chart->new(id => $::instance_conf->get_advance_payment_clearing_chart_id)->load;
+ die "No Clearing Chart for Advance Payment" unless ref $clearing_chart eq 'SL::DB::Chart';
+
+ # what does ptc say
+ my %inv_calc = $self->calculate_prices_and_taxes();
+ my @trans_ids = keys %{ $inv_calc{amounts} };
+ die "Invalid state for advance payment more than one trans_id" if (scalar @trans_ids > 1);
+ my $entry = delete $inv_calc{amounts}{$trans_ids[0]};
+ my $tax;
+ if ($entry->{tax_id}) {
+ $tax = SL::DB::Manager::Tax->find_by(id => $entry->{tax_id}); # || die "Can't find tax with id " . $entry->{tax_id};
+ }
+ if ($tax and $tax->rate != 0) {
+ my ($netamount, $taxamount);
+ my $roundplaces = 2;
+ # we dont have a clue about skonto, that's why we use $arap_amount as taxincluded
+ ($netamount, $taxamount) = Form->calculate_tax($arap_amount, $tax->rate, 1, $roundplaces);
+ # for debugging database set
+ my $fullmatch = $netamount == $entry->{amount} ? '::netamount total true' : '';
+ 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;
+ die "No Transfer Chart for Advance Payment" unless ref $transfer_chart eq 'SL::DB::Chart';
+
+ my $arap_full_booking= SL::DB::AccTransaction->new(trans_id => $self->id,
+ chart_id => $clearing_chart->id,
+ chart_link => $clearing_chart->link,
+ amount => $arap_amount * -1, # full amount
+ transdate => $transdate_obj,
+ source => 'Automatic Tax Booking for Payment in Advance' . $fullmatch,
+ taxkey => 0,
+ tax_id => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
+ $arap_full_booking->save;
+ push @new_acc_ids, $arap_full_booking->acc_trans_id;
+
+ my $arap_tax_booking= SL::DB::AccTransaction->new(trans_id => $self->id,
+ chart_id => $transfer_chart->id,
+ chart_link => $transfer_chart->link,
+ amount => _round($netamount), # full amount
+ transdate => $transdate_obj,
+ source => 'Automatic Tax Booking for Payment in Advance' . $fullmatch,
+ taxkey => $tax->taxkey,
+ tax_id => $tax->id);
+ $arap_tax_booking->save;
+ push @new_acc_ids, $arap_tax_booking->acc_trans_id;
+
+ my $tax_booking= SL::DB::AccTransaction->new(trans_id => $self->id,
+ chart_id => $tax->chart_id,
+ chart_link => $tax->chart->link,
+ amount => _round($taxamount),
+ transdate => $transdate_obj,
+ source => 'Automatic Tax Booking for Payment in Advance' . $fullmatch,
+ taxkey => 0,
+ tax_id => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
+
+ $tax_booking->save;
+ push @new_acc_ids, $tax_booking->acc_trans_id;
+ }
+ }
$fx_gain_loss_amount *= -1 if $self->is_sales;
$self->paid($self->paid + _round($paid_amount) + $fx_gain_loss_amount) if $paid_amount;
$self->datepaid($transdate_obj);
my ($self) = @_;
return 'ar_transaction' if !$self->invoice;
+ return 'invoice_for_advance_payment_storno' if $self->type eq 'invoice_for_advance_payment' && $self->amount < 0 && $self->storno;
+ return 'invoice_for_advance_payment' if $self->type eq 'invoice_for_advance_payment';
+ return 'final_invoice' if $self->type eq 'final_invoice';
# stornoed credit_notes are still credit notes and not invoices
return 'credit_note' if $self->type eq 'credit_note' && $self->amount < 0;
return 'invoice_storno' if $self->type ne 'credit_note' && $self->amount < 0 && $self->storno;
return t8('Credit Note') if $self->invoice_type eq 'credit_note';
return t8('Invoice') . "(" . t8('Storno') . ")" if $self->invoice_type eq 'invoice_storno';
return t8('Credit Note') . "(" . t8('Storno') . ")" if $self->invoice_type eq 'credit_note_storno';
+ return t8('Invoice for Advance Payment') if $self->invoice_type eq 'invoice_for_advance_payment';
+ return t8('Invoice for Advance Payment') . "(" . t8('Storno') . ")" if $self->invoice_type eq 'invoice_for_advance_payment_storno';
+ return t8('Final Invoice') if $self->invoice_type eq 'final_invoice';
return t8('Invoice');
}
return t8('Credit note (one letter abbreviation)') if $self->invoice_type eq 'credit_note';
return t8('Invoice (one letter abbreviation)') . "(" . t8('Storno (one letter abbreviation)') . ")" if $self->invoice_type eq 'invoice_storno';
return t8('Credit note (one letter abbreviation)') . "(" . t8('Storno (one letter abbreviation)') . ")" if $self->invoice_type eq 'credit_note_storno';
+ return t8('Invoice for Advance Payment (one letter abbreviation)') if $self->invoice_type eq 'invoice_for_advance_payment';
+ return t8('Invoice for Advance Payment with Storno (abbreviation)') if $self->invoice_type eq 'invoice_for_advance_payment_storno';
+ return t8('Final Invoice (one letter abbreviation)') if $self->invoice_type eq 'final_invoice';
return t8('Invoice (one letter abbreviation)');
}
address_street1 => { type => 'text' },
address_street2 => { type => 'text' },
address_zipcode => { type => 'text' },
+ advance_payment_clearing_chart_id => { type => 'integer' },
+ advance_payment_taxable_19_id => { type => 'integer' },
+ advance_payment_taxable_7_id => { type => 'integer' },
allow_new_purchase_delivery_order => { type => 'boolean', default => 'true', not_null => 1 },
allow_new_purchase_invoice => { type => 'boolean', default => 'true', not_null => 1 },
allow_sales_invoice_from_sales_order => { type => 'boolean', default => 'true', not_null => 1 },
#
my %type_to_path = (
- sales_quotation => 'angebote',
- sales_order => 'bestellungen',
- request_quotation => 'anfragen',
- purchase_order => 'lieferantenbestellungen',
- sales_delivery_order => 'verkaufslieferscheine',
- purchase_delivery_order => 'einkaufslieferscheine',
- credit_note => 'gutschriften',
- invoice => 'rechnungen',
- purchase_invoice => 'einkaufsrechnungen',
- part => 'waren',
- service => 'dienstleistungen',
- assembly => 'erzeugnisse',
- letter => 'briefe',
- general_ledger => 'dialogbuchungen',
- gl_transaction => 'dialogbuchungen',
- accounts_payable => 'kreditorenbuchungen',
- shop_image => 'shopbilder',
- customer => 'kunden',
- vendor => 'lieferanten',
+ sales_quotation => 'angebote',
+ sales_order => 'bestellungen',
+ request_quotation => 'anfragen',
+ purchase_order => 'lieferantenbestellungen',
+ sales_delivery_order => 'verkaufslieferscheine',
+ purchase_delivery_order => 'einkaufslieferscheine',
+ credit_note => 'gutschriften',
+ invoice => 'rechnungen',
+ invoice_for_advance_payment => 'rechnungen',
+ final_invoice => 'rechnungen',
+ purchase_invoice => 'einkaufsrechnungen',
+ part => 'waren',
+ service => 'dienstleistungen',
+ assembly => 'erzeugnisse',
+ letter => 'briefe',
+ general_ledger => 'dialogbuchungen',
+ gl_transaction => 'dialogbuchungen',
+ accounts_payable => 'kreditorenbuchungen',
+ shop_image => 'shopbilder',
+ customer => 'kunden',
+ vendor => 'lieferanten',
);
my %type_to_model = (
- sales_quotation => 'Order',
- sales_order => 'Order',
- request_quotation => 'Order',
- purchase_order => 'Order',
- sales_delivery_order => 'DeliveryOrder',
- purchase_delivery_order => 'DeliveryOrder',
- credit_note => 'Invoice',
- invoice => 'Invoice',
- purchase_invoice => 'PurchaseInvoice',
- part => 'Part',
- service => 'Part',
- assembly => 'Part',
- letter => 'Letter',
- general_ledger => 'GLTransaction',
- gl_transaction => 'GLTransaction',
- accounts_payable => 'GLTransaction',
- shop_image => 'Part',
- customer => 'Customer',
- vendor => 'Vendor',
+ sales_quotation => 'Order',
+ sales_order => 'Order',
+ request_quotation => 'Order',
+ purchase_order => 'Order',
+ sales_delivery_order => 'DeliveryOrder',
+ purchase_delivery_order => 'DeliveryOrder',
+ credit_note => 'Invoice',
+ invoice => 'Invoice',
+ invoice_for_advance_payment => 'Invoice',
+ final_invoice => 'Invoice',
+ purchase_invoice => 'PurchaseInvoice',
+ part => 'Part',
+ service => 'Part',
+ assembly => 'Part',
+ letter => 'Letter',
+ general_ledger => 'GLTransaction',
+ gl_transaction => 'GLTransaction',
+ accounts_payable => 'GLTransaction',
+ shop_image => 'Part',
+ customer => 'Customer',
+ vendor => 'Vendor',
);
my %model_to_number = (
local $::locale = Locale->new($self->{recipient_locale});
my %formname_translations = (
- bin_list => $main::locale->text('Bin List'),
- credit_note => $main::locale->text('Credit Note'),
- invoice => $main::locale->text('Invoice'),
- invoice_copy => $main::locale->text('Invoice Copy'),
- pick_list => $main::locale->text('Pick List'),
- proforma => $main::locale->text('Proforma Invoice'),
- purchase_order => $main::locale->text('Purchase Order'),
- request_quotation => $main::locale->text('RFQ'),
- sales_order => $main::locale->text('Confirmation'),
- sales_quotation => $main::locale->text('Quotation'),
- storno_invoice => $main::locale->text('Storno Invoice'),
- sales_delivery_order => $main::locale->text('Delivery Order'),
- purchase_delivery_order => $main::locale->text('Delivery Order'),
- dunning => $main::locale->text('Dunning'),
- dunning1 => $main::locale->text('Payment Reminder'),
- dunning2 => $main::locale->text('Dunning'),
- dunning3 => $main::locale->text('Last Dunning'),
- dunning_invoice => $main::locale->text('Dunning Invoice'),
- letter => $main::locale->text('Letter'),
- ic_supply => $main::locale->text('Intra-Community supply'),
- statement => $main::locale->text('Statement'),
+ bin_list => $main::locale->text('Bin List'),
+ credit_note => $main::locale->text('Credit Note'),
+ invoice => $main::locale->text('Invoice'),
+ invoice_copy => $main::locale->text('Invoice Copy'),
+ invoice_for_advance_payment => $main::locale->text('Invoice for Advance Payment'),
+ final_invoice => $main::locale->text('Final Invoice'),
+ pick_list => $main::locale->text('Pick List'),
+ proforma => $main::locale->text('Proforma Invoice'),
+ purchase_order => $main::locale->text('Purchase Order'),
+ request_quotation => $main::locale->text('RFQ'),
+ sales_order => $main::locale->text('Confirmation'),
+ sales_quotation => $main::locale->text('Quotation'),
+ storno_invoice => $main::locale->text('Storno Invoice'),
+ sales_delivery_order => $main::locale->text('Delivery Order'),
+ purchase_delivery_order => $main::locale->text('Delivery Order'),
+ dunning => $main::locale->text('Dunning'),
+ dunning1 => $main::locale->text('Payment Reminder'),
+ dunning2 => $main::locale->text('Dunning'),
+ dunning3 => $main::locale->text('Last Dunning'),
+ dunning_invoice => $main::locale->text('Dunning Invoice'),
+ letter => $main::locale->text('Letter'),
+ ic_supply => $main::locale->text('Intra-Community supply'),
+ statement => $main::locale->text('Statement'),
);
$main::lxdebug->leave_sub();
my ($self) = @_;
my $prefix =
- (first { $self->{type} eq $_ } qw(invoice credit_note)) ? 'inv'
- : ($self->{type} =~ /_quotation$/) ? 'quo'
- : ($self->{type} =~ /_delivery_order$/) ? 'do'
- : ($self->{type} =~ /letter/) ? 'letter'
- : 'ord';
+ (first { $self->{type} eq $_ } qw(invoice invoice_for_advance_payment final_invoice credit_note)) ? 'inv'
+ : ($self->{type} =~ /_quotation$/) ? 'quo'
+ : ($self->{type} =~ /_delivery_order$/) ? 'do'
+ : ($self->{type} =~ /letter/) ? 'letter'
+ : 'ord';
# better default like this?
# : ($self->{type} =~ /(sales|purcharse)_order/ : 'ord';
my $attachment_filename = $main::locale->unquote_special_chars('HTML', $self->get_formname_translation());
my $prefix = $self->get_number_prefix_for_type();
- if ($self->{preview} && (first { $self->{type} eq $_ } qw(invoice credit_note))) {
+ if ($self->{preview} && (first { $self->{type} eq $_ } qw(invoice invoice_for_advance_payment final_invoice credit_note))) {
$attachment_filename .= ' (' . $recipient_locale->text('Preview') . ')' . $self->get_extension_for_format();
} elsif ($attachment_filename && $self->{"${prefix}number"}) {
# $main::locale->text('UNDO TRANSFER')
# $main::locale->text('UNIMPORT')
# $main::locale->text('invoice')
+# $main::locale->text('invoice_for_advance_payment')
+# $main::locale->text('final_invoice')
# $main::locale->text('proforma')
# $main::locale->text('sales_order')
# $main::locale->text('pick_list')
($form->{type} eq 'invoice' && $form->{storno}) ? (
opthash("storno_invoice", $form->{PD}{storno_invoice}, $locale->text('Storno Invoice')),
) : undef,
+ ($form->{type} eq 'invoice_for_advance_payment') ? (
+ opthash("invoice_for_advance_payment", $form->{PD}{invoice_for_advance_payment}, $locale->text('Invoice for Advance Payment')),
+ ) : undef,
+ ($form->{type} eq 'final_invoice') ? (
+ opthash("final_invoice", $form->{PD}{final_invoice}, $locale->text('Final Invoice')),
+ ) : undef,
($form->{type} =~ /_delivery_order$/) ? (
opthash($form->{type}, $form->{PD}{$form->{type}}, $locale->text('Delivery Order')),
opthash('pick_list', $form->{PD}{pick_list}, $locale->text('Pick List')),
# transdate madness.
my $transdate = "";
- if (($form->{type} eq "invoice") or ($form->{type} eq "credit_note") or ($form->{script} eq 'ir.pl')) {
+ if ( (any {$form->{type} eq $_} qw(invoice credit_note invoice_for_advance_payment final_invoice)) or ($form->{script} eq 'ir.pl') ) {
# use deliverydate for sales and purchase invoice, if it exists
# also use deliverydate for credit notes
$transdate = $form->{tax_point} || $form->{deliverydate} || $form->{invdate};
package IS;
-use List::Util qw(max);
+use List::Util qw(max sum0);
+use List::MoreUtils qw(any);
use Carp;
use SL::AM;
use SL::IC;
use SL::IO;
use SL::TransNumber;
+use SL::DB::Chart;
use SL::DB::Default;
use SL::DB::Draft;
use SL::DB::Tax;
my @payment_arrays = qw(payment paymentaccount paymentdate paymentsource paymentmemo);
- map { $form->{TEMPLATE_ARRAYS}->{$_} = [] } (@arrays, @tax_arrays, @payment_arrays, @prepared_arrays);
+ my @invoices_for_advance_payment_arrays = qw(iap_invnumber iap_transdate
+ iap_amount iap_amount_nofmt
+ iap_taxamount iap_taxamount_nofmt
+ iap_open_amount iap_open_amount_nofmt);
+
+ map { $form->{TEMPLATE_ARRAYS}->{$_} = [] } (@arrays, @tax_arrays, @payment_arrays, @prepared_arrays, @invoices_for_advance_payment_arrays);
my $totalweight = 0;
foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
2
);
+ $form->{rounding_nofmt} = $form->{rounding};
+ $form->{total_nofmt} = $form->{total};
+ $form->{invtotal_nofmt} = $form->{invtotal};
+ $form->{paid_nofmt} = $form->{paid};
+
$form->{rounding} = $form->format_amount($myconfig, $form->{rounding}, 2);
$form->{total} = $form->format_amount($myconfig, $form->{invtotal} - $form->{paid}, 2);
$form->{invtotal} = $form->format_amount($myconfig, $form->{invtotal}, 2);
$form->{username} = $myconfig->{name};
$form->{$_} = $form->format_amount($myconfig, $form->{$_}, 2) for @separate_totals;
+ my $id_for_iap = $form->{convert_from_oe_ids} || $form->{convert_from_ar_ids} || $form->{id};
+ my $from_order = !!$form->{convert_from_oe_ids};
+ foreach my $invoice_for_advance_payment (@{$self->_get_invoices_for_advance_payment($id_for_iap, $from_order)}) {
+ # Collect VAT of invoices for advance payment.
+ # Set sellprices to fxsellprices for items, because
+ # the PriceTaxCalculator sets fxsellprice from sellprice before calculating.
+ $_->sellprice($_->fxsellprice) for @{$invoice_for_advance_payment->items};
+ my %pat = $invoice_for_advance_payment->calculate_prices_and_taxes;
+ my $taxamount = sum0 values %{ $pat{taxes_by_tax_id} };
+
+ push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_$_"} }, $invoice_for_advance_payment->$_) for qw(invnumber transdate);
+ push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_amount_nofmt"} }, $invoice_for_advance_payment->amount);
+ push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_amount"} }, $invoice_for_advance_payment->amount_as_number);
+ push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_taxamount_nofmt"} }, $taxamount);
+ push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_taxamount"} }, $form->format_amount($myconfig, $taxamount, 2));
+
+ my $open_amount = $form->round_amount($invoice_for_advance_payment->open_amount, 2);
+ push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_open_amount_nofmt"} }, $open_amount);
+ push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_open_amount"} }, $form->format_amount($myconfig, $open_amount, 2));
+
+ $form->{iap_amount_nofmt} += $invoice_for_advance_payment->amount;
+ $form->{iap_taxamount_nofmt} += $taxamount;
+ $form->{iap_open_amount_nofmt} += $open_amount;
+ $form->{iap_existing} = 1;
+ }
+ $form->{iap_amount} = $form->format_amount($myconfig, $form->{iap_amount_nofmt}, 2);
+ $form->{iap_taxamount} = $form->format_amount($myconfig, $form->{iap_taxamount_nofmt}, 2);
+ $form->{iap_open_amount} = $form->format_amount($myconfig, $form->{iap_open_amount_nofmt}, 2);
+
+ $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);
+
$main::lxdebug->leave_sub();
}
my $all_units = AM->retrieve_units($myconfig, $form);
+ my $already_booked = !!$form->{id};
+
if (!$payments_only) {
if ($form->{storno}) {
_delete_transfers($dbh, $form, $form->{storno_id});
# entsprechend auch beim Bestimmen des Steuerschlüssels in Taxkey.pm berücksichtigen
my $taxdate = $form->{tax_point} ||$form->{deliverydate} || $form->{invdate};
+ # Sanity checks for invoices for advance payment and final invoices
+ my $advance_payment_clearing_chart;
+ if (any { $_ eq $form->{type} } qw(invoice_for_advance_payment final_invoice)) {
+ $advance_payment_clearing_chart = SL::DB::Chart->new(id => $::instance_conf->get_advance_payment_clearing_chart_id)->load;
+ die "No Clearing Chart for Advance Payment" unless ref $advance_payment_clearing_chart eq 'SL::DB::Chart';
+
+ my @current_taxaccounts = (split(/ /, $form->{taxaccounts}));
+ die 'Wrong call: Cannot post invoice for advance payment or final invoice with more than one tax' if (scalar @current_taxaccounts > 1);
+
+ my @trans_ids = keys %{ $form->{amount} };
+ if (scalar @trans_ids > 1) {
+ require Data::Dumper;
+ die "Invalid state for advance payment more than one trans_id " . Dumper($form->{amount});
+ }
+ }
+
+ my $iap_amounts;
+ if ($form->{type} eq 'final_invoice') {
+ my $id_for_iap = $form->{convert_from_oe_ids} || $form->{convert_from_ar_ids} || $form->{id};
+ my $from_order = !!$form->{convert_from_oe_ids};
+ my $invoices_for_advance_payment = $self->_get_invoices_for_advance_payment($id_for_iap, $from_order);
+ if (scalar @$invoices_for_advance_payment > 0) {
+ # reverse booking for invoices for advance payment
+ foreach my $invoice_for_advance_payment (@$invoices_for_advance_payment) {
+ # delete ?
+ # --> is implemented below (bookings are marked in memo field)
+ #
+ # TODO: helper table acc_trans_advance_payment
+ # trans_id for final invoice connects to acc_trans_id here
+ # my $booking = SL::DB::AccTrans->new( ...)
+ # --> helper table not nessessary because of mark in memo field
+ #
+ # TODO: If final_invoice change (delete storno) delete all connectin acc_trans entries, if
+ # period is not closed
+ # --> no problem because gldate of reverse booking is date of final invoice
+ # if deletion of final invoice is allowed, reverting bookings in invoices
+ # for advance payment are allowed, too.
+ # $booking->id, $self->id in helper table
+ if (!$already_booked) {
+ # move all netamount to correct transfer chart (19% or 7%)
+ my %inv_calc = $invoice_for_advance_payment->calculate_prices_and_taxes();
+ my @trans_ids = keys %{ $inv_calc{amounts} };
+ die "Invalid state for advance payment invoice,more than one trans_id" if (scalar @trans_ids > 1);
+ my $entry = delete $inv_calc{amounts}{$trans_ids[0]};
+ my $tax;
+ if ($entry->{tax_id}) {
+ $tax = SL::DB::Manager::Tax->find_by(id => $entry->{tax_id}); # || die "Can't find tax with id " . $entry->{tax_id};
+ }
+ # no tax, no prob
+ if ($tax and $tax->rate != 0) {
+ 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;
+ die "No Transfer Chart for Advance Payment" unless ref $transfer_chart eq 'SL::DB::Chart';
+ $form->{amount}->{$invoice_for_advance_payment->id}->{$transfer_chart->accno} = -1 * $invoice_for_advance_payment->netamount;
+ $form->{memo} ->{$invoice_for_advance_payment->id}->{$transfer_chart->accno} = 'reverse booking by final invoice';
+ # AR
+ $form->{amount}->{$invoice_for_advance_payment->id}->{$form->{AR}} = $invoice_for_advance_payment->netamount;
+ $form->{memo} ->{$invoice_for_advance_payment->id}->{$form->{AR}} = 'reverse booking by final invoice';
+ }
+ }
+
+ # VAT for invoices for advance payment is booked on payment of these. So do not book this VAT for final invoice.
+ # And book the amount of the invoices for advance payment with taxkey 0 (see below).
+ # Collect amounts and VAT of invoices for advance payment.
+
+ # Set sellprices to fxsellprices for items, because
+ # the PriceTaxCalculator sets fxsellprice from sellprice before calculating.
+ $_->sellprice($_->fxsellprice) for @{$invoice_for_advance_payment->items};
+ my %pat = $invoice_for_advance_payment->calculate_prices_and_taxes;
+
+ foreach my $tax_chart_id (keys %{ $pat{taxes_by_chart_id} }) {
+ my $tax_accno = SL::DB::Chart->load_cached($tax_chart_id)->accno;
+ $form->{amount}{ $form->{id} }{$tax_accno} -= $pat{taxes_by_chart_id}->{$tax_chart_id};
+ $form->{amount}{ $form->{id} }{$form->{AR}} += $pat{taxes_by_chart_id}->{$tax_chart_id};
+ }
+
+ foreach my $amount_chart_id (keys %{ $pat{amounts} }) {
+ my $amount_accno = SL::DB::Chart->load_cached($amount_chart_id)->accno;
+ $iap_amounts->{$amount_accno} += $pat{amounts}->{$amount_chart_id}->{amount};
+ $form->{amount}{ $form->{id} }{$amount_accno} -= $pat{amounts}->{$amount_chart_id}->{amount};
+ }
+ }
+ }
+ }
+
+ if ($form->{type} eq 'invoice_for_advance_payment') {
+ # get gross and move to clearing chart - delete everything else
+ # 1. gross
+ my $gross = $form->{amount}{ $form->{id} }{$form->{AR}};
+ # 2. destroy
+ undef $form->{amount}{ $form->{id} };
+ # 3. rebuild
+ $form->{amount}{ $form->{id} }{$form->{AR}} = $gross;
+ $form->{amount}{ $form->{id} }{$advance_payment_clearing_chart->accno} = $gross * -1;
+ # 4. no cogs, hopefully not commonly used at all
+ undef $form->{amount_cogs};
+ }
+
foreach my $trans_id (keys %{ $form->{amount_cogs} }) {
foreach my $accno (keys %{ $form->{amount_cogs}{$trans_id} }) {
next unless ($form->{expense_inventory} =~ /\Q$accno\E/);
if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
$query =
- qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
+ qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link, memo)
VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
(SELECT tax_id
FROM taxkeys
AND startdate <= ?
ORDER BY startdate DESC LIMIT 1),
?,
- (SELECT link FROM chart WHERE accno = ?))|;
- @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_date($taxdate), $accno, conv_date($taxdate), conv_i($project_id), $accno);
+ (SELECT link FROM chart WHERE accno = ?),
+ ?)|;
+ @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_date($taxdate), $accno, conv_date($taxdate), conv_i($project_id), $accno, $form->{memo}{$trans_id}{$accno});
do_query($form, $dbh, $query, @values);
$form->{amount}{$trans_id}{$accno} = 0;
}
if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
$query =
- qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
+ qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link, memo)
VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
(SELECT tax_id
FROM taxkeys
AND startdate <= ?
ORDER BY startdate DESC LIMIT 1),
?,
- (SELECT link FROM chart WHERE accno = ?))|;
- @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_date($taxdate), $accno, conv_date($taxdate), conv_i($project_id), $accno);
+ (SELECT link FROM chart WHERE accno = ?),
+ ?)|;
+ @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_date($taxdate), $accno, conv_date($taxdate), conv_i($project_id), $accno,$form->{memo}{$trans_id}{$accno});
do_query($form, $dbh, $query, @values);
}
}
}
}
+ # Book the amount of the invoices for advance payment with taxkey 0 (see below).
+ if ($form->{type} eq 'final_invoice' && $iap_amounts) {
+ foreach my $accno (keys %$iap_amounts) {
+ $query =
+ qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
+ VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, (SELECT id FROM tax WHERE taxkey=0), 0, ?, (SELECT link FROM chart WHERE accno = ?))|;
+ @values = (conv_i($form->{id}), $accno, $iap_amounts->{$accno}, conv_date($form->{invdate}), conv_i($project_id), $accno);
+ do_query($form, $dbh, $query, @values);
+ }
+ }
+
# deduct payment differences from diff
for my $i (1 .. $form->{paidaccounts}) {
if ($form->{"paid_$i"} != 0) {
return 1;
}
+sub _get_invoices_for_advance_payment {
+ my ($self, $id, $id_is_from_order) = @_;
+
+ return [] if !$id;
+
+ # Search all related invoices for advance payment.
+ # Case 1:
+ # (order) -> invoice for adv. payment 1 -> invoice for adv. payment 2 -> invoice for adv. payment 3 -> final invoice
+ #
+ # Case 2:
+ # order -> invoice for adv. payment 1
+ # | |`-> invoice for adv. payment 2
+ # | `--> invoice for adv. payment 3
+ # `----> final invoice
+ #
+ # The id is currently that from the last invoice for adv. payment (3 in this example),
+ # that from the final invoice or that from the order.
+
+ my $invoice_obj;
+ my $order_obj;
+ my $links;
+
+ if (!$id_is_from_order) {
+ $invoice_obj = SL::DB::Invoice->load_cached($id*1);
+ $links = $invoice_obj->linked_records(direction => 'from', from => ['Order']);
+ $order_obj = $links->[0];
+ } else {
+ $order_obj = SL::DB::Order->load_cached($id*1);
+ }
+
+ if ($order_obj) {
+ $links = $order_obj ->linked_records(direction => 'to', to => ['Invoice']);
+ } else {
+ $links = $invoice_obj->linked_records(direction => 'from', from => ['Invoice'], recursive => 1);
+ }
+
+ my @related_invoices = grep {'SL::DB::Invoice' eq ref $_ && "invoice_for_advance_payment" eq $_->type} @$links;
+
+ push @related_invoices, $invoice_obj if !$order_obj && "invoice_for_advance_payment" eq $invoice_obj->type;
+
+ return \@related_invoices;
+}
+
+
sub transfer_out {
$::lxdebug->enter_sub;
do_query($form, $dbh, qq|UPDATE ar SET storno = 'f', paid = 0 WHERE id = ?|, $invoice_id);
}
+ # if we delete a final invoice, the reverse bookings for the clearing account in the invoice for advance payment
+ # must be deleted as well
+ my $invoices_for_advance_payment = $self->_get_invoices_for_advance_payment($form->{id});
+
+ # Todo: allow only if invoice for advance payment is not paid.
+ # die if any { $_->paid } for @$invoices_for_advance_payment;
+ my @trans_ids_to_consider = map { $_->id } @$invoices_for_advance_payment;
+ if (scalar @trans_ids_to_consider) {
+ my $query = sprintf 'DELETE FROM acc_trans WHERE memo LIKE ? AND trans_id IN (%s)', join ', ', ("?") x scalar @trans_ids_to_consider;
+ do_query($form, $dbh, $query, 'reverse booking by final invoice', @trans_ids_to_consider);
+ }
+
# delete spool files
my @spoolfiles = selectall_array_query($form, $dbh, qq|SELECT spoolfile FROM status WHERE trans_id = ?|, @values);
scalar => [ qw(type id number save dbh dbh_provided business_id) ],
);
-my @SUPPORTED_TYPES = qw(invoice credit_note customer vendor sales_delivery_order purchase_delivery_order sales_order purchase_order sales_quotation request_quotation part service assembly assortment letter);
+my @SUPPORTED_TYPES = qw(invoice invoice_for_advance_payment final_invoice credit_note customer vendor sales_delivery_order purchase_delivery_order sales_order purchase_order sales_quotation request_quotation part service assembly assortment letter);
sub new {
my $class = shift;
my $type = $self->type;
my %filters = ( where => '' );
- if (any { $_ eq $type } qw(invoice credit_note)) {
+ if (any { $_ eq $type } qw(invoice invoice_for_advance_payment final_invoice credit_note)) {
$filters{trans_number} = "invnumber";
$filters{numberfield} = $type eq 'credit_note' ? "cnnumber" : "invnumber";
$filters{table} = "ar";
);
my %type_to_path = (
- sales_quotation => 'angebote',
- sales_order => 'bestellungen',
- request_quotation => 'anfragen',
- purchase_order => 'lieferantenbestellungen',
- sales_delivery_order => 'verkaufslieferscheine',
- purchase_delivery_order => 'einkaufslieferscheine',
- credit_note => 'gutschriften',
- invoice => 'rechnungen',
- purchase_invoice => 'einkaufsrechnungen',
- part => 'waren',
- service => 'dienstleistungen',
- assembly => 'erzeugnisse',
- letter => 'briefe',
- general_ledger => 'dialogbuchungen',
- accounts_payable => 'kreditorenbuchungen',
- customer => 'kunden',
- vendor => 'lieferanten',
- dunning => 'mahnungen',
+ sales_quotation => 'angebote',
+ sales_order => 'bestellungen',
+ request_quotation => 'anfragen',
+ purchase_order => 'lieferantenbestellungen',
+ sales_delivery_order => 'verkaufslieferscheine',
+ purchase_delivery_order => 'einkaufslieferscheine',
+ credit_note => 'gutschriften',
+ invoice => 'rechnungen',
+ invoice_for_advance_payment => 'rechnungen',
+ final_invoice => 'rechnungen',
+ purchase_invoice => 'einkaufsrechnungen',
+ part => 'waren',
+ service => 'dienstleistungen',
+ assembly => 'erzeugnisse',
+ letter => 'briefe',
+ general_ledger => 'dialogbuchungen',
+ accounts_payable => 'kreditorenbuchungen',
+ customer => 'kunden',
+ vendor => 'lieferanten',
+ dunning => 'mahnungen',
);
sub get_all_files {
my $is_storno = $ar->{storno} && $ar->{storno_id};
my $has_storno = $ar->{storno} && !$ar->{storno_id};
- $ar->{type} =
- $has_storno ? $locale->text("Invoice with Storno (abbreviation)") :
- $is_storno ? $locale->text("Storno (one letter abbreviation)") :
- $ar->{amount} < 0 ? $locale->text("Credit note (one letter abbreviation)") :
- $ar->{invoice} ? $locale->text("Invoice (one letter abbreviation)") :
- $locale->text("AR Transaction (abbreviation)");
+ if ($ar->{type} eq 'invoice_for_advance_payment') {
+ $ar->{type} =
+ $has_storno ? $locale->text("Invoice for Advance Payment with Storno (abbreviation)") :
+ $is_storno ? $locale->text("Storno (one letter abbreviation)") :
+ $locale->text("Invoice for Advance Payment (one letter abbreviation)");
+
+ } elsif ($ar->{type} eq 'final_invoice') {
+ $ar->{type} = t8('Final Invoice (one letter abbreviation)');
+
+ } else {
+ $ar->{type} =
+ $has_storno ? $locale->text("Invoice with Storno (abbreviation)") :
+ $is_storno ? $locale->text("Storno (one letter abbreviation)") :
+ $ar->{amount} < 0 ? $locale->text("Credit note (one letter abbreviation)") :
+ $ar->{invoice} ? $locale->text("Invoice (one letter abbreviation)") :
+ $locale->text("AR Transaction (abbreviation)");
+ }
map { $ar->{$_} = $form->format_amount(\%myconfig, $ar->{$_}, 2) } qw(netamount tax amount paid due marge_total marge_percent);
if ($form->{formname} eq "invoice") {
$form->{label} = $locale->text('Invoice');
}
+
+ if ($form->{formname} eq "invoice_for_advance_payment") {
+ $form->{label} = $locale->text('Invoice for Advance Payment');
+ }
+
+ if ($form->{formname} eq "final_invoice") {
+ $form->{label} = $locale->text('Final Invoice');
+ }
+
if ($form->{formname} eq 'sales_order') {
$inv = "ord";
$due = "req";
}
$form->{TEMPLATE_DRIVER_OPTIONS} = { };
- if (any { $form->{type} eq $_ } qw(sales_quotation sales_order sales_delivery_order invoice request_quotation purchase_order purchase_delivery_order credit_note)) {
+ if (any { $form->{type} eq $_ } qw(sales_quotation sales_order sales_delivery_order invoice invoice_for_advance_payment final_invoice request_quotation purchase_order purchase_delivery_order credit_note)) {
$form->{TEMPLATE_DRIVER_OPTIONS}->{variable_content_types} = $form->get_variable_content_types();
}
sales_quotation => 'OrderItem',
request_quotation => 'OrderItem',
invoice => 'InvoiceItem',
+ invoice_for_advance_payment => 'InvoiceItem',
+ final_invoice => 'InvoiceItem',
credit_note => 'InvoiceItem',
purchase_invoice => 'InvoiceItem',
purchase_delivery_order => 'DeliveryOrderItem',
use SL::IS;
use SL::OE;
use SL::MoreCommon qw(restore_form save_form);
+use SL::RecordLinks;
+
use Data::Dumper;
use DateTime;
-use List::MoreUtils qw(uniq);
+use List::MoreUtils qw(any uniq);
use List::Util qw(max sum);
use List::UtilsBy qw(sort_by);
use English qw(-no_match_vars);
if ($form->{storno}) {
$form->{title} = $locale->text('Add Storno Credit Note');
}
+
+ } elsif ($form->{type} eq "invoice_for_advance_payment") {
+ $form->{title} = $locale->text('Add Invoice for Advance Payment');
+
+ } elsif ($form->{type} eq "final_invoice") {
+ $form->{title} = $locale->text('Add Final Invoice');
+
} else {
$form->{title} = $locale->text('Add Sales Invoice');
if ($form->{type} eq "credit_note") {
$form->{title} = $locale->text('Edit Credit Note');
$form->{title} = $locale->text('Edit Storno Credit Note') if $form->{storno};
+
+ } elsif ($form->{type} eq "invoice_for_advance_payment") {
+ $form->{title} = $locale->text('Edit Invoice for Advance Payment');
+ $form->{title} = $locale->text('Edit Storno Invoice for Advance Payment') if $form->{storno};
+
+ } elsif ($form->{type} eq "final_invoice") {
+ $form->{title} = $locale->text('Edit Final Invoice');
+
} else {
$form->{title} = $locale->text('Edit Sales Invoice');
$form->{title} = $locale->text('Edit Storno Invoice') if $form->{storno};
if ($form->{type} eq "credit_note") {
$form->{type} = "credit_note";
$form->{formname} = "credit_note";
+
+ } elsif ($form->{type} eq "invoice_for_advance_payment") {
+ $form->{type} = "invoice_for_advance_payment";
+ $form->{formname} = "invoice_for_advance_payment";
+
+ } elsif ($form->{type} eq "final_invoice") {
+ $form->{type} = "final_invoice";
+ $form->{formname} = "final_invoice";
+
} elsif ($form->{formname} eq "proforma" ) {
$form->{type} = "invoice";
+
} else {
$form->{type} = "invoice";
$form->{formname} = "invoice";
if ($::instance_conf->get_warn_no_delivery_order_for_invoice && !$form->{id}) {
$warn_unlinked_delivery_order = 1 unless $form->{convert_from_do_ids};
}
+
+ my $has_further_invoice_for_advance_payment;
+ if ($form->{id} && $form->{type} eq "invoice_for_advance_payment") {
+ my $invoice_obj = SL::DB::Invoice->load_cached($form->{id});
+ my $lr = $invoice_obj->linked_records(direction => 'to', to => ['Invoice']);
+ $has_further_invoice_for_advance_payment = any {'SL::DB::Invoice' eq ref $_ && "invoice_for_advance_payment" eq $_->type} @$lr;
+ }
+
+ my $has_final_invoice;
+ if ($form->{id} && $form->{type} eq "invoice_for_advance_payment") {
+ my $invoice_obj = SL::DB::Invoice->load_cached($form->{id});
+ my $lr = $invoice_obj->linked_records(direction => 'to', to => ['Invoice']);
+ $has_final_invoice = any {'SL::DB::Invoice' eq ref $_ && "final_invoice" eq $_->invoice_type} @$lr;
+ }
+
+ my $is_invoice_for_advance_payment_from_order;
+ if ($form->{id} && $form->{type} eq "invoice_for_advance_payment") {
+ my $invoice_obj = SL::DB::Invoice->load_cached($form->{id});
+ my $lr = $invoice_obj->linked_records(direction => 'from', from => ['Order']);
+ $is_invoice_for_advance_payment_from_order = scalar @$lr >= 1;
+ }
+
for my $bar ($::request->layout->get('actionbar')) {
$bar->add(
action => [
: !$form->{id} ? t8('This invoice has not been posted yet.')
: $is_linked_bank_transaction ? t8('This transaction is linked with a bank transaction. Please undo and redo the bank transaction booking if needed.')
: undef,
+ only_if => $form->{type} ne "invoice_for_advance_payment",
],
action => [ t8('Mark as paid'),
submit => [ '#form', { action => "mark_as_paid" } ],
disabled => !$may_edit_create ? t8('You must not change this invoice.')
: !$form->{id} ? t8('This invoice has not been posted yet.')
: undef,
- only_if => $::instance_conf->get_is_show_mark_as_paid,
+ only_if => $::instance_conf->get_is_show_mark_as_paid && $form->{type} ne "invoice_for_advance_payment",
],
], # end of combobox "Post"
: !$form->{id} ? t8('This invoice has not been posted yet.')
: undef,
],
+ action => [
+ t8('Further Invoice for Advance Payment'),
+ submit => [ '#form', { action => "further_invoice_for_advance_payment" } ],
+ checks => [ 'kivi.validate_form' ],
+ disabled => !$may_edit_create ? t8('You must not change this invoice.')
+ : !$form->{id} ? t8('This invoice has not been posted yet.')
+ : $has_further_invoice_for_advance_payment ? t8('This invoice has already a further invoice for advanced payment.')
+ : $has_final_invoice ? t8('This invoice has already a final invoice.')
+ : $is_invoice_for_advance_payment_from_order ? t8('This invoice was added from an order. See there.')
+ : undef,
+ only_if => $form->{type} eq "invoice_for_advance_payment",
+ ],
+ action => [
+ t8('Final Invoice'),
+ submit => [ '#form', { action => "final_invoice" } ],
+ checks => [ 'kivi.validate_form' ],
+ disabled => !$may_edit_create ? t8('You must not change this invoice.')
+ : !$form->{id} ? t8('This invoice has not been posted yet.')
+ : $has_further_invoice_for_advance_payment ? t8('This invoice has a further invoice for advanced payment.')
+ : $has_final_invoice ? t8('This invoice has already a final invoice.')
+ : $is_invoice_for_advance_payment_from_order ? t8('This invoice was added from an order. See there.')
+ : undef,
+ only_if => $form->{type} eq "invoice_for_advance_payment",
+ ],
action => [
t8('Credit Note'),
submit => [ '#form', { action => "credit_note" } ],
$form->{"select$item"} =~ s/option>\Q$form->{$item}\E/option selected>$form->{$item}/;
}
- $TMPL_VAR{is_type_credit_note} = $form->{type} eq "credit_note";
- $TMPL_VAR{is_format_html} = $form->{format} eq 'html';
- $TMPL_VAR{dateformat} = $myconfig{dateformat};
- $TMPL_VAR{numberformat} = $myconfig{numberformat};
+ $TMPL_VAR{is_type_normal_invoice} = $form->{type} eq "invoice";
+ $TMPL_VAR{is_type_credit_note} = $form->{type} eq "credit_note";
+ $TMPL_VAR{is_format_html} = $form->{format} eq 'html';
+ $TMPL_VAR{dateformat} = $myconfig{dateformat};
+ $TMPL_VAR{numberformat} = $myconfig{numberformat};
# hiddens
$TMPL_VAR{HIDDENS} = [qw(
}
print $form->parse_html_template('is/form_footer', {
- is_type_credit_note => ($form->{type} eq "credit_note"),
- totalpaid => $totalpaid,
- paid_missing => $form->{invtotal} - $totalpaid,
- print_options => setup_sales_purchase_print_options(),
- show_storno => $form->{id} && !$form->{storno} && !IS->has_storno(\%myconfig, $form, "ar") && !$totalpaid,
- show_delete => ($::instance_conf->get_is_changeable == 2)
- ? ($form->current_date(\%myconfig) eq $form->{gldate})
- : ($::instance_conf->get_is_changeable == 1),
- today => DateTime->today,
- vc_obj => $form->{customer_id} ? SL::DB::Customer->load_cached($form->{customer_id}) : undef,
- shipto_cvars => $shipto_cvars,
+ is_type_normal_invoice => ($form->{type} eq "invoice"),
+ is_type_credit_note => ($form->{type} eq "credit_note"),
+ totalpaid => $totalpaid,
+ paid_missing => $form->{invtotal} - $totalpaid,
+ print_options => setup_sales_purchase_print_options(),
+ show_storno => $form->{id} && !$form->{storno} && !IS->has_storno(\%myconfig, $form, "ar") && !$totalpaid,
+ show_delete => ($::instance_conf->get_is_changeable == 2)
+ ? ($form->current_date(\%myconfig) eq $form->{gldate})
+ : ($::instance_conf->get_is_changeable == 1),
+ today => DateTime->today,
+ vc_obj => $form->{customer_id} ? SL::DB::Customer->load_cached($form->{customer_id}) : undef,
+ shipto_cvars => $shipto_cvars,
});
##print $form->parse_html_template('is/_payments'); # parser
##print $form->parse_html_template('webdav/_list'); # parser
$form->isblank("exchangerate", $locale->text('Exchangerate missing!'))
if ($form->{currency} ne $form->{defaultcurrency});
+ # advance payment allows only one tax
+ if ($form->{type} eq 'invoice_for_advance_payment') {
+ my @current_taxaccounts = (split(/ /, $form->{taxaccounts}));
+ $form->error($locale->text('Cannot post invoice for advance payment with more than one tax'))
+ if (scalar @current_taxaccounts > 1);
+ }
for my $i (1 .. $form->{paidaccounts}) {
if ($form->parse_amount(\%myconfig, $form->{"paid_$i"})) {
$main::lxdebug->leave_sub();
}
+sub further_invoice_for_advance_payment {
+ my $form = $main::form;
+ my %myconfig = %main::myconfig;
+
+ $main::auth->assert('invoice_edit');
+
+ delete @{ $form }{qw(printed emailed queued invnumber invdate exchangerate forex deliverydate datepaid_1 gldate_1 acc_trans_id_1 source_1 memo_1 paid_1 exchangerate_1 AP_paid_1 storno locked)};
+ $form->{convert_from_ar_ids} = $form->{id};
+ $form->{id} = '';
+ $form->{rowcount}--;
+ $form->{paidaccounts} = 1;
+ $form->{invdate} = $form->current_date(\%myconfig);
+ my $terms = get_payment_terms_for_invoice();
+ $form->{duedate} = $terms ? $terms->calc_date(reference_date => $form->{invdate})->to_kivitendo : $form->{invdate};
+ $form->{employee_id} = SL::DB::Manager::Employee->current->id;
+ $form->{forex} = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{invdate}, 'buy');
+ $form->{exchangerate} = $form->{forex} if $form->{forex};
+
+ $form->{"converted_from_invoice_id_$_"} = delete $form->{"invoice_id_$_"} for 1 .. $form->{"rowcount"};
+
+ &display_form;
+}
+
+sub final_invoice {
+ my $form = $main::form;
+ my %myconfig = %main::myconfig;
+
+ $main::auth->assert('invoice_edit');
+
+ my $related_invoices = IS->_get_invoices_for_advance_payment($form->{id});
+
+ delete @{ $form }{qw(printed emailed queued invnumber invdate exchangerate forex deliverydate datepaid_1 gldate_1 acc_trans_id_1 source_1 memo_1 paid_1 exchangerate_1 AP_paid_1 storno locked)};
+
+ $form->{convert_from_ar_ids} = $form->{id};
+ $form->{id} = '';
+ $form->{type} = 'final_invoice';
+ $form->{title} = t8('Edit Final Invoice');
+ $form->{paidaccounts} = 1;
+ $form->{invdate} = $form->current_date(\%myconfig);
+ my $terms = get_payment_terms_for_invoice();
+ $form->{duedate} = $terms ? $terms->calc_date(reference_date => $form->{invdate})->to_kivitendo : $form->{invdate};
+ $form->{employee_id} = SL::DB::Manager::Employee->current->id;
+ $form->{forex} = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{invdate}, 'buy');
+ $form->{exchangerate} = $form->{forex} if $form->{forex};
+
+ foreach my $i (1 .. $form->{"rowcount"}) {
+ delete $form->{"id_$i"};
+ delete $form->{"invoice_id_$i"};
+ delete $form->{"parts_id_$i"};
+ delete $form->{"partnumber_$i"};
+ delete $form->{"description_$i"};
+ }
+
+ remove_emptied_rows(1);
+
+ my $i = 0;
+ foreach my $ri (@$related_invoices) {
+ foreach my $item (@{$ri->items_sorted}) {
+ $i++;
+ $form->{"id_$i"} = $item->parts_id;
+ $form->{"partnumber_$i"} = $item->part->partnumber;
+ $form->{"discount_$i"} = $item->discount*100.0;
+ $form->{"sellprice_$i"} = $item->fxsellprice;
+ $form->{$_ . "_" . $i} = $item->$_ for qw(description longdescription qty price_factor_id unit active_price_source active_discount_source);
+
+ $form->{$_ . "_" . $i} = $form->format_amount(\%myconfig, $form->{$_ . "_" . $i}) for qw(qty sellprice discount);
+ }
+ }
+ $form->{rowcount} = $i;
+
+ update();
+ $::dispatcher->end_request;
+}
+
sub storno {
$main::lxdebug->enter_sub();
&prepare_invoice;
-
&display_form;
$main::lxdebug->leave_sub();
$::dispatcher->end_request;
}
- _oe_remove_delivered_or_billed_rows(id => $form->{id}, type => 'billed');
+ _oe_remove_delivered_or_billed_rows(id => $form->{id}, type => 'billed') if $form->{new_invoice_type} ne 'final_invoice';
$form->{cp_id} *= 1;
if ( $form->{type} eq 'sales_order'
|| $form->{type} eq 'sales_quotation') {
- $form->{title} = $locale->text('Add Sales Invoice');
+ $form->{title} = ($form->{new_invoice_type} eq 'invoice_for_advance_payment') ? $locale->text('Add Invoice for Advance Payment')
+ : ($form->{new_invoice_type} eq 'final_invoice') ? $locale->text('Add Final Invoice')
+ : $locale->text('Add Sales Invoice');
$form->{script} = 'is.pl';
$script = "is";
$buysell = 'buy';
# bo creates the id, reset it
map { delete $form->{$_} } qw(id subject message cc bcc printed emailed queued);
$form->{ $form->{vc} } =~ s/--.*//g;
- $form->{type} = "invoice";
+ $form->{type} = $form->{new_invoice_type} || "invoice";
# locale messages
$main::locale = Locale->new("$myconfig{countrycode}", "$script");
'Add Delivery Order' => 'Lieferschein erfassen',
'Add Document from \'#1\'' => 'Dokument von \'#1\' hinzufügen',
'Add Dunning' => 'Mahnung erzeugen',
+ 'Add Final Invoice' => 'Schlussrechnung erfassen',
'Add Follow-Up' => 'Wiedervorlage erstellen',
'Add Follow-Up for #1' => 'Wiedervorlage für #1 erstellen',
'Add General Ledger Transaction' => 'Dialogbuchen',
+ 'Add Invoice for Advance Payment' => 'Anzahlungsrechnung erfassen',
'Add Letter' => 'Brief hinzufügen',
'Add Part' => 'Ware erfassen',
'Add Price Factor' => 'Preisfaktor erfassen',
'Cannot post a transaction without a value!' => 'Eine Buchung ohne Betrag kann nicht vorgenommen werden!',
'Cannot post invoice and/or transfer out! Error message:' => 'Rechnung kann nicht gebucht oder es kann nicht ausgelagert werden. Fehlermeldung:',
'Cannot post invoice for a closed period!' => 'Das Rechnungsdatum fällt in einen abgeschlossen Zeitraum!',
+ 'Cannot post invoice for advance payment with more than one tax' => 'Anzahlungsrechnung mit mehr als einem Steuersatz kann nicht gebucht werden',
'Cannot post invoice!' => 'Rechnung kann nicht gebucht werden!',
'Cannot post payment for a closed period!' => 'Es können keine Zahlungen für abgeschlossene Bücher gebucht werden!',
'Cannot post payment!' => 'Zahlung kann nicht gebucht werden!',
'Cleared Balance' => 'abgeschlossen',
'Cleared/uncleared only' => 'Status abgeglichen',
'Clearing Tax Received (No 71)' => 'Verrechnung des Erstattungsbetrages erwünscht (Zeile 71)',
+ 'Clearing account for advance payments' => 'Verrechnungskonto für Anzahlungen',
'Client' => 'Mandant',
'Client #1' => 'Mandant #1',
'Client Configuration' => 'Mandantenkonfiguration',
'Edit Dunning Process Config' => 'Mahnwesenkonfiguration bearbeiten',
'Edit Employee #1' => 'Benutzer #1 bearbeiten',
'Edit Factur-X/ZUGFeRD notes' => 'Factur-X-/ZUGFeRD-Notizen bearbeiten',
+ 'Edit Final Invoice' => 'Schlussrechnung bearbeiten',
'Edit Follow-Up' => 'Wiedervorlage bearbeiten',
'Edit Follow-Up for #1' => 'Wiedervorlage für #1 bearbeiten',
'Edit General Ledger Transaction' => 'Buchung im Hauptbuch bearbeiten',
+ 'Edit Invoice for Advance Payment' => 'Anzahlungsrechnung bearbeiten',
'Edit Letter' => 'Brief bearbeiten',
'Edit Part' => 'Ware bearbeiten',
'Edit Preferences for #1' => 'Einstellungen von #1 bearbeiten',
'Edit Service' => 'Dienstleistung bearbeiten',
'Edit Storno Credit Note' => 'Storno Gutschrift bearbeiten',
'Edit Storno Invoice' => 'Stornorechnung bearbeiten',
+ 'Edit Storno Invoice for Advance Payment' => 'Storno-Anzahlungsrechnung bearbeiten',
'Edit User' => 'Benutzerdaten bearbeiten',
'Edit User Group' => 'Benutzergruppe bearbeiten',
'Edit Vendor' => 'Lieferant editieren',
'Filter for item variables' => 'Filter für benutzerdefinierte Artikelvariablen',
'Filter parts' => 'Artikel filtern',
'Filter record template' => 'Filter für Buchungsvorlagen',
+ 'Final Invoice' => 'Schlussrechnung',
+ 'Final Invoice (one letter abbreviation)' => 'F',
'Financial Controlling' => 'Finanzcontrolling',
'Financial Controlling Report' => 'Finanzcontrollingbericht',
'Financial Overview' => 'Finanzübersicht',
'Function block actions' => 'Funktionsblockaktionen',
'Function block number format' => 'Format der Funktionsblocknummerierung',
'Function/position' => 'Funktion/Position',
+ 'Further Invoice for Advance Payment' => 'Weitere Anzahlungsrechnung',
'GL Transaction' => 'Dialogbuchung',
'GL Transaction (abbreviation)' => 'DB',
'GL Transactions' => 'Dialogbuchungen',
'Invoice email and Contact Person' => 'E-Mail des Rechnungsempfängers und CC an Ansprechpartner',
'Invoice email settings' => 'E-Mail Rechnungsversand',
'Invoice filter' => 'Rechnungsfilter',
+ 'Invoice for Advance Payment' => 'Anzahlungsrechnung',
+ 'Invoice for Advance Payment (one letter abbreviation)' => 'A',
+ 'Invoice for Advance Payment with Storno (abbreviation)' => 'A(S)',
'Invoice for fees' => 'Rechnung über Gebühren',
'Invoice has already been storno\'d!' => 'Diese Rechnung wurde bereits storniert.',
'Invoice number' => 'Rechnungsnummer',
'Save and Close' => 'Speichern und schließen',
'Save and Delivery Order' => 'Speichern und Lieferschein',
'Save and E-mail' => 'Speichern und E-Mail',
+ 'Save and Final Invoice' => 'Speichern und Schlussrechnung',
+ 'Save and Further Invoice for Advance Payment' => 'Speichern und weitere Anzahlungsrechnung',
'Save and Invoice' => 'Speichern und Rechnung erfassen',
+ 'Save and Invoice for Advance Payment' => 'Speichern und Anzahlungsrechnung',
'Save and Order' => 'Speichern und Auftrag erfassen',
'Save and Purchase Order' => 'Speichern und Lieferantenauftrag',
'Save and Quotation' => 'Speichern und Angebot',
'This group is valid for the following clients' => 'Diese Gruppe ist für die folgenden Mandanten gültig',
'This has been changed in this version, therefore please change the "old" bins to some real warehouse bins.' => 'Das wurde in dieser Version umgestellt, bitte ändern Sie die Freitext-Lagerplätze auf vorhandene Lagerplätze.',
'This has been changed in this version.' => 'Ab dieser Version ist dies nicht mehr so.',
+ 'This invoice has a further invoice for advanced payment.' => 'Diese Rechnung hat eine weitere Anzahlungsrechnung.',
+ 'This invoice has already a final invoice.' => 'Diese Rechnung hat schon eine Schlussrechnung.',
+ 'This invoice has already a further invoice for advanced payment.' => 'Diese Rechnung hat schon eine weitere Anzahlungsrechnung.',
'This invoice has already been posted.' => 'Die Rechnung wurde bereits gebucht.',
'This invoice has been canceled already.' => 'Die Rechnung wurde bereits storniert.',
'This invoice has been linked with a sepa export, undo this first.' => 'Diese Rechnung ist mit einem SEPA-Export verknüpft. Bitte diese Verknüpfung zuerst aufheben.',
'This invoice has not been posted yet.' => 'Die Rechnung wurde noch nicht gebucht.',
+ 'This invoice was added from an order. See there.' => 'Diese Rechnung wurde aus einem Auftrag erstellt. Siehe dort.',
'This invoice\'s dunning level: #1' => 'Mahnstufe dieser Rechnung: #1',
'This is a very critical problem.' => 'Dieses Problem ist sehr schwerwiegend.',
'This is the client to be selected by default on the login screen.' => 'Dies ist derjenige Mandant, der im Loginbildschirm standardmäßig ausgewählt sein wird.',
'This option controls the method used for determining the startdate for the balance report.' => 'Diese Option bestimmt, wie das Startdatum für den Bilanzbericht ermittelt wird',
'This option controls the method used for profit determination.' => 'Dieser Parameter legt die Berechnungsmethode für die Gewinnermittlung fest.',
'This option controls the posting and calculation behavior for the accounting method.' => 'Dieser Parameter steuert die Buchungs- und Berechnungsmethoden für die Versteuerungsart.',
+ 'This order has already a final invoice.' => 'Dieser Auftrag hat schon eine Schlussrechnung.',
'This part has already been added.' => 'Dieser Artikel wurde schon hinzugefügt',
'This part was already counted for this bin:' => 'Dieser Artikel wurde für diesen Lagerplatz bereits erfasst:',
'This price has since gone down' => 'Dieser Preis ist mittlerweile niedriger',
'filename' => 'Dateiname',
'filename has not uploadable characters ' => 'Bitte Dateinamen ändern. Er hat für den Upload nicht verwendbare Sonderzeichen ',
'filesize too big: ' => 'Datei zu groß: ',
+ 'final_invoice' => 'Schlussrechnung',
'flat-rate position' => 'Pauschalposition',
'follow_up_list' => 'wiedervorlageliste',
'for' => 'für',
'internal error (see details)' => 'Interner Fehler (siehe Details)!',
'invoice' => 'Rechnung',
'invoice mode or item mode' => 'Rechnungsmodus oder Artikelmodus',
+ 'invoice_for_advance_payment' => 'Anzahlungsrechnung',
'invoice_list' => 'debitorenbuchungsliste',
'is' => 'ist',
'is after' => 'ist nach dem',
'Add Delivery Order' => '',
'Add Document from \'#1\'' => '',
'Add Dunning' => '',
+ 'Add Final Invoice' => '',
'Add Follow-Up' => '',
'Add Follow-Up for #1' => '',
'Add General Ledger Transaction' => '',
+ 'Add Invoice for Advance Payment' => '',
'Add Letter' => '',
'Add Part' => '',
'Add Price Factor' => '',
'Cannot post a transaction without a value!' => '',
'Cannot post invoice and/or transfer out! Error message:' => '',
'Cannot post invoice for a closed period!' => '',
+ 'Cannot post invoice for advance payment with more than one tax' => '',
'Cannot post invoice!' => '',
'Cannot post payment for a closed period!' => '',
'Cannot post payment!' => '',
'Cleared Balance' => '',
'Cleared/uncleared only' => '',
'Clearing Tax Received (No 71)' => '',
+ 'Clearing account for advance payments' => '',
'Client' => '',
'Client #1' => '',
'Client Configuration' => '',
'Edit Dunning Process Config' => '',
'Edit Employee #1' => '',
'Edit Factur-X/ZUGFeRD notes' => '',
+ 'Edit Final Invoice' => '',
'Edit Follow-Up' => '',
'Edit Follow-Up for #1' => '',
'Edit General Ledger Transaction' => '',
+ 'Edit Invoice for Advance Payment' => '',
'Edit Letter' => '',
'Edit Part' => '',
'Edit Preferences for #1' => '',
'Edit Service' => '',
'Edit Storno Credit Note' => '',
'Edit Storno Invoice' => '',
+ 'Edit Storno Invoice for Advance Payment' => '',
'Edit User' => '',
'Edit User Group' => '',
'Edit Vendor' => '',
'Filter for item variables' => '',
'Filter parts' => '',
'Filter record template' => '',
+ 'Final Invoice' => '',
+ 'Final Invoice (one letter abbreviation)' => '',
'Financial Controlling' => '',
'Financial Controlling Report' => '',
'Financial Overview' => '',
'Function block actions' => '',
'Function block number format' => '',
'Function/position' => '',
+ 'Further Invoice for Advance Payment' => '',
'GL Transaction' => '',
'GL Transaction (abbreviation)' => '',
'GL Transactions' => '',
'Invoice email and Contact Person' => '',
'Invoice email settings' => '',
'Invoice filter' => '',
+ 'Invoice for Advance Payment' => '',
+ 'Invoice for Advance Payment (one letter abbreviation)' => '',
+ 'Invoice for Advance Payment with Storno (abbreviation)' => '',
'Invoice for fees' => '',
'Invoice has already been storno\'d!' => '',
'Invoice number' => '',
'Save and Close' => '',
'Save and Delivery Order' => '',
'Save and E-mail' => '',
+ 'Save and Final Invoice' => '',
+ 'Save and Further Invoice for Advance Payment' => '',
'Save and Invoice' => '',
+ 'Save and Invoice for Advance Payment' => '',
'Save and Order' => '',
'Save and Purchase Order' => '',
'Save and Quotation' => '',
'This group is valid for the following clients' => '',
'This has been changed in this version, therefore please change the "old" bins to some real warehouse bins.' => '',
'This has been changed in this version.' => '',
+ 'This invoice has a further invoice for advanced payment.' => '',
+ 'This invoice has already a final invoice.' => '',
+ 'This invoice has already a further invoice for advanced payment.' => '',
'This invoice has already been posted.' => '',
'This invoice has been canceled already.' => '',
'This invoice has been linked with a sepa export, undo this first.' => '',
'This invoice has not been posted yet.' => '',
+ 'This invoice was added from an order. See there.' => '',
'This invoice\'s dunning level: #1' => '',
'This is a very critical problem.' => '',
'This is the client to be selected by default on the login screen.' => '',
'This option controls the method used for determining the startdate for the balance report.' => '',
'This option controls the method used for profit determination.' => '',
'This option controls the posting and calculation behavior for the accounting method.' => '',
+ 'This order has already a final invoice.' => '',
'This part has already been added.' => '',
'This part was already counted for this bin:' => '',
'This price has since gone down' => '',
'filename' => '',
'filename has not uploadable characters ' => '',
'filesize too big: ' => '',
+ 'final_invoice' => '',
'flat-rate position' => '',
'follow_up_list' => '',
'for' => '',
'internal error (see details)' => '',
'invoice' => '',
'invoice mode or item mode' => '',
+ 'invoice_for_advance_payment' => '',
'invoice_list' => '',
'is' => '',
'is after' => '',
--- /dev/null
+- parent: ar
+ id: ar_add_sales_invoice_for_advance_payment
+ name: Add Invoice for Advance Payment
+ icon: sales_invoice_add
+ order: 550
+ access: invoice_edit
+ module: is.pl
+ params:
+ action: add
+ type: invoice_for_advance_payment
--- /dev/null
+-- @tag: defaults_advance_payment_clearing_chart_id
+-- @description: Voreingestelltes Konto für Verrechnung von Anzahlungen
+-- @depends: new_chart_1593_1495
+
+ALTER TABLE defaults ADD COLUMN advance_payment_clearing_chart_id INTEGER;
+
+DO $$
+BEGIN
+
+ IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR03EU' THEN
+ DECLARE
+ clearing_accno text := '1593';
+
+ BEGIN
+ IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE clearing_accno ) = 1 THEN
+ UPDATE defaults SET advance_payment_clearing_chart_id = (SELECT id FROM chart WHERE accno LIKE clearing_accno);
+ END IF;
+ END;
+ END IF;
+
+ IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR04EU' THEN
+ DECLARE
+ clearing_accno text := '1495';
+
+ BEGIN
+ IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE clearing_accno ) = 1 THEN
+ UPDATE defaults SET advance_payment_clearing_chart_id = (SELECT id FROM chart WHERE accno LIKE clearing_accno);
+ END IF;
+ END;
+ END IF;
+
+END $$;
--- /dev/null
+-- @tag: defaults_advance_payment_transfer_charts
+-- @description: Standardkonten für erhaltene versteuerte Anzahlungen 7% und 19% setzen
+-- @depends:new_chart_3260_1711 new_chart_3272_1718 defaults_advance_payment_clearing_chart_id
+
+
+ALTER TABLE defaults ADD COLUMN advance_payment_taxable_19_id INTEGER;
+ALTER TABLE defaults ADD COLUMN advance_payment_taxable_7_id INTEGER;
+UPDATE chart set link ='AR' where id = (select advance_payment_clearing_chart_id from defaults);
+
+
+DO $$
+BEGIN
+
+ IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR03EU' THEN
+ DECLARE
+ clearing_accno text := '1718';
+
+ BEGIN
+ IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE clearing_accno ) = 1 THEN
+ UPDATE defaults SET advance_payment_taxable_19_id = (SELECT id FROM chart WHERE accno LIKE clearing_accno);
+ END IF;
+ END;
+ END IF;
+
+ IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR04EU' THEN
+ DECLARE
+ clearing_accno text := '3272';
+
+ BEGIN
+ IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE clearing_accno ) = 1 THEN
+ UPDATE defaults SET advance_payment_taxable_19_id = (SELECT id FROM chart WHERE accno LIKE clearing_accno);
+ END IF;
+ END;
+ END IF;
+
+ IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR03EU' THEN
+ DECLARE
+ clearing_accno text := '1711';
+
+ BEGIN
+ IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE clearing_accno ) = 1 THEN
+ UPDATE defaults SET advance_payment_taxable_7_id = (SELECT id FROM chart WHERE accno LIKE clearing_accno);
+ END IF;
+ END;
+ END IF;
+
+ IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR04EU' THEN
+ DECLARE
+ clearing_accno text := '3260';
+
+ BEGIN
+ IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE clearing_accno ) = 1 THEN
+ UPDATE defaults SET advance_payment_taxable_7_id = (SELECT id FROM chart WHERE accno LIKE clearing_accno);
+ END IF;
+ END;
+ END IF;
+
+
+END $$;
--- /dev/null
+-- @tag: file_storage_partial_invoices
+-- @description: Dateispeicher auch für Anzahlungs- und Schlussrechnung
+-- @depends: file_storage_project
+
+ALTER TABLE files
+ DROP CONSTRAINT valid_type;
+ALTER TABLE files
+ ADD CONSTRAINT valid_type CHECK (
+ (object_type = 'credit_note' ) OR (object_type = 'invoice' ) OR (object_type = 'sales_order' )
+ OR (object_type = 'sales_quotation' ) OR (object_type = 'sales_delivery_order' ) OR (object_type = 'request_quotation' )
+ OR (object_type = 'purchase_order' ) OR (object_type = 'purchase_delivery_order' ) OR (object_type = 'purchase_invoice' )
+ OR (object_type = 'vendor' ) OR (object_type = 'customer' ) OR (object_type = 'part' )
+ OR (object_type = 'gl_transaction' ) OR (object_type = 'dunning' ) OR (object_type = 'dunning1' )
+ OR (object_type = 'dunning2' ) OR (object_type = 'dunning3' ) OR (object_type = 'dunning_orig_invoice' )
+ OR (object_type = 'dunning_invoice' ) OR (object_type = 'draft' ) OR (object_type = 'statement' )
+ OR (object_type = 'shop_image' ) OR (object_type = 'letter' ) OR (object_type = 'project' )
+ OR (object_type = 'invoice_for_advance_payment') OR (object_type = 'final_invoice')
+ );
--- /dev/null
+-- @tag: new_chart_1593_1495
+-- @description: Neue Konten "Verrechnungskonto erhalt. Anzahl. bei Buchung über Debitorenkonto"
+-- @depends: release_3_5_8
+
+
+DO $$
+BEGIN
+
+ IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR03EU' THEN
+ DECLARE
+ new_accno text := '1593';
+
+ BEGIN
+ IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE new_accno ) = 0 THEN
+ INSERT INTO chart (accno, description, charttype, category, link, taxkey_id)
+ VALUES (new_accno, 'Verrechnungskonto erhalt. Anzahl. bei Buchung über Debitorenkonto','A', 'L', 'AR_amount', 0);
+ INSERT INTO taxkeys (chart_id, tax_id, taxkey_id, startdate)
+ VALUES ((SELECT id FROM chart WHERE accno LIKE new_accno), 0, 0, '1970-01-01');
+ END IF;
+ END;
+ END IF;
+
+ IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR04EU' THEN
+ DECLARE
+ new_accno text := '1495';
+
+ BEGIN
+ IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE new_accno ) = 0 THEN
+ INSERT INTO chart (accno, description, charttype, category, link, taxkey_id)
+ VALUES (new_accno, 'Verrechnungskonto erhalt. Anzahl. bei Buchung über Debitorenkonto','A', 'L', 'AR_amount', 0);
+ INSERT INTO taxkeys (chart_id, tax_id, taxkey_id, startdate)
+ VALUES ((SELECT id FROM chart WHERE accno LIKE new_accno), 0, 0, '1970-01-01');
+ END IF;
+ END;
+ END IF;
+
+END $$;
--- /dev/null
+-- @tag: new_chart_3260_1711
+-- @description: Neues Konto "Erhaltene, versteuerte Anzahlungen 7 % USt (Verbindlichkeiten)"
+-- @depends: release_3_5_8
+
+
+DO $$
+BEGIN
+
+ IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR03EU' THEN
+ DECLARE
+ new_accno text := '1711';
+
+ BEGIN
+ IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE new_accno ) = 0 THEN
+ INSERT INTO chart (accno, description, charttype, category, link, taxkey_id)
+ VALUES (new_accno, 'Erhaltene, versteuerte Anzahlungen 7 % USt (Verbindlichkeiten)','A', 'L', 'AR_amount', 0);
+ INSERT INTO taxkeys (chart_id, tax_id, taxkey_id, startdate)
+ VALUES ((SELECT id FROM chart WHERE accno LIKE new_accno), 0, 0, '1970-01-01');
+ END IF;
+ END;
+ END IF;
+
+ IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR04EU' THEN
+ DECLARE
+ new_accno text := '3260';
+
+ BEGIN
+ IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE new_accno ) = 0 THEN
+ INSERT INTO chart (accno, description, charttype, category, link, taxkey_id)
+ VALUES (new_accno, 'Erhaltene, versteuerte Anzahlungen 7 % USt (Verbindlichkeiten)','A', 'L', 'AR_amount', 0);
+ INSERT INTO taxkeys (chart_id, tax_id, taxkey_id, startdate)
+ VALUES ((SELECT id FROM chart WHERE accno LIKE new_accno), 0, 0, '1970-01-01');
+ END IF;
+ END;
+ END IF;
+
+END $$;
--- /dev/null
+-- @tag: new_chart_3272_1718
+-- @description: Neues Konto "Erhaltene, versteuerte Anzahlungen 19 % USt (Verbindlichkeiten)"
+-- @depends: release_3_5_8
+
+
+DO $$
+BEGIN
+
+ IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR03EU' THEN
+ DECLARE
+ new_accno text := '1718';
+
+ BEGIN
+ IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE new_accno ) = 0 THEN
+ INSERT INTO chart (accno, description, charttype, category, link, taxkey_id)
+ VALUES (new_accno, 'Erhaltene, versteuerte Anzahlungen 19 % USt (Verbindlichkeiten)','A', 'L', 'AR_amount', 0);
+ INSERT INTO taxkeys (chart_id, tax_id, taxkey_id, startdate)
+ VALUES ((SELECT id FROM chart WHERE accno LIKE new_accno), 0, 0, '1970-01-01');
+ END IF;
+ END;
+ END IF;
+
+ IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR04EU' THEN
+ DECLARE
+ new_accno text := '3272';
+
+ BEGIN
+ IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE new_accno ) = 0 THEN
+ INSERT INTO chart (accno, description, charttype, category, link, taxkey_id)
+ VALUES (new_accno, 'Erhaltene, versteuerte Anzahlungen 19 % USt (Verbindlichkeiten)','A', 'L', 'AR_amount', 0);
+ INSERT INTO taxkeys (chart_id, tax_id, taxkey_id, startdate)
+ VALUES ((SELECT id FROM chart WHERE accno LIKE new_accno), 0, 0, '1970-01-01');
+ END IF;
+ END;
+ END IF;
+
+END $$;
\newcommand{\textUstid} {UStId:}
+% anzahlungsrechnung (invoice_for_advance_payment)
+\newcommand{\anzahlungsrechnung} {Anzahlungsrechnung}
+\newcommand{\schlussrechnung} {Schlussrechnung}
+\newcommand{\ust} {USt}
+\newcommand{\abzueglichAnzahlungsrechnungen} {Abzüglich folgender Anzahlungsrechnungen}
+\newcommand{\rechnungsbetrag} {Rechnungsbetrag}
+
% gutschrift (credit_note)
\newcommand{\gutschrift} {Gutschrift}
\newcommand{\fuerRechnung} {für Rechnung}
\newcommand{\textUstid} {VAT number:}
+% anzahlungsrechnung (invoice_for_advance_payment)
+\newcommand{\anzahlungsrechnung} {Invoice for advance payment}
+\newcommand{\schlussrechnung} {Final Invoice}
+\newcommand{\ust} {VAT}
+\newcommand{\abzueglichAnzahlungsrechnungen} {Minus following invoices for advance payment}
+\newcommand{\rechnungsbetrag} {Invoice amount}
+
% gutschrift (credit_note)
\newcommand{\gutschrift} {Credit note}
\newcommand{\fuerRechnung} {for invoice}
--- /dev/null
+invoice.tex
\ No newline at end of file
% settings: Einstellungen, Logo, Briefpapier, Kopfzeile, Fusszeile
\input{insettings.tex}
+<%if template_meta.formname == "invoice_for_advance_payment"%>
+ \renewcommand{\rechnung}{\anzahlungsrechnung}
+<%end if%>
+
+<%if template_meta.formname == "final_invoice"%>
+ \renewcommand{\rechnung}{\schlussrechnung}
+<%end if%>
% laufende Kopfzeile:
\ourhead{\kundennummer}{<%customernumber%>}{\rechnung}{<%invnumber%>}{<%invdate%>}
\vspace{0.2cm}
+<%if iap_existing%>%
+ \abzueglichAnzahlungsrechnungen:\\
+ \begin{SimpleTabular}[colspec=llr<{\tabcurrency}r<{\tabcurrency},headline={\bfseries\nr& \bfseries\date& \bfseries\betrag & \bfseries\ust}]%
+ <%foreach iap_invnumber%>%
+ <%iap_invnumber%> & <%iap_transdate_as_date%> & <%iap_amount%> & <%iap_taxamount%>\\%
+ <%end iap_invnumber%>%
+ \end{SimpleTabular}%
+ <%if template_meta.formname == "final_invoice"%>%
+ \bfseries\rechnungsbetrag: <%iap_final_amount%> \currency\\%
+ <%end%>%
+<%end iap_available%>%
+
\Ifstr{<%deliverydate%>}{}{%
\leistungsdatumGleichRechnungsdatum%
}{
--- /dev/null
+invoice.tex
\ No newline at end of file
<td>[% P.chart.picker('defaults.ar_chart_id', SELF.defaults.ar_chart_id, type='AR', choose=1, style=style) %]<td>
</tr>
+ <tr>
+ <td align="right">[% LxERP.t8("Clearing account for advance payments") %]</td>
+ <td>[% P.chart.picker('defaults.advance_payment_clearing_chart_id', SELF.defaults.advance_payment_clearing_chart_id, choose=1, style=style) %]<td>
+ </tr>
+
<tr>
<td align="right">[% LxERP.t8("Account for workflow from purchase order to ap transaction") %]</td>
<td>[% P.chart.picker('defaults.workflow_po_ap_chart_id', SELF.defaults.workflow_po_ap_chart_id, type='AP_amount', choose=1, style=style) %]<td>
</table>
</td>
</tr>
-
-[% PROCESS 'is/_payments.html' %]
+[% IF is_type_normal_invoice OR is_type_credit_note %]
+ [% PROCESS 'is/_payments.html' %]
+[% END %]
</table>
</div>
[% PROCESS 'webdav/_list.html' %]
[%- END %]
[%- IF id %]
[%- IF INSTANCE_CONF.get_doc_storage %]
- [% object_type = is_type_credit_note? 'credit_note' : 'invoice' %]
- <li><a href="controller.pl?action=File/list&file_type=document&object_type=[% object_type %]&object_id=[% HTML.url(id) %]">[% 'Documents' | $T8 %]</a></li>
- <li><a href="controller.pl?action=File/list&file_type=attachment&object_type=[% object_type %]&object_id=[% HTML.url(id) %]">[% 'Attachments' | $T8 %]</a></li>
+ <li><a href="controller.pl?action=File/list&file_type=document&object_type=[% type %]&object_id=[% HTML.url(id) %]">[% 'Documents' | $T8 %]</a></li>
+ <li><a href="controller.pl?action=File/list&file_type=attachment&object_type=[% type %]&object_id=[% HTML.url(id) %]">[% 'Attachments' | $T8 %]</a></li>
[%- END %]
[%- IF AUTH.assert('record_links', 1) %]
<li><a href="controller.pl?action=RecordLinks/ajax_list&object_model=Invoice&object_id=[% HTML.url(id) %]">[% 'Linked Records' | $T8 %]</a></li>