commit
5f110cbf43
|
@ -6,15 +6,7 @@ from odoo import models
|
|||
class AccountReconcileAbstract(models.AbstractModel):
|
||||
_inherit = "account.reconcile.abstract"
|
||||
|
||||
def _get_reconcile_line(
|
||||
self, line, kind, is_counterpart=False, max_amount=False, from_unreconcile=False
|
||||
):
|
||||
vals = super()._get_reconcile_line(
|
||||
line=line,
|
||||
kind=kind,
|
||||
is_counterpart=is_counterpart,
|
||||
max_amount=max_amount,
|
||||
from_unreconcile=from_unreconcile,
|
||||
)
|
||||
def _get_reconcile_line(self, line, kind, **kwargs):
|
||||
vals = super()._get_reconcile_line(line, kind, **kwargs)
|
||||
vals[0]["manual_analytic_tag_ids"] = [(6, 0, line.analytic_tag_ids.ids)]
|
||||
return vals
|
||||
|
|
|
@ -164,7 +164,11 @@ class AccountAccountReconcile(models.Model):
|
|||
for line_id in counterparts:
|
||||
max_amount = amount if line_id == counterparts[-1] else 0
|
||||
lines = self._get_reconcile_line(
|
||||
self.env["account.move.line"].browse(line_id), "other", True, max_amount
|
||||
self.env["account.move.line"].browse(line_id),
|
||||
"other",
|
||||
is_counterpart=True,
|
||||
max_amount=max_amount,
|
||||
move=True,
|
||||
)
|
||||
new_data["data"] += lines
|
||||
amount += sum(line["amount"] for line in lines)
|
||||
|
|
|
@ -8,6 +8,7 @@ from dateutil.relativedelta import relativedelta
|
|||
|
||||
from odoo import Command, _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.fields import first
|
||||
from odoo.tools import float_is_zero
|
||||
|
||||
|
||||
|
@ -194,6 +195,18 @@ class AccountBankStatementLine(models.Model):
|
|||
)._default_reconcile_data()
|
||||
self.can_reconcile = self.reconcile_data_info.get("can_reconcile", False)
|
||||
|
||||
def _get_amount_currency(self, line, dest_curr):
|
||||
if line["line_currency_id"] == dest_curr.id:
|
||||
amount = line["currency_amount"]
|
||||
else:
|
||||
amount = self.company_id.currency_id._convert(
|
||||
line["amount"],
|
||||
dest_curr,
|
||||
self.company_id,
|
||||
self.date,
|
||||
)
|
||||
return amount
|
||||
|
||||
@api.onchange("add_account_move_line_id")
|
||||
def _onchange_add_account_move_line_id(self):
|
||||
if self.add_account_move_line_id:
|
||||
|
@ -201,9 +214,10 @@ class AccountBankStatementLine(models.Model):
|
|||
new_data = []
|
||||
is_new_line = True
|
||||
pending_amount = 0.0
|
||||
currency = self._get_reconcile_currency()
|
||||
for line in data:
|
||||
if line["kind"] != "suspense":
|
||||
pending_amount += line["amount"]
|
||||
pending_amount += self._get_amount_currency(line, currency)
|
||||
if self.add_account_move_line_id.id in line.get(
|
||||
"counterpart_line_ids", []
|
||||
):
|
||||
|
@ -212,7 +226,11 @@ class AccountBankStatementLine(models.Model):
|
|||
new_data.append(line)
|
||||
if is_new_line:
|
||||
reconcile_auxiliary_id, lines = self._get_reconcile_line(
|
||||
self.add_account_move_line_id, "other", True, pending_amount
|
||||
self.add_account_move_line_id,
|
||||
"other",
|
||||
is_counterpart=True,
|
||||
max_amount=currency.round(pending_amount),
|
||||
move=True,
|
||||
)
|
||||
new_data += lines
|
||||
self.reconcile_data_info = self._recompute_suspense_line(
|
||||
|
@ -226,9 +244,11 @@ class AccountBankStatementLine(models.Model):
|
|||
def _recompute_suspense_line(self, data, reconcile_auxiliary_id, manual_reference):
|
||||
can_reconcile = True
|
||||
total_amount = 0
|
||||
currency_amount = 0
|
||||
new_data = []
|
||||
suspense_line = False
|
||||
counterparts = []
|
||||
suspense_currency = self.foreign_currency_id or self.currency_id
|
||||
for line in data:
|
||||
if line.get("counterpart_line_ids"):
|
||||
counterparts += line["counterpart_line_ids"]
|
||||
|
@ -240,10 +260,29 @@ class AccountBankStatementLine(models.Model):
|
|||
if line["kind"] != "suspense":
|
||||
new_data.append(line)
|
||||
total_amount += line["amount"]
|
||||
if not line.get("is_exchange_counterpart"):
|
||||
# case of statement line with foreign_currency
|
||||
if (
|
||||
line["kind"] == "liquidity"
|
||||
and line["line_currency_id"] != suspense_currency.id
|
||||
):
|
||||
currency_amount += self.amount_currency
|
||||
elif (
|
||||
line.get("currency_amount")
|
||||
and line.get("line_currency_id") == suspense_currency.id
|
||||
):
|
||||
currency_amount += line.get("currency_amount")
|
||||
else:
|
||||
currency_amount += self.company_id.currency_id._convert(
|
||||
line["amount"],
|
||||
suspense_currency,
|
||||
self.company_id,
|
||||
self.date,
|
||||
)
|
||||
else:
|
||||
suspense_line = line
|
||||
if not float_is_zero(
|
||||
total_amount, precision_digits=self.currency_id.decimal_places
|
||||
total_amount, precision_digits=self.company_id.currency_id.decimal_places
|
||||
):
|
||||
can_reconcile = False
|
||||
if suspense_line:
|
||||
|
@ -252,9 +291,11 @@ class AccountBankStatementLine(models.Model):
|
|||
"amount": -total_amount,
|
||||
"credit": total_amount if total_amount > 0 else 0.0,
|
||||
"debit": -total_amount if total_amount < 0 else 0.0,
|
||||
"currency_amount": -currency_amount,
|
||||
}
|
||||
)
|
||||
else:
|
||||
|
||||
suspense_line = {
|
||||
"reference": "reconcile_auxiliary;%s" % reconcile_auxiliary_id,
|
||||
"id": False,
|
||||
|
@ -269,8 +310,8 @@ class AccountBankStatementLine(models.Model):
|
|||
"debit": -total_amount if total_amount < 0 else 0.0,
|
||||
"kind": "suspense",
|
||||
"currency_id": self.company_id.currency_id.id,
|
||||
"line_currency_id": self.company_id.currency_id.id,
|
||||
"currency_amount": -total_amount,
|
||||
"line_currency_id": suspense_currency.id,
|
||||
"currency_amount": -currency_amount,
|
||||
}
|
||||
reconcile_auxiliary_id += 1
|
||||
new_data.append(suspense_line)
|
||||
|
@ -291,7 +332,9 @@ class AccountBankStatementLine(models.Model):
|
|||
or self.manual_account_id.id != line["account_id"][0]
|
||||
or self.manual_name != line["name"]
|
||||
or (
|
||||
self.manual_partner_id and self.manual_partner_id.name_get()[0] or False
|
||||
self.manual_partner_id
|
||||
and self.manual_partner_id.name_get()[0]
|
||||
or [False, False]
|
||||
)
|
||||
!= line.get("partner_id")
|
||||
or self.analytic_distribution != line.get("analytic_distribution", False)
|
||||
|
@ -372,7 +415,11 @@ class AccountBankStatementLine(models.Model):
|
|||
|
||||
@api.onchange("manual_amount_in_currency")
|
||||
def _onchange_manual_amount_in_currency(self):
|
||||
if self.manual_line_id.exists() and self.manual_line_id:
|
||||
if (
|
||||
self.manual_line_id.exists()
|
||||
and self.manual_line_id
|
||||
and self.manual_kind != "liquidity"
|
||||
):
|
||||
self.manual_amount = self.manual_in_currency_id._convert(
|
||||
self.manual_amount_in_currency,
|
||||
self.company_id.currency_id,
|
||||
|
@ -382,7 +429,7 @@ class AccountBankStatementLine(models.Model):
|
|||
self._onchange_manual_reconcile_vals()
|
||||
|
||||
def _get_manual_reconcile_vals(self):
|
||||
return {
|
||||
vals = {
|
||||
"name": self.manual_name,
|
||||
"partner_id": self.manual_partner_id
|
||||
and self.manual_partner_id.name_get()[0]
|
||||
|
@ -395,6 +442,18 @@ class AccountBankStatementLine(models.Model):
|
|||
"debit": self.manual_amount if self.manual_amount > 0 else 0.0,
|
||||
"analytic_distribution": self.analytic_distribution,
|
||||
}
|
||||
if self.manual_line_id:
|
||||
vals.update(
|
||||
{
|
||||
"currency_amount": self.manual_line_id.currency_id._convert(
|
||||
self.manual_amount,
|
||||
self.manual_in_currency_id,
|
||||
self.company_id,
|
||||
self.manual_line_id.date,
|
||||
),
|
||||
}
|
||||
)
|
||||
return vals
|
||||
|
||||
@api.onchange(
|
||||
"manual_account_id",
|
||||
|
@ -529,7 +588,10 @@ class AccountBankStatementLine(models.Model):
|
|||
reconcile_auxiliary_id = 1
|
||||
for line in liquidity_lines:
|
||||
reconcile_auxiliary_id, lines = self._get_reconcile_line(
|
||||
line, "liquidity", reconcile_auxiliary_id=reconcile_auxiliary_id
|
||||
line,
|
||||
"liquidity",
|
||||
reconcile_auxiliary_id=reconcile_auxiliary_id,
|
||||
move=True,
|
||||
)
|
||||
data += lines
|
||||
if not from_unreconcile:
|
||||
|
@ -555,6 +617,7 @@ class AccountBankStatementLine(models.Model):
|
|||
self.manual_reference,
|
||||
)
|
||||
elif res and res.get("amls"):
|
||||
# TODO should be signed in currency get_reconcile_currency
|
||||
amount = self.amount_total_signed
|
||||
for line in res.get("amls", []):
|
||||
reconcile_auxiliary_id, line_data = self._get_reconcile_line(
|
||||
|
@ -574,16 +637,87 @@ class AccountBankStatementLine(models.Model):
|
|||
self.manual_reference,
|
||||
)
|
||||
for line in other_lines:
|
||||
reconcile_auxiliary_id, lines = self._get_reconcile_line(
|
||||
line, "other", from_unreconcile=from_unreconcile
|
||||
)
|
||||
data += lines
|
||||
partial_lines = self._all_partials_lines(line) if from_unreconcile else []
|
||||
if partial_lines:
|
||||
for reconciled_line in (
|
||||
partial_lines.debit_move_id + partial_lines.credit_move_id - line
|
||||
):
|
||||
if (
|
||||
reconciled_line.move_id.journal_id
|
||||
== self.company_id.currency_exchange_journal_id
|
||||
):
|
||||
reconcile_auxiliary_id, lines = self._get_reconcile_line(
|
||||
reconciled_line.move_id.line_ids - reconciled_line,
|
||||
"other",
|
||||
from_unreconcile=False,
|
||||
move=True,
|
||||
)
|
||||
data += lines
|
||||
continue
|
||||
partial = partial_lines.filtered(
|
||||
lambda r: r.debit_move_id == reconciled_line
|
||||
or r.credit_move_id == reconciled_line
|
||||
)
|
||||
partial_amount = sum(
|
||||
partial.filtered(
|
||||
lambda r: r.credit_move_id == reconciled_line
|
||||
).mapped("amount")
|
||||
) - sum(
|
||||
partial.filtered(
|
||||
lambda r: r.debit_move_id == reconciled_line
|
||||
).mapped("amount")
|
||||
)
|
||||
reconcile_auxiliary_id, lines = self._get_reconcile_line(
|
||||
reconciled_line,
|
||||
"other",
|
||||
from_unreconcile={
|
||||
"amount": partial_amount,
|
||||
"credit": partial_amount > 0 and partial_amount,
|
||||
"debit": partial_amount < 0 and -partial_amount,
|
||||
"currency_amount": sum(
|
||||
partial.filtered(
|
||||
lambda r: r.credit_move_id == reconciled_line
|
||||
).mapped("credit_amount_currency")
|
||||
)
|
||||
- sum(
|
||||
partial.filtered(
|
||||
lambda r: r.debit_move_id == reconciled_line
|
||||
).mapped("debit_amount_currency")
|
||||
),
|
||||
},
|
||||
move=True,
|
||||
)
|
||||
data += lines
|
||||
else:
|
||||
reconcile_auxiliary_id, lines = self._get_reconcile_line(
|
||||
line, "other", from_unreconcile=False
|
||||
)
|
||||
data += lines
|
||||
|
||||
return self._recompute_suspense_line(
|
||||
data,
|
||||
reconcile_auxiliary_id,
|
||||
self.manual_reference,
|
||||
)
|
||||
|
||||
def _all_partials_lines(self, lines):
|
||||
reconciliation_lines = lines.filtered(
|
||||
lambda x: x.account_id.reconcile
|
||||
or x.account_id.account_type in ("asset_cash", "liability_credit_card")
|
||||
)
|
||||
current_lines = reconciliation_lines
|
||||
current_partials = self.env["account.partial.reconcile"]
|
||||
partials = self.env["account.partial.reconcile"]
|
||||
while current_lines:
|
||||
current_partials = (
|
||||
current_lines.matched_debit_ids + current_lines.matched_credit_ids
|
||||
) - current_partials
|
||||
current_lines = (
|
||||
current_partials.debit_move_id + current_partials.credit_move_id
|
||||
) - current_lines
|
||||
partials += current_partials
|
||||
return partials
|
||||
|
||||
def clean_reconcile(self):
|
||||
self.reconcile_data_info = self._default_reconcile_data()
|
||||
self.can_reconcile = self.reconcile_data_info.get("can_reconcile", False)
|
||||
|
@ -737,12 +871,13 @@ class AccountBankStatementLine(models.Model):
|
|||
to_reverse._reverse_moves(default_values_list, cancel=True)
|
||||
|
||||
def _reconcile_move_line_vals(self, line, move_id=False):
|
||||
return {
|
||||
vals = {
|
||||
"move_id": move_id or self.move_id.id,
|
||||
"account_id": line["account_id"][0],
|
||||
"partner_id": line.get("partner_id") and line["partner_id"][0],
|
||||
"credit": line["credit"],
|
||||
"debit": line["debit"],
|
||||
"currency_id": line.get("line_currency_id", self.company_id.currency_id.id),
|
||||
"tax_ids": line.get("tax_ids", []),
|
||||
"tax_tag_ids": line.get("tax_tag_ids", []),
|
||||
"group_tax_id": line.get("group_tax_id"),
|
||||
|
@ -751,6 +886,11 @@ class AccountBankStatementLine(models.Model):
|
|||
"name": line.get("name"),
|
||||
"reconcile_model_id": line.get("reconcile_model_id"),
|
||||
}
|
||||
if line.get("line_currency_id") and line["currency_id"] != line.get(
|
||||
"line_currency_id"
|
||||
):
|
||||
vals["amount_currency"] = line["currency_amount"]
|
||||
return vals
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, mvals):
|
||||
|
@ -770,7 +910,9 @@ class AccountBankStatementLine(models.Model):
|
|||
data = []
|
||||
for line in liquidity_lines:
|
||||
reconcile_auxiliary_id, lines = record._get_reconcile_line(
|
||||
line, "liquidity"
|
||||
line,
|
||||
"liquidity",
|
||||
move=True,
|
||||
)
|
||||
data += lines
|
||||
reconcile_auxiliary_id = 1
|
||||
|
@ -782,10 +924,10 @@ class AccountBankStatementLine(models.Model):
|
|||
self.manual_reference,
|
||||
)
|
||||
elif res.get("amls"):
|
||||
amount = self.amount
|
||||
amount = self.amount_currency or self.amount
|
||||
for line in res.get("amls", []):
|
||||
reconcile_auxiliary_id, line_datas = record._get_reconcile_line(
|
||||
line, "other", is_counterpart=True, max_amount=amount
|
||||
line, "other", is_counterpart=True, max_amount=amount, move=True
|
||||
)
|
||||
amount -= sum(line_data.get("amount") for line_data in line_datas)
|
||||
data += line_datas
|
||||
|
@ -847,6 +989,7 @@ class AccountBankStatementLine(models.Model):
|
|||
is_counterpart=True,
|
||||
reconcile_auxiliary_id=reconcile_auxiliary_id,
|
||||
max_amount=original_amount,
|
||||
move=True,
|
||||
)
|
||||
new_data += lines
|
||||
new_data.append(
|
||||
|
@ -894,6 +1037,7 @@ class AccountBankStatementLine(models.Model):
|
|||
max_amount=False,
|
||||
from_unreconcile=False,
|
||||
reconcile_auxiliary_id=False,
|
||||
move=False,
|
||||
):
|
||||
new_vals = super()._get_reconcile_line(
|
||||
line,
|
||||
|
@ -901,29 +1045,48 @@ class AccountBankStatementLine(models.Model):
|
|||
is_counterpart=is_counterpart,
|
||||
max_amount=max_amount,
|
||||
from_unreconcile=from_unreconcile,
|
||||
move=move,
|
||||
)
|
||||
rates = []
|
||||
for vals in new_vals:
|
||||
rate = False
|
||||
if vals["partner_id"] is False:
|
||||
vals["partner_id"] = (False, self.partner_name)
|
||||
reconcile_auxiliary_id, rate = self._compute_exchange_rate(
|
||||
vals, line, reconcile_auxiliary_id
|
||||
)
|
||||
if vals.get("kind") not in ("suspense", "liquidity"):
|
||||
reconcile_auxiliary_id, rate = self._compute_exchange_rate(
|
||||
vals, line, reconcile_auxiliary_id
|
||||
)
|
||||
if rate:
|
||||
rates.append(rate)
|
||||
new_vals += rates
|
||||
return reconcile_auxiliary_id, new_vals
|
||||
|
||||
def _get_exchange_rate_amount(self, amount, currency_amount, currency, line):
|
||||
return (
|
||||
currency._convert(
|
||||
if self.foreign_currency_id == currency:
|
||||
# take real rate of statement line to compute the exchange rate gain/loss
|
||||
real_rate = self.amount / self.amount_currency
|
||||
to_amount_journal_currency = currency_amount * real_rate
|
||||
to_amount_company_currency = self.currency_id._convert(
|
||||
to_amount_journal_currency,
|
||||
self.company_id.currency_id,
|
||||
self.company_id,
|
||||
self.date,
|
||||
)
|
||||
to_amount = self.company_id.currency_id.round(to_amount_company_currency)
|
||||
elif self.currency_id == currency and not self.foreign_currency_id:
|
||||
liquidity_lines, _suspense_lines, _other_lines = self._seek_for_lines()
|
||||
real_rate = (
|
||||
first(liquidity_lines).balance / first(liquidity_lines).amount_currency
|
||||
)
|
||||
to_amount = self.company_id.currency_id.round(currency_amount * real_rate)
|
||||
else:
|
||||
to_amount = currency._convert(
|
||||
currency_amount,
|
||||
self.company_id.currency_id,
|
||||
self.company_id,
|
||||
self.date,
|
||||
)
|
||||
- amount
|
||||
)
|
||||
return self.company_id.currency_id.round(to_amount - amount)
|
||||
|
||||
def _compute_exchange_rate(
|
||||
self,
|
||||
|
@ -962,8 +1125,8 @@ class AccountBankStatementLine(models.Model):
|
|||
"debit": amount if amount > 0 else 0.0,
|
||||
"kind": "other",
|
||||
"currency_id": self.company_id.currency_id.id,
|
||||
"line_currency_id": self.company_id.currency_id.id,
|
||||
"currency_amount": amount,
|
||||
"line_currency_id": currency.id,
|
||||
"currency_amount": 0,
|
||||
}
|
||||
reconcile_auxiliary_id += 1
|
||||
return reconcile_auxiliary_id, data
|
||||
|
@ -989,3 +1152,10 @@ class AccountBankStatementLine(models.Model):
|
|||
"split_line_id": self.id,
|
||||
}
|
||||
return action
|
||||
|
||||
def _get_reconcile_currency(self):
|
||||
return (
|
||||
self.foreign_currency_id
|
||||
or self.journal_id.currency_id
|
||||
or self.company_id.currency_id
|
||||
)
|
||||
|
|
|
@ -33,24 +33,46 @@ class AccountReconcileAbstract(models.AbstractModel):
|
|||
related="company_id.currency_id", string="Company Currency"
|
||||
)
|
||||
|
||||
def _get_reconcile_currency(self):
|
||||
return self.currency_id or self.company_id._currency_id
|
||||
|
||||
def _get_reconcile_line(
|
||||
self, line, kind, is_counterpart=False, max_amount=False, from_unreconcile=False
|
||||
self,
|
||||
line,
|
||||
kind,
|
||||
is_counterpart=False,
|
||||
max_amount=False,
|
||||
from_unreconcile=False,
|
||||
move=False,
|
||||
):
|
||||
date = self.date if "date" in self._fields else line.date
|
||||
original_amount = amount = net_amount = line.debit - line.credit
|
||||
line_currency = line.currency_id
|
||||
if is_counterpart:
|
||||
currency_amount = -line.amount_residual_currency or line.amount_residual
|
||||
amount = -line.amount_residual
|
||||
currency = line.currency_id or self.company_id.currency_id
|
||||
currency = line.currency_id or line.company_id.currency_id
|
||||
original_amount = net_amount = -line.amount_residual
|
||||
if max_amount:
|
||||
currency_max_amount = self.company_id.currency_id._convert(
|
||||
max_amount, currency, self.company_id, date
|
||||
)
|
||||
dest_currency = self._get_reconcile_currency()
|
||||
if currency == dest_currency:
|
||||
real_currency_amount = currency_amount
|
||||
elif self.company_id.currency_id == dest_currency:
|
||||
real_currency_amount = amount
|
||||
else:
|
||||
real_currency_amount = self.company_id.currency_id._convert(
|
||||
amount,
|
||||
dest_currency,
|
||||
self.company_id,
|
||||
date,
|
||||
)
|
||||
if (
|
||||
-currency_amount > currency_max_amount > 0
|
||||
or -currency_amount < currency_max_amount < 0
|
||||
-real_currency_amount > max_amount > 0
|
||||
or -real_currency_amount < max_amount < 0
|
||||
):
|
||||
currency_max_amount = self._get_reconcile_currency()._convert(
|
||||
max_amount, currency, self.company_id, date
|
||||
)
|
||||
amount = currency_max_amount
|
||||
net_amount = -max_amount
|
||||
currency_amount = -amount
|
||||
|
@ -61,8 +83,11 @@ class AccountReconcileAbstract(models.AbstractModel):
|
|||
date,
|
||||
)
|
||||
else:
|
||||
currency_amount = line.amount_currency
|
||||
currency_amount = self.amount_currency or self.amount
|
||||
line_currency = self._get_reconcile_currency()
|
||||
vals = {
|
||||
"move_id": move and line.move_id.id,
|
||||
"move": move and line.move_id.name,
|
||||
"reference": "account.move.line;%s" % line.id,
|
||||
"id": line.id,
|
||||
"account_id": line.account_id.name_get()[0],
|
||||
|
@ -74,7 +99,7 @@ class AccountReconcileAbstract(models.AbstractModel):
|
|||
"amount": amount,
|
||||
"net_amount": amount - net_amount,
|
||||
"currency_id": self.company_id.currency_id.id,
|
||||
"line_currency_id": line.currency_id.id,
|
||||
"line_currency_id": line_currency.id,
|
||||
"currency_amount": currency_amount,
|
||||
"analytic_distribution": line.analytic_distribution,
|
||||
"kind": kind,
|
||||
|
@ -82,11 +107,11 @@ class AccountReconcileAbstract(models.AbstractModel):
|
|||
if from_unreconcile:
|
||||
vals.update(
|
||||
{
|
||||
"id": False,
|
||||
"counterpart_line_ids": (
|
||||
line.matched_debit_ids.mapped("debit_move_id")
|
||||
| line.matched_credit_ids.mapped("credit_move_id")
|
||||
).ids,
|
||||
"credit": vals["debit"] and from_unreconcile["debit"],
|
||||
"debit": vals["credit"] and from_unreconcile["credit"],
|
||||
"amount": from_unreconcile["amount"],
|
||||
"net_amount": from_unreconcile["amount"],
|
||||
"currency_amount": from_unreconcile["currency_amount"],
|
||||
}
|
||||
)
|
||||
if not float_is_zero(
|
||||
|
|
|
@ -3,12 +3,15 @@
|
|||
import fieldUtils from "web.field_utils";
|
||||
import {registry} from "@web/core/registry";
|
||||
import session from "web.session";
|
||||
import {useService} from "@web/core/utils/hooks";
|
||||
|
||||
const {Component} = owl;
|
||||
|
||||
export class AccountReconcileDataWidget extends Component {
|
||||
setup() {
|
||||
super.setup(...arguments);
|
||||
this.orm = useService("orm");
|
||||
this.action = useService("action");
|
||||
this.foreignCurrency =
|
||||
this.props &&
|
||||
this.props.record &&
|
||||
|
@ -83,6 +86,15 @@ export class AccountReconcileDataWidget extends Component {
|
|||
});
|
||||
this.env.bus.trigger("RECONCILE_PAGE_NAVIGATE", triggerEv);
|
||||
}
|
||||
async openMove(ev, moveId) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
console.log(moveId);
|
||||
const action = await this.orm.call("account.move", "get_formview_action", [
|
||||
[moveId],
|
||||
]);
|
||||
this.action.doAction(action);
|
||||
}
|
||||
}
|
||||
AccountReconcileDataWidget.template = "account_reconcile_oca.ReconcileDataWidget";
|
||||
|
||||
|
|
|
@ -116,7 +116,18 @@
|
|||
t-on-click="(ev) => this.selectReconcileLine(ev, reconcile_line)"
|
||||
t-att-class="'o_reconcile_widget_line ' + reconcile_line.kind + (props.record.data.manual_reference == reconcile_line.reference ? ' selected ' : ' ')"
|
||||
>
|
||||
<td t-esc="reconcile_line.account_id[1]" />
|
||||
<td>
|
||||
<div t-esc="reconcile_line.account_id[1]" />
|
||||
<div t-if="reconcile_line.move_id">
|
||||
<a
|
||||
t-att-href="'/web#id=' + reconcile_line.move_id + '&view_type=form&model=account.move'"
|
||||
class="o_form_uri"
|
||||
t-on-click="(ev) => this.openMove(ev, reconcile_line.move_id)"
|
||||
>
|
||||
<small t-esc="reconcile_line.move" />
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span
|
||||
t-esc="reconcile_line.partner_id[1]"
|
||||
|
|
|
@ -84,7 +84,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
inv1 = self.create_invoice(currency_id=self.currency_usd_id, invoice_amount=100)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -112,6 +111,42 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
self.assertFalse(f.add_account_move_line_id)
|
||||
self.assertTrue(f.can_reconcile)
|
||||
|
||||
def test_manual_line_with_currency(self):
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
}
|
||||
)
|
||||
bank_stmt_line = self.acc_bank_stmt_line_model.create(
|
||||
{
|
||||
"name": "testLine",
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"statement_id": bank_stmt.id,
|
||||
"amount": 50,
|
||||
"amount_currency": 100,
|
||||
"foreign_currency_id": self.currency_usd_id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
}
|
||||
)
|
||||
receivable_acc = self.company_data["default_account_receivable"]
|
||||
with Form(
|
||||
bank_stmt_line,
|
||||
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
|
||||
) as f:
|
||||
self.assertFalse(f.can_reconcile)
|
||||
f.manual_reference = "reconcile_auxiliary;1"
|
||||
f.manual_account_id = receivable_acc
|
||||
self.assertTrue(f.can_reconcile)
|
||||
bank_stmt_line.reconcile_bank_line()
|
||||
receivable_line = bank_stmt_line.line_ids.filtered(
|
||||
lambda line: line.account_id == receivable_acc
|
||||
)
|
||||
self.assertEqual(receivable_line.currency_id.id, self.currency_usd_id)
|
||||
self.assertEqual(receivable_line.amount_currency, -100)
|
||||
self.assertEqual(receivable_line.balance, -50)
|
||||
|
||||
def test_reconcile_invoice_reconcile_full(self):
|
||||
"""
|
||||
We want to test the reconcile widget for bank statements on invoices.
|
||||
|
@ -123,7 +158,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -172,7 +206,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -235,7 +268,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -299,7 +331,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -353,7 +384,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
"""
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -397,7 +427,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -452,7 +481,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -512,7 +540,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -542,7 +569,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -600,7 +626,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -642,7 +667,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
"""
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -677,7 +701,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -715,7 +738,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -756,7 +778,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -797,7 +818,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -833,7 +853,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
"""
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -884,7 +903,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
"""
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -927,7 +945,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -991,7 +1008,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_euro.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -1025,7 +1041,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
inv1 = self.create_invoice(currency_id=self.currency_usd_id, invoice_amount=100)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_usd.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -1064,30 +1079,51 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
|
||||
def test_journal_foreign_currency_change(self):
|
||||
cny = self.env.ref("base.CNY")
|
||||
cny.write({"active": True})
|
||||
cny_journal = self.env["account.journal"].create(
|
||||
{
|
||||
"name": "Bank CNY",
|
||||
"type": "bank",
|
||||
"currency_id": cny.id,
|
||||
}
|
||||
)
|
||||
self.env["res.currency.rate"].create(
|
||||
{
|
||||
"currency_id": self.env.ref("base.EUR").id,
|
||||
"name": time.strftime("%Y-07-14"),
|
||||
"rate": 1.15,
|
||||
"name": time.strftime("%Y-09-10"),
|
||||
"currency_id": cny.id,
|
||||
"inverse_company_rate": 0.125989013758,
|
||||
}
|
||||
)
|
||||
self.env["res.currency.rate"].create(
|
||||
{
|
||||
"name": time.strftime("%Y-09-09"),
|
||||
"currency_id": cny.id,
|
||||
"inverse_company_rate": 0.126225969731,
|
||||
}
|
||||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_usd.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"journal_id": cny_journal.id,
|
||||
"date": time.strftime("%Y-09-10"),
|
||||
"name": "test",
|
||||
}
|
||||
)
|
||||
bank_stmt_line = self.acc_bank_stmt_line_model.create(
|
||||
{
|
||||
"name": "testLine",
|
||||
"journal_id": self.bank_journal_usd.id,
|
||||
"journal_id": cny_journal.id,
|
||||
"statement_id": bank_stmt.id,
|
||||
"amount": 100,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"amount": 259200,
|
||||
"date": time.strftime("%Y-09-10"),
|
||||
}
|
||||
)
|
||||
inv1 = self._create_invoice(
|
||||
currency_id=cny.id,
|
||||
invoice_amount=259200,
|
||||
date_invoice=time.strftime("%Y-09-09"),
|
||||
auto_validate=True,
|
||||
)
|
||||
with Form(
|
||||
bank_stmt_line,
|
||||
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
|
||||
|
@ -1095,24 +1131,17 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
line = f.reconcile_data_info["data"][0]
|
||||
self.assertEqual(
|
||||
line["currency_amount"],
|
||||
100,
|
||||
259200,
|
||||
)
|
||||
self.env["res.currency.rate"].create(
|
||||
{
|
||||
"currency_id": self.env.ref("base.EUR").id,
|
||||
"name": time.strftime("%Y-07-15"),
|
||||
"rate": 1.2,
|
||||
}
|
||||
)
|
||||
with Form(
|
||||
bank_stmt_line,
|
||||
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
|
||||
) as f:
|
||||
line = f.reconcile_data_info["data"][0]
|
||||
self.assertEqual(
|
||||
line["currency_amount"],
|
||||
100,
|
||||
f.add_account_move_line_id = inv1.line_ids.filtered(
|
||||
lambda l: l.account_id.account_type == "asset_receivable"
|
||||
)
|
||||
self.assertTrue(f.can_reconcile)
|
||||
self.assertEqual(len(bank_stmt_line.reconcile_data_info["data"]), 3)
|
||||
exchange_line = bank_stmt_line.reconcile_data_info["data"][-1]
|
||||
self.assertEqual(exchange_line["amount"], 61.42)
|
||||
bank_stmt_line.reconcile_bank_line()
|
||||
self.assertEqual(inv1.payment_state, "paid")
|
||||
|
||||
def test_invoice_foreign_currency_change(self):
|
||||
self.env["res.currency.rate"].create(
|
||||
|
@ -1137,7 +1166,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"journal_id": self.bank_journal_usd.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
|
@ -1167,3 +1195,75 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
self.assertFalse(f.add_account_move_line_id)
|
||||
self.assertTrue(f.can_reconcile)
|
||||
self.assertEqual(3, len(f.reconcile_data_info["data"]))
|
||||
|
||||
def test_invoice_foreign_currency_late_change_of_rate(self):
|
||||
# Test we can reconcile lines in foreign currency even if the rate was updated
|
||||
# late in odoo, meaning the statement line was created and the rate was updated
|
||||
# in odoo after that.
|
||||
self.env["res.currency.rate"].create(
|
||||
{
|
||||
"currency_id": self.env.ref("base.USD").id,
|
||||
"name": time.strftime("%Y-07-14"),
|
||||
"rate": 1.15,
|
||||
}
|
||||
)
|
||||
self.env["res.currency.rate"].create(
|
||||
{
|
||||
"currency_id": self.env.ref("base.USD").id,
|
||||
"name": time.strftime("%Y-07-15"),
|
||||
"rate": 1.2,
|
||||
}
|
||||
)
|
||||
inv1 = self._create_invoice(
|
||||
currency_id=self.currency_usd_id,
|
||||
invoice_amount=100,
|
||||
date_invoice=time.strftime("%Y-07-14"),
|
||||
auto_validate=True,
|
||||
)
|
||||
bank_stmt = self.acc_bank_stmt_model.create(
|
||||
{
|
||||
"journal_id": self.bank_journal_usd.id,
|
||||
"date": time.strftime("%Y-07-15"),
|
||||
"name": "test",
|
||||
}
|
||||
)
|
||||
bank_stmt_line = self.acc_bank_stmt_line_model.create(
|
||||
{
|
||||
"name": "testLine",
|
||||
"journal_id": self.bank_journal_usd.id,
|
||||
"statement_id": bank_stmt.id,
|
||||
"amount": 100,
|
||||
"date": time.strftime("%Y-07-16"),
|
||||
}
|
||||
)
|
||||
# rate of 07-16 is create after the statement line, meaning the rate of the
|
||||
# statement line is the one of the 07-15
|
||||
self.env["res.currency.rate"].create(
|
||||
{
|
||||
"currency_id": self.env.ref("base.USD").id,
|
||||
"name": time.strftime("%Y-07-16"),
|
||||
"rate": 1.25,
|
||||
}
|
||||
)
|
||||
with Form(
|
||||
bank_stmt_line,
|
||||
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
|
||||
) as f:
|
||||
line = f.reconcile_data_info["data"][0]
|
||||
self.assertEqual(
|
||||
line["currency_amount"],
|
||||
100,
|
||||
)
|
||||
self.assertEqual(
|
||||
line["amount"],
|
||||
83.33,
|
||||
)
|
||||
f.manual_reference = "account.move.line;%s" % line["id"]
|
||||
# simulate click on statement line, check amount does not recompute
|
||||
self.assertEqual(f.manual_amount, 83.33)
|
||||
f.add_account_move_line_id = inv1.line_ids.filtered(
|
||||
lambda l: l.account_id.account_type == "asset_receivable"
|
||||
)
|
||||
self.assertEqual(3, len(f.reconcile_data_info["data"]))
|
||||
self.assertTrue(f.can_reconcile)
|
||||
self.assertEqual(f.reconcile_data_info["data"][-1]["amount"], 3.63)
|
||||
|
|
Loading…
Reference in New Issue