Skip to content

Commit 28ca8eb

Browse files
committed
[MIG] hr_expense_advance_clearing: Migration to 16.0
1 parent ec8b64b commit 28ca8eb

File tree

6 files changed

+164
-68
lines changed

6 files changed

+164
-68
lines changed

hr_expense_advance_clearing/__manifest__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
{
55
"name": "Employee Advance and Clearing",
6-
"version": "15.0.1.2.0",
6+
"version": "16.0.1.0.0",
77
"category": "Human Resources",
88
"author": "Ecosoft, Odoo Community Association (OCA)",
99
"license": "AGPL-3",

hr_expense_advance_clearing/models/hr_expense.py

Lines changed: 91 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from odoo import _, api, fields, models
55
from odoo.exceptions import ValidationError
6+
from odoo.tools import float_compare
67

78

89
class HrExpense(models.Model):
@@ -59,37 +60,95 @@ def onchange_advance(self):
5960
)
6061

6162
def _get_account_move_line_values(self):
62-
move_line_values_by_expense = super()._get_account_move_line_values()
63-
# Only when do the clearing, change cr payable to cr advance
64-
emp_advance = self.env.ref("hr_expense_advance_clearing.product_emp_advance")
65-
sheets = self.mapped("sheet_id").filtered("advance_sheet_id")
66-
sheets_x = sheets.filtered(lambda x: x.advance_sheet_residual <= 0.0)
67-
if sheets_x: # Advance Sheets with no residual left
68-
raise ValidationError(
69-
_("Advance: %s has no amount to clear")
70-
% ", ".join(sheets_x.mapped("name"))
63+
"""Create move line (journal) from clearing"""
64+
move_line_values_by_expense = {}
65+
for expense in self:
66+
advance_to_clear = expense.sheet_id.advance_sheet_residual
67+
move_line_name = (
68+
expense.employee_id.name + ": " + expense.name.split("\n")[0][:64]
7169
)
72-
for sheet in sheets:
73-
advance_to_clear = sheet.advance_sheet_residual
74-
for move_lines in move_line_values_by_expense.values():
75-
payable_move_line = False
76-
for move_line in move_lines:
77-
credit = move_line["credit"]
78-
if not credit:
79-
continue
80-
# cr payable -> cr advance
81-
remain_payable = 0.0
82-
if credit > advance_to_clear:
83-
remain_payable = credit - advance_to_clear
84-
move_line["credit"] = advance_to_clear
85-
advance_to_clear = 0.0
86-
# extra payable line
87-
payable_move_line = move_line.copy()
88-
payable_move_line["credit"] = remain_payable
89-
else:
90-
advance_to_clear -= credit
91-
# advance line
92-
move_line["account_id"] = emp_advance.property_account_expense_id.id
93-
if payable_move_line:
94-
move_lines.append(payable_move_line)
70+
account_src = expense.account_id
71+
account_dst = expense._get_expense_account_destination()
72+
account_date = (
73+
expense.date
74+
or expense.sheet_id.accounting_date
75+
or fields.Date.context_today(expense)
76+
)
77+
78+
move_line_values = []
79+
unit_amount = expense.unit_amount or expense.total_amount
80+
quantity = expense.quantity if expense.unit_amount else 1
81+
taxes = expense.tax_ids.with_context(round=True).compute_all(
82+
unit_amount, expense.currency_id, quantity, expense.product_id
83+
)
84+
total_amount = 0.0
85+
total_amount_currency = 0.0
86+
partner_id = (
87+
expense.employee_id.sudo().address_home_id.commercial_partner_id.id
88+
)
89+
# source move line
90+
balance = expense.total_amount_company - expense.amount_tax_company
91+
amount_currency = expense.total_amount - expense.amount_tax
92+
move_line_src = {
93+
"name": move_line_name,
94+
"quantity": expense.quantity or 1,
95+
"debit": balance if balance > 0 else 0,
96+
"credit": -balance if balance < 0 else 0,
97+
"amount_currency": amount_currency,
98+
"account_id": account_src.id,
99+
"product_id": expense.product_id.id,
100+
"product_uom_id": expense.product_uom_id.id,
101+
"analytic_distribution": expense.analytic_distribution,
102+
"expense_id": expense.id,
103+
"partner_id": partner_id,
104+
"tax_ids": [(6, 0, expense.tax_ids.ids)],
105+
"tax_tag_ids": [(6, 0, taxes["base_tags"])],
106+
"currency_id": expense.currency_id.id,
107+
}
108+
move_line_values.append(move_line_src)
109+
total_amount -= expense.total_amount_company
110+
total_amount_currency -= expense.total_amount
111+
112+
# destination move line
113+
emp_advance = self.env.ref(
114+
"hr_expense_advance_clearing.product_emp_advance"
115+
)
116+
move_line_dst = {
117+
"name": move_line_name,
118+
"debit": total_amount > 0 and total_amount,
119+
"credit": total_amount < 0 and -total_amount,
120+
"account_id": emp_advance.property_account_expense_id.id,
121+
"date_maturity": account_date,
122+
"amount_currency": total_amount_currency,
123+
"currency_id": expense.currency_id.id,
124+
"expense_id": expense.id,
125+
"partner_id": partner_id,
126+
}
127+
# Check clearing > advance, it will split line
128+
credit = move_line_dst["credit"]
129+
# cr payable -> cr advance
130+
remain_payable = 0.0
131+
payable_move_line = []
132+
if (
133+
float_compare(
134+
credit,
135+
advance_to_clear,
136+
precision_rounding=expense.currency_id.rounding,
137+
)
138+
== 1
139+
):
140+
remain_payable = credit - advance_to_clear
141+
move_line_dst["credit"] = advance_to_clear
142+
move_line_dst["amount_currency"] = -advance_to_clear
143+
advance_to_clear = 0.0
144+
# extra payable line
145+
payable_move_line = move_line_dst.copy()
146+
payable_move_line["credit"] = remain_payable
147+
payable_move_line["amount_currency"] = -remain_payable
148+
payable_move_line["account_id"] = account_dst
149+
# Add destination first
150+
move_line_values.append(move_line_dst)
151+
if payable_move_line:
152+
move_line_values.append(payable_move_line)
153+
move_line_values_by_expense[expense.id] = move_line_values
95154
return move_line_values_by_expense

hr_expense_advance_clearing/models/hr_expense_sheet.py

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Copyright 2019 Kitti Upariphutthiphong <[email protected]>
22
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
33

4-
from odoo import _, api, fields, models
4+
from odoo import Command, _, api, fields, models
55
from odoo.exceptions import ValidationError
66
from odoo.tools import float_compare
77
from odoo.tools.safe_eval import safe_eval
@@ -64,6 +64,15 @@ def _check_advance_expense(self):
6464
if advance_lines and len(advance_lines) != len(self.expense_line_ids):
6565
raise ValidationError(_("Advance must contain only advance expense line"))
6666

67+
@api.depends("account_move_id.payment_state")
68+
def _compute_payment_state(self):
69+
"""After clear advance. payment state will change to 'paid'"""
70+
res = super()._compute_payment_state()
71+
for sheet in self:
72+
if sheet.advance_sheet_id and sheet.account_move_id.state == "posted":
73+
sheet.payment_state = "paid"
74+
return res
75+
6776
@api.depends("account_move_id.line_ids.amount_residual")
6877
def _compute_clearing_residual(self):
6978
emp_advance = self.env.ref(
@@ -90,13 +99,13 @@ def _compute_clearing_count(self):
9099

91100
def action_sheet_move_create(self):
92101
res = super().action_sheet_move_create()
93-
# Reconcile advance of this sheet with the advance_sheet
94102
emp_advance = self.env.ref("hr_expense_advance_clearing.product_emp_advance")
95-
ctx = self._context.copy()
96-
ctx.update({"skip_account_move_synchronization": True})
97103
for sheet in self:
104+
if not sheet.advance_sheet_id:
105+
continue
106+
amount_residual_bf_reconcile = sheet.advance_sheet_residual
98107
advance_residual = float_compare(
99-
sheet.advance_sheet_residual,
108+
amount_residual_bf_reconcile,
100109
sheet.total_amount,
101110
precision_rounding=sheet.currency_id.rounding,
102111
)
@@ -116,10 +125,45 @@ def action_sheet_move_create(self):
116125
]
117126
)
118127
)
119-
adv_move_lines.with_context(**ctx).reconcile()
128+
adv_move_lines.reconcile()
120129
# Update state on clearing advance when advance residual > total amount
121-
if sheet.advance_sheet_id and advance_residual != -1:
122-
sheet.write({"state": "done"})
130+
if advance_residual != -1:
131+
sheet.write(
132+
{
133+
"state": "done",
134+
}
135+
)
136+
# Update amount residual and state when advance residual < total amount
137+
else:
138+
sheet.write(
139+
{
140+
"state": "post",
141+
"payment_state": "not_paid",
142+
"amount_residual": sheet.total_amount
143+
- amount_residual_bf_reconcile,
144+
}
145+
)
146+
return res
147+
148+
def _prepare_bill_vals(self):
149+
"""create journal entry instead of bills when clearing document"""
150+
self.ensure_one()
151+
res = super()._prepare_bill_vals()
152+
if self.advance_sheet_id and self.payment_mode == "own_account":
153+
if (
154+
self.advance_sheet_residual <= 0.0
155+
): # Advance Sheets with no residual left
156+
raise ValidationError(
157+
_("Advance: %s has no amount to clear") % (self.name)
158+
)
159+
res["move_type"] = "entry"
160+
move_line_vals = []
161+
162+
for expense in self.expense_line_ids:
163+
# get move line values
164+
move_line_values_by_expense = expense._get_account_move_line_values()
165+
move_line_vals.extend(move_line_values_by_expense.get(expense.id))
166+
res["line_ids"] = [Command.create(x) for x in move_line_vals]
123167
return res
124168

