diff --git a/__init__.py b/__init__.py index 9b57775..197e0c3 100644 --- a/__init__.py +++ b/__init__.py @@ -5,14 +5,12 @@ from trytond.pool import Pool from . import invoice from . import commission from . import payment -from . import move def register(): Pool.register( invoice.Invoice, - move.Move, - move.Line, + invoice.Move, module='account_invoice_posted2draft', type_='model') Pool.register( payment.Invoice, diff --git a/commission.py b/commission.py index 80a6a16..b72ac34 100644 --- a/commission.py +++ b/commission.py @@ -4,43 +4,27 @@ from trytond.pool import Pool, PoolMeta from trytond.tools import grouped_slice +__all__ = ['Invoice'] + class Invoice(metaclass=PoolMeta): __name__ = 'account.invoice' - def get_allow_draft(self, name): - pool = Pool() - Commission = pool.get('commission') - - result = super().get_allow_draft(name) - - invoiced = Commission.search([ - ('origin.invoice', '=', self.id, 'account.invoice.line'), - ('invoice_line', '!=', None), - ]) - if invoiced: - result = False - return result - @classmethod def draft(cls, invoices): - pool = Pool() - Commission = pool.get('commission') + Commission = Pool().get('commission') - to_delete = [] for sub_invoices in grouped_slice(invoices): ids = [i.id for i in sub_invoices] - to_delete = Commission.search([ + commissions = Commission.search([ ('origin.invoice', 'in', ids, 'account.invoice.line'), - ('invoice_line', '=', None), ]) - if to_delete: - to_delete_origin = Commission.search([ - ('origin.id', 'in', - [x.id for x in to_delete], 'commission'), - ('invoice_line', '=', None), + if commissions: + commissions_origin = Commission.search([ + ('origin.id', 'in', [c.id for c in commissions], 'commission'), ]) - if to_delete_origin: - to_delete += to_delete_origin - Commission.delete(to_delete) + if commissions_origin: + commissions += commissions_origin + Commission.delete(commissions) + return super(Invoice, cls).draft(invoices) diff --git a/invoice.py b/invoice.py index 4e08c62..e869871 100644 --- a/invoice.py +++ b/invoice.py @@ -1,9 +1,8 @@ # This file is part account_invoice_posted2draft module for Tryton. # The COPYRIGHT file at the top level of this repository contains # the full copyright notices and license terms. -from trytond.pool import Pool, PoolMeta -from trytond.model import fields from trytond.pyson import Eval +from trytond.pool import Pool, PoolMeta from trytond.transaction import Transaction from trytond.i18n import gettext from trytond.exceptions import UserError @@ -12,35 +11,14 @@ from trytond.exceptions import UserError class Invoice(metaclass=PoolMeta): __name__ = 'account.invoice' - allow_draft = fields.Function( - fields.Boolean("Allow Draft Invoice"), 'get_allow_draft') - @classmethod def __setup__(cls): super(Invoice, cls).__setup__() + cls._check_modify_exclude.add('move') cls._transitions |= set((('posted', 'draft'),)) - cls._buttons['draft']['invisible'] = ~Eval('allow_draft', False) - cls._buttons['draft']['depends'] += tuple(['allow_draft']) - - def get_allow_draft(self, name): - # when IN invoice is validate from scratch, the move is in 'draft' - # state, so in this case could be draft in a "normal" way - if (self.state == 'validated' and self.move - and self.move.state != 'draft'): - return False - elif self.state == 'cancelled' and self.number is not None: - return False - elif self.state in {'paid', 'draft'}: - return False - elif self.state == 'posted': - lines_to_pay = [l for l in self.lines_to_pay - if not l.reconciliation] - # Invoice already paid or partial paid, should not be possible - # to change state to draft. - if (not lines_to_pay - or self.amount_to_pay != self.total_amount): - return False - return True + cls._buttons['draft']['invisible'] = ( + Eval('state').in_(['draft', 'paid']) | ( + (Eval('state') == 'cancelled') & Eval('cancel_move'))) @classmethod def draft(cls, invoices): @@ -48,54 +26,64 @@ class Invoice(metaclass=PoolMeta): Move = pool.get('account.move') MoveLine = pool.get('account.move.line') JournalPeriod = pool.get('account.journal.period') - Warning = pool.get('res.user.warning') moves = [] - move_lines = [] - to_draft = [] - to_save = [] + payment_lines = [] for invoice in invoices: - if not invoice.allow_draft: - continue + if invoice.move: + # check period is closed + if invoice.move.period.state == 'close': + raise UserError(gettext( + 'account_invoice_posted2draft.msg_draft_closed_period', + invoice=invoice.rec_name, + period=invoice.move.period.rec_name, + )) + # check period and journal is closed + journal_periods = JournalPeriod.search([ + ('journal', '=', invoice.move.journal.id), + ('period', '=', invoice.move.period.id), + ], limit=1) + if journal_periods: + journal_period, = journal_periods + if journal_period.state == 'close': + raise UserError(gettext( + 'account_invoice_posted2draft.' + 'msg_modify_closed_journal_period', + invoice=invoice.rec_name, + journal_period=journal_period.rec_name)) + moves.append(invoice.move) + if invoice.payment_lines: + for payment_line in invoice.payment_lines: + if payment_line.move and payment_line.move.lines: + for lines in payment_line.move.lines: + payment_lines.append(lines) - move = invoice.move - if move: - if move.state == 'draft': - to_draft.append(invoice) - else: - to_save.append(invoice) - cancel_move = move.cancel() - Move.post([cancel_move]) - moves.extend((invoice.move, cancel_move)) - invoice.move = None - else: - to_draft.append(invoice) - if invoice.cancel_move: - moves.append(invoice.cancel_move) - invoice.cancel_move = None - invoice.additional_moves += tuple(moves) + if moves: + with Transaction().set_context(draft_invoices=True): + Move.write(moves, {'state': 'draft'}) + # If the payment lines dont have a reconciliation, then the field + # invoice_payment will be fill up, and when we try to draft an + # invoice it will give us an error + if payment_lines: + MoveLine.write(payment_lines, {'invoice_payment':None}) + cls.write(invoices, { + 'invoice_report_format': None, + 'invoice_report_cache': None, + }) + with Transaction().set_context(draft_invoices=True): + return super(Invoice, cls).draft(invoices) - # Only make the special steps for the invoices that came from 'posted' - # state or 'validated', 'cancelled' with number, so the invoice have one - # or more move associated. - # The other possible invoices follow the standard workflow. - if to_draft: - super().draft(to_draft) - if to_save: - cls.save(to_save) - with Transaction().set_context(invoice_posted2draft=True): - super().draft(to_save) + @classmethod + def credit(cls, invoices, refund=False, **values): + with Transaction().set_context(cancel_from_credit=True): + return super().credit(invoices, refund, **values) - for invoice in to_save: - to_reconcile = [] - for move in invoice.additional_moves: - for line in move.lines: - if (not line.reconciliation - and line.account == invoice.account): - to_reconcile.append(line) - if to_reconcile: - MoveLine.reconcile(to_reconcile) - # Remove links to lines which actually do not pay the invoice - if to_save: - cls._clean_payments(to_save) +class Move(metaclass=PoolMeta): + __name__ = 'account.move' + + @classmethod + def check_modify(cls, *args, **kwargs): + if Transaction().context.get('draft_invoices', False): + return + return super(Move, cls).check_modify(*args, **kwargs) diff --git a/locale/ca.po b/locale/ca.po index 0c91f7a..7931d08 100644 --- a/locale/ca.po +++ b/locale/ca.po @@ -2,26 +2,22 @@ msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" -msgctxt "field:account.invoice,allow_draft:" -msgid "Allow Draft Invoice" -msgstr "Permet factura esborrany" +msgctxt "model:ir.message,text:msg_cancel_invoice_with_number" +msgid "You cannot cancel invoice \"%(invoice)s\" because it already has a number." +msgstr "No podeu cancel·lar la factura \"%(invoice)s\" amb un número assignat." msgctxt "model:ir.message,text:msg_draft_closed_period" msgid "" -"You cannot create an account compesantion move in the period %(period)s " -"because is closed." +"You can not set to draft invoice \"%(invoice)s\" because period " +"\"%(period)s\" is closed." msgstr "" -"No podeu crear un assentamet de compensació en el període %(period)s perquè " -"està tancat." +"No es pot passar a esborrany la factura \"%(invoice)s\" perquè el període " +"\"%(period)s\" està tancat." -msgctxt "model:ir.message,text:msg_invoice_in_payment" +msgctxt "model:ir.message,text:msg_modify_closed_journal_period" msgid "" -"The invoice %(invoice)s could not be possible to draft, becasue it have one " -"or more move lines in payments [IDs: %(payments)s]. This means that is " -"possible that this payment will be in a payment group and this group upload " -"on a Bank." +"You can not set to draft invoice \"%(invoice)s\" on closed journal-period " +"\"%(journal_period)s\"." msgstr "" -"La factura %(invoice)s no es pot passar a esborrany, perquè té un o més " -"apunts relacionats a pagaments [ID: %(payments)s]. Això vol dir que és " -"possible que aquest pagament estigui en una remesa bancària i aquesta estigui " -"pujada ja al Banc." +"No es pot passar a esborrany la factura \"%(invoice)s\" perquè el diari-" +"període \"%(journal_period)s\". està tancat." diff --git a/locale/es.po b/locale/es.po index f1f17f2..294ed0e 100644 --- a/locale/es.po +++ b/locale/es.po @@ -2,26 +2,22 @@ msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" -msgctxt "field:account.invoice,allow_draft:" -msgid "Allow Draft Invoice" -msgstr "Permitir factura borrador" +msgctxt "model:ir.message,text:msg_cancel_invoice_with_number" +msgid "You cannot cancel invoice \"%(invoice)s\" because it already has a number." +msgstr "No puede cancelar la factura \"%(invoice)s\" con un número asignado." msgctxt "model:ir.message,text:msg_draft_closed_period" msgid "" -"You cannot create an account compesantion move in the period %(period)s " -"because is closed." +"You can not set to draft invoice \"%(invoice)s\" because period " +"\"%(period)s\" is closed." msgstr "" -"No puedes crear un asiento de compensación en el periodo %(period)s porque " -"está cerrado." +"No se puede pasar a borrador la factura \"%(invoice)s\" porqué el período " +"\"%(period)s\" está cerrado." -msgctxt "model:ir.message,text:msg_invoice_in_payment" +msgctxt "model:ir.message,text:msg_modify_closed_journal_period" msgid "" -"The invoice %(invoice)s could not be possible to draft, becasue it have one " -"or more move lines in payments [IDs: %(payments)s]. This means that is " -"possible that this payment will be in a payment group and this group upload " -"on a Bank." +"You can not set to draft invoice \"%(invoice)s\" on closed journal-period " +"\"%(journal_period)s\"." msgstr "" -"La factura %(invoice)s no se puede pasar a borrador, porque tiene uno o más " -"apuntes relacionados a pagos [ID: %(payments)s]. Esto quiere decir que és " -"posible que estos pagos esten ya en una remesa bancárea y ésta esté subida " -"al Banco." +"No se puede pasar a borrador la factura \"%(invoice)s\" porqué el diario-" +"período \"%(journal_period)s\" está cerrado." diff --git a/messages.xml b/messages.xml index 2073dbd..cb1160d 100644 --- a/messages.xml +++ b/messages.xml @@ -4,10 +4,13 @@ this repository contains the full copyright notices and license terms. --> - You cannot create an account compesantion move in the period %(period)s because is closed. + You can not set to draft invoice "%(invoice)s" because period "%(period)s" is closed. - - The invoice %(invoice)s could not be possible to draft, becasue it have one or more move lines in payments [IDs: %(payments)s]. This means that is possible that this payment will be in a payment group and this group upload on a Bank. + + You cannot cancel invoice "%(invoice)s" because it already has a number. + + + You can not set to draft invoice "%(invoice)s" on closed journal-period "%(journal_period)s". diff --git a/move.py b/move.py deleted file mode 100644 index 95008b2..0000000 --- a/move.py +++ /dev/null @@ -1,40 +0,0 @@ -# This file is part account_invoice_posted2draft module for Tryton. -# The COPYRIGHT file at the top level of this repository contains -# the full copyright notices and license terms. -from trytond.pool import Pool, PoolMeta -from trytond.transaction import Transaction - - -class Move(metaclass=PoolMeta): - __name__ = 'account.move' - - @classmethod - def check_modify(cls, *args, **kwargs): - # As now the moves related to an invoice are not delete when 'draft' - # the invoice, is needed to modify some restricted fields when the - # move is in post state - if Transaction().context.get('invoice_posted2draft', False): - return - return super().check_modify(*args, **kwargs) - - @classmethod - def delete(cls, moves): - # When invoice is set to 'draft', try to delete the move's associated - # in 'move' and 'additional_move' fields. If these moves are posted - # they cannot be deleted but keep them as history - if Transaction().context.get('invoice_posted2draft', False): - return - super().delete(moves) - - -class Line(metaclass=PoolMeta): - __name__ = 'account.move.line' - - @classmethod - def check_modify(cls, lines, modified_fields=None): - # As now the moves related to an invoice are not delete when 'draft' - # the invoice, is needed to modify some restricted fields when the - # move is in post state - if Transaction().context.get('invoice_posted2draft', False): - return - return super().check_modify(lines, modified_fields) diff --git a/payment.py b/payment.py index 4f07d90..d15997f 100644 --- a/payment.py +++ b/payment.py @@ -2,8 +2,8 @@ # The COPYRIGHT file at the top level of this repository contains # the full copyright notices and license terms. from trytond.pool import Pool, PoolMeta -from trytond.i18n import gettext -from trytond.exceptions import UserError + +__all__ = ['Invoice'] class Invoice(metaclass=PoolMeta): @@ -11,26 +11,18 @@ class Invoice(metaclass=PoolMeta): @classmethod def draft(cls, invoices): - pool = Pool() - Payment = pool.get('account.payment') + Payment = Pool().get('account.payment') + lines = [] for invoice in invoices: - moves = [] if invoice.move: - moves.append(invoice.move) - if invoice.additional_moves: - moves.extend(invoice.additional_moves) + lines.extend([l.id for l in invoice.move.lines]) + if lines: + payments = Payment.search([ + ('line', 'in', lines), + ('state', '=', 'failed'), + ]) + if payments: + Payment.write(payments, {'line': None}) - if moves: - lines = [l.id for m in moves for l in m.lines] - if lines: - payments = Payment.search([ - ('line', 'in', lines), - ('state', '!=', 'failed'), - ]) - if payments: - raise UserError(gettext('account_invoice_posted2draft' - '.msg_invoice_in_payment', - invoice=invoice.rec_name, - payments=", ".join([p.id for p in payments]))) - return super().draft(invoices) + return super(Invoice, cls).draft(invoices)