From e1f2871c3b37139486b080ef1a56f5a2fc3268c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 27 Feb 2021 15:23:46 +0100 Subject: [PATCH] Add method to post invoices by batch issue10054 review333811002 --- CHANGELOG | 1 + account.py | 25 ++++++++++++++++++++++++- invoice.py | 36 +++++++++++++++++++++++++++++------- message.xml | 3 +++ 4 files changed, 57 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7eb3be652d..09f147e159 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Add method to post invoices by batch * Add payment term date in invoice * Raise warning on invoice with maturity dates on the past * Remove foreign key for sequence of Invoice diff --git a/account.py b/account.py index ecce3bb4c6..b5dd518bf7 100644 --- a/account.py +++ b/account.py @@ -5,13 +5,15 @@ from collections import OrderedDict from sql import Literal from sql.conditionals import Coalesce -from trytond.model import (fields, ModelView, ModelSQL, MatchMixin, +from trytond.i18n import gettext +from trytond.model import (fields, ModelView, ModelSQL, Workflow, MatchMixin, sequence_ordered) from trytond.pyson import Eval, If, Bool from trytond.pool import Pool, PoolMeta from trytond.tools import grouped_slice from trytond.transaction import Transaction +from trytond.modules.account.exceptions import ClosePeriodError from trytond.modules.company.model import CompanyValueMixin @@ -136,6 +138,27 @@ class Period(metaclass=PoolMeta): table.drop_column('in_invoice_sequence') table.drop_column('in_credit_note_sequence') + @classmethod + @ModelView.button + @Workflow.transition('close') + def close(cls, periods): + pool = Pool() + Invoice = pool.get('account.invoice') + company_ids = list({p.company.id for p in periods}) + invoices = Invoice.search([ + ('company', 'in', company_ids), + ('state', '=', 'posted'), + ('move', '=', None), + ]) + if invoices: + names = ', '.join(i.rec_name for i in invoices[:5]) + if len(invoices) > 5: + names += '...' + raise ClosePeriodError( + gettext('account_invoice.msg_close_period_non_posted_invoices', + invoices=names)) + super().close() + class InvoiceSequence(sequence_ordered(), ModelSQL, ModelView, MatchMixin): 'Invoice Sequence' diff --git a/invoice.py b/invoice.py index 1797cbcd53..77992b99b6 100644 --- a/invoice.py +++ b/invoice.py @@ -244,8 +244,9 @@ class Invoice(Workflow, ModelSQL, ModelView, TaxableMixin): @classmethod def __setup__(cls): super(Invoice, cls).__setup__() - cls._check_modify_exclude = ['state', 'payment_lines', 'cancel_move', - 'invoice_report_cache', 'invoice_report_format', 'lines'] + cls._check_modify_exclude = { + 'state', 'payment_lines', 'move', 'cancel_move', + 'invoice_report_cache', 'invoice_report_format', 'lines'} cls._order = [ ('number', 'DESC NULLS FIRST'), ('id', 'DESC'), @@ -265,6 +266,7 @@ class Invoice(Workflow, ModelSQL, ModelView, TaxableMixin): ('draft', 'validated'), ('validated', 'posted'), ('draft', 'posted'), + ('posted', 'posted'), ('posted', 'paid'), ('validated', 'draft'), ('paid', 'posted'), @@ -302,8 +304,9 @@ class Invoice(Workflow, ModelSQL, ModelView, TaxableMixin): ('invoice_date', '!=', None), ('type', '!=', 'in'), ], - 'invisible': ~Eval('state').in_(['draft', 'validated']), - 'depends': ['state'], + 'invisible': (~Eval('state').in_(['draft', 'validated']) + | ((Eval('state') == 'posted') & Bool(Eval('move')))), + 'depends': ['state', 'move'], }, 'pay': { 'invisible': Eval('state') != 'posted', @@ -1200,7 +1203,7 @@ class Invoice(Workflow, ModelSQL, ModelView, TaxableMixin): actions = iter(args) all_invoices = [] for invoices, values in zip(actions, actions): - if set(values) - set(cls._check_modify_exclude): + if set(values) - cls._check_modify_exclude: cls.check_modify(invoices) all_invoices += invoices update_tax = [i for i in all_invoices if i.state == 'draft'] @@ -1463,11 +1466,30 @@ class Invoice(Workflow, ModelSQL, ModelView, TaxableMixin): Move.save(moves) cls.save(invoices_in) + @classmethod + @Workflow.transition('posted') + def post_batch(cls, invoices): + pool = Pool() + Date = pool.get('ir.date') + today = Date.today() + cls.set_number(invoices) + for invoice in invoices: + if not invoice.payment_term_date: + invoice.payment_term_date = today + cls.save(invoices) + with Transaction().set_context(_skip_warnings=True): + cls.__queue__._post(invoices) + @classmethod @ModelView.button @Workflow.transition('posted') def post(cls, invoices): - Move = Pool().get('account.move') + cls._post(invoices) + + @classmethod + def _post(cls, invoices): + pool = Pool() + Move = pool.get('account.move') cls.set_number(invoices) moves = [] @@ -1528,7 +1550,7 @@ class Invoice(Workflow, ModelSQL, ModelView, TaxableMixin): delete_moves = [] to_save = [] for invoice in invoices: - if invoice.move: + if invoice.move or invoice.number: if invoice.move.state == 'draft': delete_moves.append(invoice.move) elif not invoice.cancel_move: diff --git a/message.xml b/message.xml index be673fabc3..46dbd96873 100644 --- a/message.xml +++ b/message.xml @@ -69,6 +69,9 @@ this repository contains the full copyright notices and license terms. --> The invoice "%(invoice)s" generates a payment date "%(date)s" in the past. + + To close the periods you must post the invoices "%(moves)s". +