125169
def open_clear_advance(self):
@@ -156,7 +200,7 @@ def _prepare_clear_advance(self, line):
156200
# Prepare the clearing expense
157201
clear_line_dict = {
158202
"advance": False,
159-
"name": False,
203+
"name": line.clearing_product_id.display_name,
160204
"product_id": line.clearing_product_id.id,
161205
"clearing_product_id": False,
162206
"date": fields.Date.context_today(self),
@@ -166,7 +210,7 @@ def _prepare_clear_advance(self, line):
166210
"av_line_id": line.id,
167211
}
168212
clear_line = self.env["hr.expense"].new(clear_line_dict)
169-
clear_line._compute_from_product_id_company_id() # Set some vals
213+
clear_line._compute_account_id() # Set some vals
170214
# Prepare the original advance line
171215
adv_dict = line._convert_to_write(line._cache)
172216
# remove no update columns

hr_expense_advance_clearing/tests/test_hr_expense_advance_clearing.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,15 @@ def setUpClass(cls):
4141
{
4242
"code": "154000",
4343
"name": "Employee Advance",
44-
"user_type_id": cls.env.ref(
45-
"account.data_account_type_current_assets"
46-
).id,
44+
"account_type": "asset_current",
4745
"reconcile": True,
4846
}
4947
)
5048
cls.account_sales = cls.env["account.account"].create(
5149
{
5250
"code": "X1020",
5351
"name": "Product Sales - (test)",
54-
"user_type_id": cls.env.ref("account.data_account_type_revenue").id,
52+
"account_type": "asset_current",
5553
}
5654
)
5755
cls.emp_advance = cls.env.ref("hr_expense_advance_clearing.product_emp_advance")
@@ -81,7 +79,6 @@ def _create_expense(
8179
amount,
8280
advance=False,
8381
payment_mode="own_account",
84-
account=False,
8582
):
8683
with Form(
8784
self.env["hr.expense"].with_context(default_advance=advance)
@@ -90,10 +87,8 @@ def _create_expense(
9087
expense.employee_id = employee
9188
if not advance:
9289
expense.product_id = product
93-
expense.unit_amount = amount
90+
expense.total_amount = amount
9491
expense.payment_mode = payment_mode
95-
if account:
96-
expense.account_id = account
9792
expense = expense.save()
9893
expense.tax_ids = False # Test no vat
9994
return expense
@@ -145,8 +140,9 @@ def test_0_test_constraints(self):
145140
self.emp_advance,
146141
1.0,
147142
advance=True,
148-
account=self.account_sales,
149143
)
144+
expense.account_id = self.account_sales.id
145+
expense._check_advance()
150146
# Advance Sheet should not have > 1 expense lines
151147
with self.assertRaises(ValidationError):
152148
expense = self._create_expense(
@@ -333,5 +329,10 @@ def test_4_clearing_product_advance(self):
333329
self.assertEqual(len(ex_sheet.expense_line_ids), 0)
334330
ex_sheet._onchange_advance_sheet_id()
335331
self.assertEqual(len(ex_sheet.expense_line_ids), 1)
336-
reverse_move = self.advance.account_move_id._reverse_moves(cancel=True)
332+
reverse_move = self.advance.account_move_id._reverse_moves(
333+
default_values_list=[
334+
{"invoice_date": self.advance.account_move_id.date, "ref": False}
335+
],
336+
cancel=True,
337+
)
337338
self.assertNotEqual(reverse_move, self.advance.account_move_id)

hr_expense_advance_clearing/views/hr_expense_views.xml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,7 @@
141141
placeholder="Optional clearing product is used during clear advance"
142142
/>
143143
</field>
144-
<field name="analytic_account_id" position="attributes">
145-
<attribute name="attrs">
146-
{'invisible': [('advance', '!=', False)]}
147-
</attribute>
148-
</field>
149-
<field name="analytic_tag_ids" position="attributes">
144+
<field name="analytic_distribution" position="attributes">
150145
<attribute name="attrs">
151146
{'invisible': [('advance', '!=', False)]}
152147
</attribute>

hr_expense_advance_clearing/wizard/account_payment_register.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,20 +110,17 @@ def expense_post_return_advance(self):
110110
emp_advance = self.env.ref("hr_expense_advance_clearing.product_emp_advance")
111111
advance_account = emp_advance.property_account_expense_id
112112
# Create return advance and post it
113-
payment_vals = self._create_payment_vals_from_wizard()
113+
batches = self._get_batches()
114+
first_batch_result = batches[0]
115+
payment_vals = self._create_payment_vals_from_wizard(first_batch_result)
116+
# Set new payment_type and payment entry to be Dr Bank, Cr Advance
114117
payment_vals["advance_id"] = expense_sheet.id
118+
payment_vals["partner_type"] = "customer"
119+
payment_vals["destination_account_id"] = advance_account.id
115120
payment_vals_list = [payment_vals]
116121
payment = (
117122
self.env["account.payment"].with_context(**ctx).create(payment_vals_list)
118123
)
119-
# Set new payment_type and payment entry to be Dr Bank, Cr Advance
120-
payment.write(
121-
{
122-
"payment_type": "inbound",
123-
"partner_type": "customer",
124-
"destination_account_id": advance_account,
125-
}
126-
)
127124
payment.action_post()
128125

129126
redirect_link = (

0 commit comments

Comments
 (0)