-
-
Notifications
You must be signed in to change notification settings - Fork 536
/
Copy pathaccount_payment_line.py
222 lines (208 loc) · 8.58 KB
/
account_payment_line.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
# © 2015-2016 Akretion - Alexis de Lattre <[email protected]>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import _, api, fields, models
from odoo.exceptions import UserError
class AccountPaymentLine(models.Model):
_name = "account.payment.line"
_description = "Payment Lines"
_check_company_auto = True
name = fields.Char(string="Payment Reference", readonly=True, copy=False)
order_id = fields.Many2one(
comodel_name="account.payment.order",
string="Payment Order",
ondelete="cascade",
index=True,
check_company=True,
)
company_id = fields.Many2one(
related="order_id.company_id", store=True, readonly=True
)
company_currency_id = fields.Many2one(
related="order_id.company_currency_id", store=True, readonly=True
)
payment_type = fields.Selection(
related="order_id.payment_type", store=True, readonly=True
)
bank_account_required = fields.Boolean(
related="order_id.payment_method_id.bank_account_required", readonly=True
)
state = fields.Selection(
related="order_id.state", string="State", readonly=True, store=True
)
move_line_id = fields.Many2one(
comodel_name="account.move.line",
string="Journal Item",
ondelete="restrict",
check_company=True,
)
ml_maturity_date = fields.Date(related="move_line_id.date_maturity", readonly=True)
currency_id = fields.Many2one(
comodel_name="res.currency",
string="Currency of the Payment Transaction",
required=True,
default=lambda self: self.env.user.company_id.currency_id,
)
amount_currency = fields.Monetary(string="Amount", currency_field="currency_id")
amount_company_currency = fields.Monetary(
compute="_compute_amount_company_currency",
string="Amount in Company Currency",
currency_field="company_currency_id",
)
partner_id = fields.Many2one(
comodel_name="res.partner",
string="Partner",
required=True,
domain=[("parent_id", "=", False)],
check_company=True,
)
partner_bank_id = fields.Many2one(
comodel_name="res.partner.bank",
string="Partner Bank Account",
required=False,
ondelete="restrict",
check_company=True,
)
partner_bank_acc_type = fields.Selection(
related="partner_bank_id.acc_type", string="Bank Account Type"
)
date = fields.Date(string="Payment Date")
# communication field is required=False because we don't want to block
# the creation of lines from move/invoices when communication is empty
# This field is required in the form view and there is an error message
# when going from draft to confirm if the field is empty
communication = fields.Char(
required=False, help="Label of the payment that will be seen by the destinee"
)
communication_type = fields.Selection(
selection=[("normal", "Free")], required=True, default="normal"
)
payment_ids = fields.Many2many(
comodel_name="account.payment",
string="Payment transaction",
readonly=True,
)
_sql_constraints = [
(
"name_company_unique",
"unique(name, company_id)",
"A payment line already exists with this reference in the same company!",
)
]
@api.model
def create(self, vals):
if vals.get("name", "New") == "New":
vals["name"] = (
self.env["ir.sequence"].next_by_code("account.payment.line") or "New"
)
return super(AccountPaymentLine, self).create(vals)
@api.depends("amount_currency", "currency_id", "company_currency_id", "date")
def _compute_amount_company_currency(self):
for line in self:
if line.currency_id and line.company_currency_id:
line.amount_company_currency = line.currency_id._convert(
line.amount_currency,
line.company_currency_id,
line.company_id,
line.date or fields.Date.today(),
)
else:
line.amount_company_currency = 0
@api.model
def _get_payment_line_grouping_fields(self):
"""This list of fields is used o compute the grouping hashcode."""
return [
"currency_id",
"partner_id",
"partner_bank_id",
"date",
"communication_type",
]
def payment_line_hashcode(self):
self.ensure_one()
values = []
for field in self._get_payment_line_grouping_fields():
values.append(str(self[field]))
# Don't group the payment lines that are attached to the same supplier
# but to move lines with different accounts (very unlikely),
# for easier generation/comprehension of the transfer move
values.append(str(self.move_line_id.account_id or False))
# Don't group the payment lines that use a structured communication
# otherwise it would break the structured communication system !
if self.communication_type != "normal":
values.append(str(self.id))
return "-".join(values)
@api.onchange("partner_id")
def partner_id_change(self):
partner_bank = False
if self.partner_id.bank_ids:
partner_bank = self.partner_id.bank_ids[0]
self.partner_bank_id = partner_bank
@api.onchange("move_line_id")
def move_line_id_change(self):
if self.move_line_id:
vals = self.move_line_id._prepare_payment_line_vals(self.order_id)
vals.pop("order_id")
for field, value in vals.items():
self[field] = value
else:
self.partner_id = False
self.partner_bank_id = False
self.amount_currency = 0.0
self.currency_id = self.env.user.company_id.currency_id
self.communication = False
def invoice_reference_type2communication_type(self):
"""This method is designed to be inherited by
localization modules"""
# key = value of 'reference_type' field on account_invoice
# value = value of 'communication_type' field on account_payment_line
res = {"none": "normal", "structured": "structured"}
return res
def draft2open_payment_line_check(self):
self.ensure_one()
if self.bank_account_required and not self.partner_bank_id:
raise UserError(
_("Missing Partner Bank Account on payment line %s") % self.name
)
if not self.communication:
raise UserError(_("Communication is empty on payment line %s.") % self.name)
def _prepare_account_payment_vals(self):
"""Prepare the dictionary to create an account payment record from a set of
payment lines.
"""
journal = self.order_id.journal_id
vals = {
"payment_type": self.order_id.payment_type,
"partner_id": self.partner_id.id,
"destination_account_id": self.move_line_id.account_id.id,
"company_id": self.order_id.company_id.id,
"amount": sum(self.mapped("amount_currency")),
"date": fields.Date.today(),
"currency_id": self.currency_id.id,
"ref": self.order_id.name,
"payment_reference": " - ".join([line.communication for line in self]),
"journal_id": journal.id,
"partner_bank_id": self.partner_bank_id.id,
"payment_order_id": self.order_id.id,
"payment_method_id": self.order_id.payment_mode_id.payment_method_id.id,
"payment_line_ids": [(6, 0, self.ids)],
}
# Determine partner_type
move_type = self[:1].move_line_id.move_id.move_type
if move_type in {"out_invoice", "out_refund"}:
vals["partner_type"] = "customer"
elif move_type in {"in_invoice", "in_refund"}:
vals["partner_type"] = "supplier"
else:
p_type = "customer" if vals["payment_type"] == "inbound" else "supplier"
vals["partner_type"] = p_type
# Fill destination account if manual payment line with no linked journal item
if not vals["destination_account_id"]:
if vals["partner_type"] == "customer":
vals[
"destination_account_id"
] = self.partner_id.property_account_receivable_id.id
else:
vals[
"destination_account_id"
] = self.partner_id.property_account_payable_id.id
return vals