251 lines
8.0 KiB
Python
251 lines
8.0 KiB
Python
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
|
# this repository contains the full copyright notices and license terms.
|
|
|
|
from operator import attrgetter
|
|
|
|
from num2words import num2words
|
|
|
|
from trytond.i18n import gettext
|
|
from trytond.model import ModelView, fields
|
|
from trytond.pool import Pool, PoolMeta
|
|
from trytond.pyson import Eval, Id, If
|
|
from trytond.report import Report
|
|
from trytond.transaction import Transaction
|
|
from trytond.wizard import (
|
|
Button, StateAction, StateTransition, StateView, Wizard)
|
|
|
|
from .exceptions import CheckNumberError
|
|
|
|
|
|
class PaymentJournal(metaclass=PoolMeta):
|
|
__name__ = 'account.payment.journal'
|
|
|
|
check_sequence = fields.Many2One(
|
|
'ir.sequence.strict', "Check Sequence",
|
|
domain=[
|
|
('company', '=', Eval('company', -1)),
|
|
('sequence_type', '=',
|
|
Id('account_payment_check',
|
|
'sequence_type_account_payment_check')),
|
|
('prefix', '=', ''),
|
|
('suffix', '=', ''),
|
|
('type', '=', 'incremental'),
|
|
('number_increment', '=', 1),
|
|
],
|
|
states={
|
|
'invisible': Eval('process_method') != 'check',
|
|
},
|
|
help="Leave empty for manual numbering.")
|
|
check_max_number = fields.Integer(
|
|
"Maximum Check Number",
|
|
states={
|
|
'invisible': Eval('process_method') != 'check',
|
|
},
|
|
help="The highest check number allowed for this journal.")
|
|
check_format = fields.Many2One(
|
|
'ir.action.report', "Check Format", ondelete='RESTRICT',
|
|
domain=[
|
|
('model', '=', 'account.payment'),
|
|
('report_name', '=', 'account.payment.check'),
|
|
],
|
|
states={
|
|
'invisible': Eval('process_method') != 'check',
|
|
},
|
|
help="The report layout for printing checks.")
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super().__setup__()
|
|
cls.process_method.selection.append(('check', "Check"))
|
|
|
|
|
|
class PaymentGroup(metaclass=PoolMeta):
|
|
__name__ = 'account.payment.group'
|
|
|
|
check_printed = fields.Boolean(
|
|
"Check Printed", readonly=True,
|
|
states={
|
|
'invisible': (
|
|
(Eval('process_method') != 'check')
|
|
| (Eval('kind') != 'payable')),
|
|
})
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super().__setup__()
|
|
cls._buttons.update(
|
|
check_print={
|
|
'invisible': (
|
|
(Eval('process_method') != 'check')
|
|
| (Eval('kind') != 'payable')
|
|
| Eval('check_printed')),
|
|
'depends': ['process_method', 'kind', 'check_printed'],
|
|
},
|
|
)
|
|
|
|
def process_check(self):
|
|
pass
|
|
|
|
@classmethod
|
|
@ModelView.button_action(
|
|
'account_payment_check.account_payment_check_print')
|
|
def check_print(cls, groups):
|
|
pass
|
|
|
|
|
|
class Payment(metaclass=PoolMeta):
|
|
__name__ = 'account.payment'
|
|
|
|
check_printed = fields.Function(
|
|
fields.Boolean("Check Printed"),
|
|
'get_check_printed')
|
|
check_number = fields.Char(
|
|
"Check Number",
|
|
states={
|
|
'readonly': Eval('state') != 'draft',
|
|
'invisible': Eval('process_method') != 'check',
|
|
'required': If(Eval('kind') == 'receivable',
|
|
Eval('state') != 'draft',
|
|
Eval('check_printed', False),
|
|
),
|
|
})
|
|
|
|
def get_check_printed(self, name):
|
|
return self.group.check_printed if self.group else None
|
|
|
|
@classmethod
|
|
def view_attributes(cls):
|
|
return super().view_attributes() + [
|
|
('//page[id="check"]', 'states', {
|
|
'invisible': Eval('process_method') != 'check',
|
|
}),
|
|
]
|
|
|
|
@classmethod
|
|
def process_method_with_group(cls):
|
|
return super().process_method_with_group() + ['check']
|
|
|
|
|
|
class PaymentCheckPrint(Wizard):
|
|
__name__ = 'account.payment.check.print'
|
|
|
|
start = StateTransition()
|
|
number = StateView(
|
|
'account.payment.check.print.number',
|
|
'account_payment_check.account_payment_check_print_number_view_form', [
|
|
Button("Cancel", 'end', 'tryton-cancel'),
|
|
Button("Print", 'print_', 'tryton-print'),
|
|
])
|
|
print_ = StateAction(
|
|
'account_payment_check.report_account_payment_check_print')
|
|
|
|
def transition_start(self):
|
|
if (self.record.process_method != 'check'
|
|
or self.record.check_printed):
|
|
return 'end'
|
|
elif not self.record.journal.check_sequence:
|
|
return 'number'
|
|
else:
|
|
return 'print_'
|
|
|
|
def do_print_(self, action):
|
|
pool = Pool()
|
|
Payment = pool.get('account.payment')
|
|
|
|
payments = self.record.payments
|
|
sequence = self.record.journal.check_sequence
|
|
if sequence:
|
|
for payment, number in zip(
|
|
payments, sequence.get_many(len(payments))):
|
|
payment.check_number = number
|
|
else:
|
|
padding = len(self.number.start_number)
|
|
start_number = int(self.number.start_number)
|
|
for number, payment in enumerate(payments, start_number):
|
|
payment.check_number = f'{number:0>{padding}d}'
|
|
|
|
if max_number := self.record.journal.check_max_number:
|
|
if max_number < max(
|
|
map(int, map(attrgetter('check_number'), payments))):
|
|
raise CheckNumberError(gettext(
|
|
'account_payment_check.'
|
|
'msg_payment_group_journal_max_number',
|
|
group=self.record.rec_name,
|
|
journal=self.record.journal.rec_name,
|
|
))
|
|
Payment.save(payments)
|
|
self.record.check_printed = True
|
|
self.record.save()
|
|
|
|
if self.record.journal.check_format:
|
|
action.update(
|
|
self.record.journal.check_format.action.get_action_value())
|
|
return action, {'ids': list(map(int, payments))}
|
|
|
|
|
|
class PaymentCheckPrintNumber(ModelView):
|
|
__name__ = 'account.payment.check.print.number'
|
|
|
|
start_number = fields.Char("Start Number", required=True)
|
|
|
|
|
|
class PaymentCheck(Report):
|
|
__name__ = 'account.payment.check'
|
|
|
|
@classmethod
|
|
def get_context(cls, records, header, data):
|
|
context = super().get_context(records, header, data)
|
|
context['num2words'] = cls.num2words
|
|
return context
|
|
|
|
@classmethod
|
|
def num2words(cls, number, lang=None, **kwargs):
|
|
if lang is None:
|
|
lang = Transaction().language
|
|
try:
|
|
return num2words(number, lang=lang, **kwargs)
|
|
except NotImplementedError:
|
|
return num2words(number, **kwargs)
|
|
|
|
|
|
class StatementRule(metaclass=PoolMeta):
|
|
__name__ = 'account.statement.rule'
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super().__setup__()
|
|
cls.description.help += "\n'check'"
|
|
|
|
|
|
class StatementRuleLine(metaclass=PoolMeta):
|
|
__name__ = 'account.statement.rule.line'
|
|
|
|
@classmethod
|
|
def _get_payment_check_domain(cls, number, origin):
|
|
return [
|
|
('check_number', '=', number),
|
|
('company', '=', origin.company.id),
|
|
('currency', '=', origin.currency.id),
|
|
('state', 'in', ['processing', 'succeeded', 'failed']),
|
|
]
|
|
|
|
def _get_payment(self, origin, keywords, party=None, amount=0):
|
|
pool = Pool()
|
|
Payment = pool.get('account.payment')
|
|
|
|
payment = super()._get_payment(
|
|
origin, keywords, party=party, amount=amount)
|
|
|
|
if keywords.get('check'):
|
|
domain = self._get_payment_check_domain(keywords['check'], origin)
|
|
if party:
|
|
domain.append(('party', '=', party.id))
|
|
if amount > 0:
|
|
domain.append(('kind', '=', 'receivable'))
|
|
elif amount < 0:
|
|
domain.append(('kind', '=', 'payable'))
|
|
payments = Payment.search(domain)
|
|
if len(payments) == 1:
|
|
payment, = payments
|
|
return payment
|