Files
tryton/modules/account_dunning_fee/dunning.py
T

191 lines
6.6 KiB
Python
Raw Normal View History

2016-06-27 19:36:56 +02:00
# 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 collections import defaultdict
2021-12-11 17:58:41 +01:00
from trytond.model import DeactivableMixin, ModelSQL, ModelView, Unique, fields
from trytond.modules.currency.fields import Monetary
from trytond.pool import Pool, PoolMeta
2016-06-27 19:36:56 +02:00
from trytond.pyson import Eval
from trytond.transaction import Transaction
2018-03-26 14:16:30 +02:00
class Fee(DeactivableMixin, ModelSQL, ModelView):
2016-06-27 19:36:56 +02:00
'Account Dunning Fee'
__name__ = 'account.dunning.fee'
name = fields.Char('Name', required=True, translate=True)
product = fields.Many2One('product.product', 'Product', required=True,
domain=[
('type', '=', 'service'),
('template.type', '=', 'service'),
])
journal = fields.Many2One('account.journal', 'Journal', required=True)
compute_method = fields.Selection([
('list_price', 'List Price'),
('percentage', 'Percentage'),
], 'Compute Method', required=True,
help='Method to compute the fee amount')
percentage = fields.Numeric('Percentage', digits=(16, 8),
states={
'invisible': Eval('compute_method') != 'percentage',
'required': Eval('compute_method') == 'percentage',
})
2016-06-27 19:36:56 +02:00
def get_list_price(self, dunning, **pattern):
pattern.setdefault('company', dunning.company.id)
return self.product.get_multivalue('list_price', **pattern)
2016-06-27 19:36:56 +02:00
def get_amount(self, dunning):
'Return fee amount and currency'
amount, currency = None, None
if self.compute_method == 'list_price':
currency = dunning.company.currency
amount = currency.round(self.get_list_price(dunning))
2016-06-27 19:36:56 +02:00
elif self.compute_method == 'percentage':
if dunning.second_currency:
amount = dunning.amount_second_currency
currency = dunning.second_currency
else:
amount = dunning.amount
currency = dunning.company.currency
amount = currency.round(amount * self.percentage)
return amount, currency
2018-06-26 19:11:41 +02:00
class Level(metaclass=PoolMeta):
2016-06-27 19:36:56 +02:00
__name__ = 'account.dunning.level'
fee = fields.Many2One('account.dunning.fee', 'Fee')
2018-06-26 19:11:41 +02:00
class Dunning(metaclass=PoolMeta):
2016-06-27 19:36:56 +02:00
__name__ = 'account.dunning'
fees = fields.One2Many(
'account.dunning.fee.dunning_level', 'dunning', 'Fees', readonly=True)
@classmethod
def process(cls, dunnings):
pool = Pool()
FeeDunningLevel = pool.get('account.dunning.fee.dunning_level')
fees = []
for dunning in dunnings:
if dunning.blocked or not dunning.level.fee:
continue
if dunning.level in {f.level for f in dunning.fees}:
continue
fee = FeeDunningLevel(dunning=dunning, level=dunning.level)
fee.amount, fee.currency = dunning.level.fee.get_amount(dunning)
fees.append(fee)
FeeDunningLevel.save(fees)
FeeDunningLevel.process(fees)
super(Dunning, cls).process(dunnings)
class FeeDunningLevel(ModelSQL, ModelView):
'Account Dunning Fee Dunning-Level'
__name__ = 'account.dunning.fee.dunning_level'
dunning = fields.Many2One(
'account.dunning', "Dunning", required=True)
2016-06-27 19:36:56 +02:00
level = fields.Many2One('account.dunning.level', 'Level', required=True)
2021-08-21 09:09:55 +02:00
amount = Monetary(
"Amount", currency='currency', digits='currency')
2016-06-27 19:36:56 +02:00
currency = fields.Many2One('currency.currency', 'Currency')
moves = fields.One2Many('account.move', 'origin', 'Moves', readonly=True)
@classmethod
def __setup__(cls):
super(FeeDunningLevel, cls).__setup__()
t = cls.__table__()
cls._sql_constraints = [
('dunning_level_unique', Unique(t, t.dunning, t.level),
2018-12-29 14:20:28 +01:00
'account_dunning_fee.msg_fee_dunning_level_unique'),
2016-06-27 19:36:56 +02:00
]
def get_rec_name(self, name):
return '%s @ %s' % (self.dunning.rec_name, self.level.rec_name)
@classmethod
def search_rec_name(cls, name, clause):
_, operator, value = clause
if operator.startswith('!') or operator.startswith('not '):
bool_op = 'AND'
else:
bool_op = 'OR'
return [bool_op,
('dunning.rec_name', *clause[1:]),
('level.rec_name', *clause[1:]),
2016-06-27 19:36:56 +02:00
]
@classmethod
def process(cls, fees):
pool = Pool()
Move = pool.get('account.move')
moves = []
for fee in fees:
move = fee.get_move_process()
moves.append(move)
Move.save(moves)
Move.post(moves)
def get_move_process(self):
pool = Pool()
Move = pool.get('account.move')
Line = pool.get('account.move.line')
Date = pool.get('ir.date')
Period = pool.get('account.period')
Currency = pool.get('currency.currency')
with Transaction().set_context(company=self.dunning.company.id):
today = Date.today()
2016-06-27 19:36:56 +02:00
move = Move()
move.company = self.dunning.company
move.journal = self.level.fee.journal
move.date = today
move.period = Period.find(move.company, date=today)
2016-06-27 19:36:56 +02:00
move.origin = self
move.description = self.level.fee.name
line = Line()
if self.currency == move.company.currency:
line.debit = self.amount
else:
line.second_currency = self.currency
line.amount_second_currency = self.amount
line.debit = Currency.compute(
self.currency, self.amount, move.company.currency)
line.account = self.dunning.line.account
line.party = self.dunning.line.party
counterpart = Line()
counterpart.credit = line.debit
counterpart.account = self.level.fee.product.account_revenue_used
2016-06-27 19:36:56 +02:00
if counterpart.account and counterpart.account.party_required:
counterpart.party = self.dunning.party
move.lines = [line, counterpart]
return move
# TODO create move with taxes on reconcile of process move line
2018-06-26 19:11:41 +02:00
class Letter(metaclass=PoolMeta):
2016-06-27 19:36:56 +02:00
__name__ = 'account.dunning.letter'
@classmethod
def get_party_letter(cls):
PartyLetter = super(Letter, cls).get_party_letter()
class PartyLetterFee(PartyLetter):
@property
def fees(self):
2018-10-31 18:17:35 +01:00
fees = defaultdict(int)
2016-06-27 19:36:56 +02:00
fees.update(super(PartyLetterFee, self).fees)
for dunning in self.dunnings:
for fee in dunning.fees:
fees[fee.currency] += fee.amount
return fees
return PartyLetterFee