From: Jan Büren Date: Mon, 14 Feb 2022 13:00:23 +0000 (+0100) Subject: Merge pull request #36 from kivitendo/master-partial_invoice-2 X-Git-Tag: kivitendo-mebil_0.1-0~10^2~2^2~217 X-Git-Url: http://wagnertech.de/gitweb/gitweb.cgi/mfinanz.git/commitdiff_plain/9f0c5105e2c79feead651fd0de5d9ba725a2c1ff?hp=17ede850d9f16aebb63bc52493c07be4c201b3ea Merge pull request #36 from kivitendo/master-partial_invoice-2 Master partial invoice 2 --- diff --git a/SL/AR.pm b/SL/AR.pm index 280184d7e..77c62d39c 100644 --- a/SL/AR.pm +++ b/SL/AR.pm @@ -487,6 +487,7 @@ sub ar_transactions { 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, | . diff --git a/SL/BackgroundJob/SelfTest/Transactions.pm b/SL/BackgroundJob/SelfTest/Transactions.pm index 9eda7222c..ab145cece 100644 --- a/SL/BackgroundJob/SelfTest/Transactions.pm +++ b/SL/BackgroundJob/SelfTest/Transactions.pm @@ -472,6 +472,7 @@ sub check_ar_acc_trans_amount { 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); diff --git a/SL/Controller/File.pm b/SL/Controller/File.pm index 7cd9406d0..dcf790e5b 100644 --- a/SL/Controller/File.pm +++ b/SL/Controller/File.pm @@ -55,25 +55,27 @@ __PACKAGE__->run_before('check_object_params', only => [ qw(list ajax_delete aja # 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 ---# diff --git a/SL/Controller/Order.pm b/SL/Controller/Order.pm index 64ad14d23..b4328a1e2 100644 --- a/SL/Controller/Order.pm +++ b/SL/Controller/Order.pm @@ -57,11 +57,11 @@ use Rose::Object::MakeMethods::Generic __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) ]); # @@ -688,6 +688,26 @@ sub action_save_and_invoice { ); } +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(); @@ -1974,6 +1994,18 @@ sub setup_edit_action_bar { 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 => [ @@ -2040,6 +2072,26 @@ sub setup_edit_action_bar { @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 ], diff --git a/SL/Controller/PriceSource.pm b/SL/Controller/PriceSource.pm index 85e3765be..c0c113cd0 100644 --- a/SL/Controller/PriceSource.pm +++ b/SL/Controller/PriceSource.pm @@ -83,6 +83,8 @@ sub _make_record_item { 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', diff --git a/SL/DB/Helper/Payment.pm b/SL/DB/Helper/Payment.pm index 6dee0918f..8d0174d9b 100644 --- a/SL/DB/Helper/Payment.pm +++ b/SL/DB/Helper/Payment.pm @@ -77,6 +77,7 @@ sub pay_invoice { }; # 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 @@ -290,6 +291,67 @@ sub pay_invoice { $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); diff --git a/SL/DB/Invoice.pm b/SL/DB/Invoice.pm index 54f5483e8..45259a064 100644 --- a/SL/DB/Invoice.pm +++ b/SL/DB/Invoice.pm @@ -539,6 +539,9 @@ sub invoice_type { 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; @@ -559,6 +562,9 @@ sub displayable_type { 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'); } @@ -573,6 +579,9 @@ sub abbreviation { 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)'); } diff --git a/SL/DB/MetaSetup/Default.pm b/SL/DB/MetaSetup/Default.pm index ff3733a7d..b7fe2b1e2 100644 --- a/SL/DB/MetaSetup/Default.pm +++ b/SL/DB/MetaSetup/Default.pm @@ -15,6 +15,9 @@ __PACKAGE__->meta->columns( 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 }, diff --git a/SL/File/Backend/Webdav.pm b/SL/File/Backend/Webdav.pm index 2956e03f9..bf8f9af61 100644 --- a/SL/File/Backend/Webdav.pm +++ b/SL/File/Backend/Webdav.pm @@ -113,47 +113,51 @@ sub enabled { # 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 = ( diff --git a/SL/Form.pm b/SL/Form.pm index 9c05c3353..62ebe73f6 100644 --- a/SL/Form.pm +++ b/SL/Form.pm @@ -1085,27 +1085,29 @@ sub get_formname_translation { 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(); @@ -1131,11 +1133,11 @@ sub get_number_prefix_for_type { 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'; @@ -1170,7 +1172,7 @@ sub generate_attachment_filename { 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"}) { @@ -2944,6 +2946,8 @@ sub save_status { # $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') diff --git a/SL/Helper/PrintOptions.pm b/SL/Helper/PrintOptions.pm index cf4616f62..2b07ee707 100644 --- a/SL/Helper/PrintOptions.pm +++ b/SL/Helper/PrintOptions.pm @@ -69,6 +69,12 @@ sub get_print_options { ($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')), diff --git a/SL/IC.pm b/SL/IC.pm index da83c33b8..2a9460745 100644 --- a/SL/IC.pm +++ b/SL/IC.pm @@ -736,7 +736,7 @@ sub retrieve_accounts { # 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}; diff --git a/SL/IS.pm b/SL/IS.pm index 9474b18e0..11db135be 100644 --- a/SL/IS.pm +++ b/SL/IS.pm @@ -35,7 +35,8 @@ package IS; -use List::Util qw(max); +use List::Util qw(max sum0); +use List::MoreUtils qw(any); use Carp; use SL::AM; @@ -51,6 +52,7 @@ use SL::MoreCommon; 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; @@ -175,7 +177,12 @@ sub invoice_details { 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) { @@ -560,6 +567,11 @@ sub invoice_details { 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); @@ -574,6 +586,38 @@ sub invoice_details { $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(); } @@ -714,6 +758,8 @@ sub _post_invoice { 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}); @@ -1039,6 +1085,105 @@ SQL # 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/); @@ -1076,7 +1221,7 @@ SQL 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 @@ -1093,8 +1238,9 @@ SQL 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; } @@ -1105,7 +1251,7 @@ SQL 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 @@ -1122,8 +1268,9 @@ SQL 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); } } @@ -1137,6 +1284,17 @@ SQL } } + # 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) { @@ -1459,6 +1617,50 @@ SQL 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; @@ -1965,6 +2167,18 @@ sub _delete_invoice { 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); diff --git a/SL/TransNumber.pm b/SL/TransNumber.pm index bd3e75332..25646dafb 100644 --- a/SL/TransNumber.pm +++ b/SL/TransNumber.pm @@ -15,7 +15,7 @@ use Rose::Object::MakeMethods::Generic 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; @@ -37,7 +37,7 @@ sub _get_filters { 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"; diff --git a/SL/Webdav.pm b/SL/Webdav.pm index 0b27d7dc6..b0f89090b 100644 --- a/SL/Webdav.pm +++ b/SL/Webdav.pm @@ -17,24 +17,26 @@ use Rose::Object::MakeMethods::Generic ( ); 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 { diff --git a/bin/mozilla/ar.pl b/bin/mozilla/ar.pl index b2a6602bb..0ed071eca 100644 --- a/bin/mozilla/ar.pl +++ b/bin/mozilla/ar.pl @@ -1206,12 +1206,23 @@ sub ar_transactions { 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); diff --git a/bin/mozilla/io.pl b/bin/mozilla/io.pl index 9628ddffd..2f0fb95cd 100644 --- a/bin/mozilla/io.pl +++ b/bin/mozilla/io.pl @@ -1205,6 +1205,15 @@ sub print_form { 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"; @@ -1302,7 +1311,7 @@ sub print_form { } $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(); } @@ -1885,6 +1894,8 @@ sub _make_record_item { 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', diff --git a/bin/mozilla/is.pl b/bin/mozilla/is.pl index 12deb267b..f0246220d 100644 --- a/bin/mozilla/is.pl +++ b/bin/mozilla/is.pl @@ -36,9 +36,11 @@ use SL::FU; 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); @@ -89,6 +91,13 @@ sub add { 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'); @@ -132,6 +141,14 @@ sub edit { 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}; @@ -237,8 +254,18 @@ sub prepare_invoice { 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"; @@ -294,6 +321,28 @@ sub setup_is_action_bar { 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 => [ @@ -328,6 +377,7 @@ sub setup_is_action_bar { : !$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" } ], @@ -335,7 +385,7 @@ sub setup_is_action_bar { 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" @@ -377,6 +427,30 @@ sub setup_is_action_bar { : !$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" } ], @@ -550,10 +624,11 @@ sub form_header { $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( @@ -693,17 +768,18 @@ sub form_footer { } 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 @@ -967,6 +1043,12 @@ sub post { $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"})) { @@ -1111,6 +1193,80 @@ sub use_as_new { $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(); @@ -1240,7 +1396,6 @@ sub credit_note { &prepare_invoice; - &display_form; $main::lxdebug->leave_sub(); diff --git a/bin/mozilla/oe.pl b/bin/mozilla/oe.pl index a3425ecde..96764ebdf 100644 --- a/bin/mozilla/oe.pl +++ b/bin/mozilla/oe.pl @@ -1654,7 +1654,7 @@ sub invoice { $::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; @@ -1699,7 +1699,9 @@ sub invoice { 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'; @@ -1708,7 +1710,7 @@ sub invoice { # 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"); diff --git a/locale/de/all b/locale/de/all index 29feb69ac..3bd120334 100755 --- a/locale/de/all +++ b/locale/de/all @@ -176,9 +176,11 @@ $self->{texts} = { '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', @@ -586,6 +588,7 @@ $self->{texts} = { '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!', @@ -668,6 +671,7 @@ $self->{texts} = { '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', @@ -1244,9 +1248,11 @@ $self->{texts} = { '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', @@ -1263,6 +1269,7 @@ $self->{texts} = { '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', @@ -1551,6 +1558,8 @@ $self->{texts} = { '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', @@ -1618,6 +1627,7 @@ $self->{texts} = { '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', @@ -1872,6 +1882,9 @@ $self->{texts} = { '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', @@ -2991,7 +3004,10 @@ $self->{texts} = { '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', @@ -3842,10 +3858,14 @@ $self->{texts} = { '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.', @@ -3862,6 +3882,7 @@ $self->{texts} = { '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', @@ -4408,6 +4429,7 @@ $self->{texts} = { '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', @@ -4434,6 +4456,7 @@ $self->{texts} = { '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', diff --git a/locale/en/all b/locale/en/all index 79e8f6be7..9c747ff0d 100644 --- a/locale/en/all +++ b/locale/en/all @@ -176,9 +176,11 @@ $self->{texts} = { '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' => '', @@ -586,6 +588,7 @@ $self->{texts} = { '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!' => '', @@ -668,6 +671,7 @@ $self->{texts} = { 'Cleared Balance' => '', 'Cleared/uncleared only' => '', 'Clearing Tax Received (No 71)' => '', + 'Clearing account for advance payments' => '', 'Client' => '', 'Client #1' => '', 'Client Configuration' => '', @@ -1244,9 +1248,11 @@ $self->{texts} = { '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' => '', @@ -1263,6 +1269,7 @@ $self->{texts} = { 'Edit Service' => '', 'Edit Storno Credit Note' => '', 'Edit Storno Invoice' => '', + 'Edit Storno Invoice for Advance Payment' => '', 'Edit User' => '', 'Edit User Group' => '', 'Edit Vendor' => '', @@ -1551,6 +1558,8 @@ $self->{texts} = { 'Filter for item variables' => '', 'Filter parts' => '', 'Filter record template' => '', + 'Final Invoice' => '', + 'Final Invoice (one letter abbreviation)' => '', 'Financial Controlling' => '', 'Financial Controlling Report' => '', 'Financial Overview' => '', @@ -1618,6 +1627,7 @@ $self->{texts} = { 'Function block actions' => '', 'Function block number format' => '', 'Function/position' => '', + 'Further Invoice for Advance Payment' => '', 'GL Transaction' => '', 'GL Transaction (abbreviation)' => '', 'GL Transactions' => '', @@ -1872,6 +1882,9 @@ $self->{texts} = { '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' => '', @@ -2989,7 +3002,10 @@ $self->{texts} = { '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' => '', @@ -3837,10 +3853,14 @@ $self->{texts} = { '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.' => '', @@ -3857,6 +3877,7 @@ $self->{texts} = { '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' => '', @@ -4404,6 +4425,7 @@ $self->{texts} = { 'filename' => '', 'filename has not uploadable characters ' => '', 'filesize too big: ' => '', + 'final_invoice' => '', 'flat-rate position' => '', 'follow_up_list' => '', 'for' => '', @@ -4430,6 +4452,7 @@ $self->{texts} = { 'internal error (see details)' => '', 'invoice' => '', 'invoice mode or item mode' => '', + 'invoice_for_advance_payment' => '', 'invoice_list' => '', 'is' => '', 'is after' => '', diff --git a/menus/user/20-invoice-for-advance-payment.yaml b/menus/user/20-invoice-for-advance-payment.yaml new file mode 100644 index 000000000..b76dcadf7 --- /dev/null +++ b/menus/user/20-invoice-for-advance-payment.yaml @@ -0,0 +1,10 @@ +- 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 diff --git a/sql/Pg-upgrade2/defaults_advance_payment_clearing_chart_id.sql b/sql/Pg-upgrade2/defaults_advance_payment_clearing_chart_id.sql new file mode 100644 index 000000000..53da9089d --- /dev/null +++ b/sql/Pg-upgrade2/defaults_advance_payment_clearing_chart_id.sql @@ -0,0 +1,32 @@ +-- @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 $$; diff --git a/sql/Pg-upgrade2/defaults_advance_payment_transfer_charts.sql b/sql/Pg-upgrade2/defaults_advance_payment_transfer_charts.sql new file mode 100644 index 000000000..f77b2578e --- /dev/null +++ b/sql/Pg-upgrade2/defaults_advance_payment_transfer_charts.sql @@ -0,0 +1,59 @@ +-- @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 $$; diff --git a/sql/Pg-upgrade2/file_storage_partial_invoices.sql b/sql/Pg-upgrade2/file_storage_partial_invoices.sql new file mode 100644 index 000000000..7fed883ac --- /dev/null +++ b/sql/Pg-upgrade2/file_storage_partial_invoices.sql @@ -0,0 +1,18 @@ +-- @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') + ); diff --git a/sql/Pg-upgrade2/new_chart_1593_1495.sql b/sql/Pg-upgrade2/new_chart_1593_1495.sql new file mode 100644 index 000000000..d6f83d769 --- /dev/null +++ b/sql/Pg-upgrade2/new_chart_1593_1495.sql @@ -0,0 +1,37 @@ +-- @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 $$; diff --git a/sql/Pg-upgrade2/new_chart_3260_1711.sql b/sql/Pg-upgrade2/new_chart_3260_1711.sql new file mode 100644 index 000000000..a9fb7d4ae --- /dev/null +++ b/sql/Pg-upgrade2/new_chart_3260_1711.sql @@ -0,0 +1,37 @@ +-- @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 $$; diff --git a/sql/Pg-upgrade2/new_chart_3272_1718.sql b/sql/Pg-upgrade2/new_chart_3272_1718.sql new file mode 100644 index 000000000..24c973ad8 --- /dev/null +++ b/sql/Pg-upgrade2/new_chart_3272_1718.sql @@ -0,0 +1,37 @@ +-- @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 $$; diff --git a/templates/print/marei/deutsch.tex b/templates/print/marei/deutsch.tex index 0d2960fd9..75276e4fa 100644 --- a/templates/print/marei/deutsch.tex +++ b/templates/print/marei/deutsch.tex @@ -95,6 +95,13 @@ \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} diff --git a/templates/print/marei/english.tex b/templates/print/marei/english.tex index a2b6ec307..a6322df09 100644 --- a/templates/print/marei/english.tex +++ b/templates/print/marei/english.tex @@ -94,6 +94,13 @@ \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} diff --git a/templates/print/marei/final_invoice.tex b/templates/print/marei/final_invoice.tex new file mode 120000 index 000000000..b6a6ad821 --- /dev/null +++ b/templates/print/marei/final_invoice.tex @@ -0,0 +1 @@ +invoice.tex \ No newline at end of file diff --git a/templates/print/marei/invoice.tex b/templates/print/marei/invoice.tex index 586847fcd..7cdef54a7 100644 --- a/templates/print/marei/invoice.tex +++ b/templates/print/marei/invoice.tex @@ -21,6 +21,13 @@ % 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%>} @@ -152,6 +159,18 @@ \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% }{ diff --git a/templates/print/marei/invoice_for_advance_payment.tex b/templates/print/marei/invoice_for_advance_payment.tex new file mode 120000 index 000000000..b6a6ad821 --- /dev/null +++ b/templates/print/marei/invoice_for_advance_payment.tex @@ -0,0 +1 @@ +invoice.tex \ No newline at end of file diff --git a/templates/webpages/client_config/_default_accounts.html b/templates/webpages/client_config/_default_accounts.html index 35a8a3a70..05f4e9e1c 100644 --- a/templates/webpages/client_config/_default_accounts.html +++ b/templates/webpages/client_config/_default_accounts.html @@ -55,6 +55,11 @@ [% P.chart.picker('defaults.ar_chart_id', SELF.defaults.ar_chart_id, type='AR', choose=1, style=style) %] + + [% LxERP.t8("Clearing account for advance payments") %] + [% P.chart.picker('defaults.advance_payment_clearing_chart_id', SELF.defaults.advance_payment_clearing_chart_id, choose=1, style=style) %] + + [% LxERP.t8("Account for workflow from purchase order to ap transaction") %] [% P.chart.picker('defaults.workflow_po_ap_chart_id', SELF.defaults.workflow_po_ap_chart_id, type='AP_amount', choose=1, style=style) %] diff --git a/templates/webpages/is/form_footer.html b/templates/webpages/is/form_footer.html index 7d4c6089d..856c7f488 100644 --- a/templates/webpages/is/form_footer.html +++ b/templates/webpages/is/form_footer.html @@ -134,8 +134,9 @@ - -[% PROCESS 'is/_payments.html' %] +[% IF is_type_normal_invoice OR is_type_credit_note %] + [% PROCESS 'is/_payments.html' %] +[% END %] [% PROCESS 'webdav/_list.html' %] diff --git a/templates/webpages/is/form_header.html b/templates/webpages/is/form_header.html index 5b78c3ec5..ec575dde0 100644 --- a/templates/webpages/is/form_header.html +++ b/templates/webpages/is/form_header.html @@ -34,9 +34,8 @@ [%- END %] [%- IF id %] [%- IF INSTANCE_CONF.get_doc_storage %] - [% object_type = is_type_credit_note? 'credit_note' : 'invoice' %] -
  • [% 'Documents' | $T8 %]
  • -
  • [% 'Attachments' | $T8 %]
  • +
  • [% 'Documents' | $T8 %]
  • +
  • [% 'Attachments' | $T8 %]
  • [%- END %] [%- IF AUTH.assert('record_links', 1) %]
  • [% 'Linked Records' | $T8 %]