-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathstatement.py
236 lines (199 loc) · 8.25 KB
/
statement.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# 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
from sql import Null
from sql.operators import Concat
from trytond.model import fields
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Eval, If
from trytond.transaction import Transaction
class Payment(metaclass=PoolMeta):
__name__ = 'account.payment'
statement_lines = fields.One2Many(
'account.statement.line', 'related_to', "Statement Lines",
readonly=True)
@property
def clearing_lines(self):
clearing_account = self.journal.clearing_account
yield from super().clearing_lines
for statement_line in self.statement_lines:
if statement_line.move:
for line in statement_line.move.lines:
if line.account == clearing_account:
yield line
class PaymentGroup(metaclass=PoolMeta):
__name__ = 'account.payment.group'
statement_lines = fields.One2Many(
'account.statement.line', 'related_to', "Statement Lines",
readonly=True)
@property
def clearing_lines(self):
clearing_account = self.journal.clearing_account
yield from super().clearing_lines
for statement_line in self.statement_lines:
if statement_line.move:
for line in statement_line.move.lines:
if line.account == clearing_account:
yield line
class Statement(metaclass=PoolMeta):
__name__ = 'account.statement'
@classmethod
def create_move(cls, statements):
pool = Pool()
Payment = pool.get('account.payment')
moves = super(Statement, cls).create_move(statements)
to_success = defaultdict(set)
to_fail = defaultdict(set)
for move, statement, lines in moves:
for line in lines:
if line.payment:
payments = {line.payment}
kind = line.payment.kind
elif line.payment_group:
payments = set(line.payment_group.payments)
kind = line.payment_group.kind
else:
continue
if (kind == 'receivable') == (line.amount >= 0):
to_success[line.date].update(payments)
else:
to_fail[line.date].update(payments)
# The failing should be done last because success is usually not a
# definitive state
if to_success:
for date, payments in to_success.items():
with Transaction().set_context(clearing_date=date):
Payment.succeed(Payment.browse(payments))
if to_fail:
for date, payments in to_fail.items():
with Transaction().set_context(clearing_date=date):
Payment.fail(Payment.browse(payments))
if to_success or to_fail:
Payment.__queue__.reconcile_clearing(
list(set.union(*to_success.values(), *to_fail.values())))
return moves
def _group_key(self, line):
key = super(Statement, self)._group_key(line)
if hasattr(line, 'payment'):
key += (('payment', line.payment),)
return key
class StatementLine(metaclass=PoolMeta):
__name__ = 'account.statement.line'
@classmethod
def __setup__(cls):
super(StatementLine, cls).__setup__()
cls.related_to.domain['account.payment'] = [
cls.related_to.domain.get('account.payment', []),
If(Eval('statement_state') == 'draft',
('clearing_reconciled', '!=', True),
()),
]
cls.related_to.domain['account.payment.group'] = [
('company', '=', Eval('company', -1)),
('currency', '=', Eval('currency', -1)),
If(Eval('statement_state') == 'draft',
('clearing_reconciled', '!=', True),
()),
]
@classmethod
def __register__(cls, module):
table = cls.__table__()
super().__register__(module)
table_h = cls.__table_handler__(module)
cursor = Transaction().connection.cursor()
# Migration from 6.2: replace payment by related_to
if table_h.column_exist('payment'):
cursor.execute(*table.update(
[table.related_to],
[Concat('account.payment,', table.payment)],
where=table.payment != Null))
table_h.drop_column('payment')
# Migration from 6.2: replace payment_group by related_to
if table_h.column_exist('payment_group'):
cursor.execute(*table.update(
[table.related_to],
[Concat('account.payment.group,', table.payment_group)],
where=table.payment_group != Null))
table_h.drop_column('payment_group')
@classmethod
def _get_relations(cls):
return super()._get_relations() + ['account.payment.group']
@property
@fields.depends('related_to')
def payment_group(self):
pool = Pool()
PaymentGroup = pool.get('account.payment.group')
related_to = getattr(self, 'related_to', None)
if isinstance(related_to, PaymentGroup) and related_to.id >= 0:
return related_to
@payment_group.setter
def payment_group(self, value):
self.related_to = value
@fields.depends(methods=['payment', 'payment_group'])
def on_change_related_to(self):
super().on_change_related_to()
if self.payment:
clearing_account = self.payment.journal.clearing_account
if clearing_account:
self.account = clearing_account
if self.payment_group:
self.party = None
clearing_account = self.payment_group.journal.clearing_account
if clearing_account:
self.account = clearing_account
@fields.depends('party', methods=['payment'])
def on_change_party(self):
super(StatementLine, self).on_change_party()
if self.payment:
if self.payment.party != self.party:
self.payment = None
if self.party:
self.payment_group = None
@fields.depends('account', methods=['payment', 'payment_group'])
def on_change_account(self):
super(StatementLine, self).on_change_account()
if self.payment:
clearing_account = self.payment.journal.clearing_account
elif self.payment_group:
clearing_account = self.payment_group.journal.clearing_account
else:
return
if self.account != clearing_account:
self.payment = None
@classmethod
def post_move(cls, lines):
pool = Pool()
Move = pool.get('account.move')
super(StatementLine, cls).post_move(lines)
Move.post([l.payment.clearing_move for l in lines
if l.payment
and l.payment.clearing_move
and l.payment.clearing_move.state == 'draft'])
class StatementRuleLine(metaclass=PoolMeta):
__name__ = 'account.statement.rule.line'
def get_line(self, origin, keywords, **context):
line = super().get_line(origin, keywords, **context)
if line:
line.payment = self._get_payment(origin, keywords)
if (line.payment and line.party
and line.payment.party != line.party):
return
line.payment_group = self._get_payment_group(origin, keywords)
return line
def _get_payment(self, origin, keywords):
pool = Pool()
Payment = pool.get('account.payment')
if keywords.get('payment'):
payments = Payment.search([('rec_name', '=', keywords['payment'])])
if len(payments) == 1:
payment, = payments
return payment
def _get_payment_group(self, origin, keywords):
pool = Pool()
Payment = pool.get('account.payment.group')
if keywords.get('payment_group'):
groups, = Payment.search(
[('rec_name', '=', keywords['payment_group'])])
if len(groups) == 1:
group, = groups
return group