trytond-account_payment_pro.../payment.py

225 lines
8.3 KiB
Python
Raw Normal View History

2016-06-28 11:43:34 +02:00
# The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms.
2016-06-30 15:09:50 +02:00
from collections import defaultdict
from decimal import Decimal
from trytond.model import ModelView, Workflow, fields
2016-06-28 11:43:34 +02:00
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Bool, Eval
2016-06-30 15:09:50 +02:00
from trytond.transaction import Transaction
2016-06-28 11:43:34 +02:00
__all__ = ['Journal', 'Payment']
2019-05-09 21:55:53 +02:00
class Journal(metaclass=PoolMeta):
2016-06-28 11:43:34 +02:00
__name__ = 'account.payment.journal'
processing_account = fields.Many2One('account.account',
'Processing Account', states={
'required': Bool(Eval('processing_journal')),
},
depends=['processing_journal'])
processing_journal = fields.Many2One('account.journal',
'Processing Journal', states={
'required': Bool(Eval('processing_account')),
},
depends=['processing_account'])
2022-05-06 13:52:16 +02:00
@classmethod
def __setup__(cls):
super().__setup__()
cls.clearing_journal.context = {'company': Eval('company', -1)}
2022-05-06 13:54:49 +02:00
cls.clearing_journal.depends.add('company')
cls.processing_journal.context = {'company': Eval('company', -1)}
2022-05-06 13:54:49 +02:00
cls.processing_journal.depends.add('company')
2022-05-06 13:52:16 +02:00
2016-06-28 11:43:34 +02:00
2019-05-09 21:55:53 +02:00
class Payment(metaclass=PoolMeta):
2016-06-28 11:43:34 +02:00
__name__ = 'account.payment'
processing_move = fields.Many2One('account.move', 'Processing Move',
readonly=True)
@classmethod
@Workflow.transition('processing')
def process(cls, payments, group):
pool = Pool()
Move = pool.get('account.move')
2016-06-30 15:09:50 +02:00
Line = pool.get('account.move.line')
2016-06-28 11:43:34 +02:00
group = super(Payment, cls).process(payments, group)
moves = []
for payment in payments:
move = payment.create_processing_move()
if move:
moves.append(move)
if moves:
2019-01-04 09:37:23 +01:00
Move.save(moves)
2016-06-28 11:43:34 +02:00
cls.write(*sum((([m.origin], {'processing_move': m.id})
for m in moves), ()))
Move.post(moves)
2016-06-30 15:09:50 +02:00
to_reconcile = defaultdict(list)
for payment in payments:
if (payment.line
and not payment.line.reconciliation
and payment.processing_move):
lines = [l for l in payment.processing_move.lines
if l.account == payment.line.account] + [payment.line]
if not sum(l.debit - l.credit for l in lines):
to_reconcile[payment.party].extend(lines)
2019-05-09 21:55:53 +02:00
for lines in list(to_reconcile.values()):
2016-06-30 15:09:50 +02:00
Line.reconcile(lines)
2016-06-28 11:43:34 +02:00
return group
def create_processing_move(self, date=None):
2016-06-28 11:43:34 +02:00
pool = Pool()
2016-06-30 15:09:50 +02:00
Currency = pool.get('currency.currency')
2016-06-28 11:43:34 +02:00
Move = pool.get('account.move')
Line = pool.get('account.move.line')
Period = pool.get('account.period')
Date = pool.get('ir.date')
if not self.line:
return
if (not self.journal.processing_account
or not self.journal.processing_journal):
return
2019-01-04 09:37:23 +01:00
2016-06-28 11:43:34 +02:00
if self.processing_move:
return self.processing_move
if date is None:
date = Date.today()
2016-06-28 11:43:34 +02:00
period = Period.find(self.company.id, date=date)
2016-06-30 15:09:50 +02:00
# compatibility with account_bank_statement_payment
clearing_percent = getattr(
self.journal, 'clearing_percent', Decimal(1)) or Decimal(1)
processing_amount = self.amount * clearing_percent
local_currency = self.journal.currency == self.company.currency
if not local_currency:
with Transaction().set_context(date=self.date):
local_amount = Currency.compute(
self.journal.currency, processing_amount,
self.company.currency)
else:
local_amount = self.company.currency.round(processing_amount)
2016-06-30 15:09:50 +02:00
2016-06-28 11:43:34 +02:00
move = Move(
journal=self.journal.processing_journal,
origin=self,
date=date,
period=period)
line = Line()
if self.kind == 'payable':
2016-06-30 15:09:50 +02:00
line.debit, line.credit = local_amount, 0
2016-06-28 11:43:34 +02:00
else:
2016-06-30 15:09:50 +02:00
line.debit, line.credit = 0, local_amount
2016-06-28 11:43:34 +02:00
line.account = self.line.account
2016-06-30 15:09:50 +02:00
if not local_currency:
line.amount_second_currency = processing_amount
line.second_currency = self.journal.currency
2016-06-28 11:43:34 +02:00
line.party = (self.line.party
if self.line.account.party_required else None)
counterpart = Line()
if self.kind == 'payable':
2016-06-30 15:09:50 +02:00
counterpart.debit, counterpart.credit = 0, local_amount
2016-06-28 11:43:34 +02:00
else:
2016-06-30 15:09:50 +02:00
counterpart.debit, counterpart.credit = local_amount, 0
2016-06-28 11:43:34 +02:00
counterpart.account = self.journal.processing_account
2016-06-30 15:09:50 +02:00
if not local_currency:
counterpart.amount_second_currency = -processing_amount
counterpart.second_currency = self.journal.currency
2016-06-28 11:43:34 +02:00
counterpart.party = (self.line.party
if self.journal.processing_account.party_required else None)
2016-06-30 15:09:50 +02:00
2016-06-28 11:43:34 +02:00
move.lines = (line, counterpart)
return move
2016-06-30 15:09:50 +02:00
@classmethod
@ModelView.button
@Workflow.transition('succeeded')
def succeed(cls, payments):
pool = Pool()
Line = pool.get('account.move.line')
super(Payment, cls).succeed(payments)
for payment in payments:
if (payment.journal.processing_account
and payment.journal.processing_account.reconcile
and payment.processing_move
and payment.journal.clearing_account
and payment.journal.clearing_account.reconcile
and payment.clearing_move):
to_reconcile = defaultdict(list)
lines = (payment.processing_move.lines
+ payment.clearing_move.lines)
for line in lines:
if line.account.reconcile and not line.reconciliation:
key = (
line.account.id,
line.party.id if line.party else None)
to_reconcile[key].append(line)
2019-05-09 21:55:53 +02:00
for lines in list(to_reconcile.values()):
2016-06-30 15:09:50 +02:00
if not sum((l.debit - l.credit) for l in lines):
Line.reconcile(lines)
def _get_clearing_move(self, date=None):
move = super(Payment, self)._get_clearing_move(date=date)
2016-06-28 11:43:34 +02:00
if move and self.processing_move:
for line in move.lines:
2016-06-30 15:09:50 +02:00
if line.account == self.line.account:
2016-06-28 11:43:34 +02:00
line.account = self.journal.processing_account
line.party = (self.line.party
if line.account.party_required else None)
return move
2016-06-30 15:09:50 +02:00
@classmethod
@ModelView.button
@Workflow.transition('failed')
def fail(cls, payments):
pool = Pool()
Move = pool.get('account.move')
Line = pool.get('account.move.line')
Reconciliation = pool.get('account.move.reconciliation')
super(Payment, cls).fail(payments)
to_delete = []
to_reconcile = defaultdict(lambda: defaultdict(list))
to_unreconcile = []
to_post = []
for payment in payments:
if payment.processing_move:
if payment.processing_move.state == 'draft':
to_delete.append(payment.processing_move)
for line in payment.processing_move.lines:
if line.reconciliation:
to_unreconcile.append(line.reconciliation)
else:
cancel_move = payment.processing_move.cancel()
to_post.append(cancel_move)
for line in (payment.processing_move.lines
+ cancel_move.lines):
if line.reconciliation:
to_unreconcile.append(line.reconciliation)
if line.account.reconcile:
to_reconcile[payment.party][line.account].append(
line)
if to_unreconcile:
Reconciliation.delete(to_unreconcile)
if to_delete:
Move.delete(to_delete)
if to_post:
Move.post(to_post)
for party in to_reconcile:
2019-05-09 21:55:53 +02:00
for lines in list(to_reconcile[party].values()):
2016-06-30 15:09:50 +02:00
Line.reconcile(lines)
cls.write(payments, {'processing_move': None})