trytond-account_invoice_pos.../invoice.py

110 lines
4.0 KiB
Python

# 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.transaction import Transaction
from trytond.i18n import gettext
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._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
@classmethod
def draft(cls, invoices):
pool = Pool()
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 = []
for invoice in invoices:
if not invoice.allow_draft:
continue
move = invoice.move
if move:
if move.state == 'draft':
to_draft.append(invoice)
else:
to_save.append(invoice)
cancel_move = move.cancel(reversal=True)
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)
invoice.invoice_report_format = None
invoice.invoice_report_cache = None
# 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)
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)
@classmethod
def check_modify(cls, invoices):
if Transaction().context.get('invoice_posted2draft', False):
return
return super().check_modify(invoices)