Initial commit: Odoo 18.0-20251222 extra-addons
This commit is contained in:
2
account_check_deposit/models/__init__.py
Executable file
2
account_check_deposit/models/__init__.py
Executable file
@@ -0,0 +1,2 @@
|
||||
from . import account_check_deposit
|
||||
from . import account_move_line
|
||||
343
account_check_deposit/models/account_check_deposit.py
Executable file
343
account_check_deposit/models/account_check_deposit.py
Executable file
@@ -0,0 +1,343 @@
|
||||
# Copyright 2012-2022 Akretion (http://www.akretion.com/)
|
||||
# @author: Benoît GUILLOT <benoit.guillot@akretion.com>
|
||||
# @author: Chafique DELLI <chafique.delli@akretion.com>
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# @author: Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
|
||||
# Copyright 2018-2022 Tecnativa - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
|
||||
|
||||
class AccountCheckDeposit(models.Model):
|
||||
_name = "account.check.deposit"
|
||||
_description = "Check Deposit"
|
||||
_inherit = ["mail.thread", "mail.activity.mixin"]
|
||||
_order = "deposit_date desc"
|
||||
_check_company_auto = True
|
||||
|
||||
name = fields.Char(readonly=True, default=lambda self: _("New"), copy=False)
|
||||
check_payment_ids = fields.One2many(
|
||||
comodel_name="account.move.line",
|
||||
inverse_name="check_deposit_id",
|
||||
string="Check Payments",
|
||||
)
|
||||
deposit_date = fields.Date(
|
||||
required=True,
|
||||
default=fields.Date.context_today,
|
||||
tracking=True,
|
||||
copy=False,
|
||||
)
|
||||
journal_id = fields.Many2one(
|
||||
comodel_name="account.journal",
|
||||
string="Check Journal",
|
||||
domain="[('company_id', '=', company_id), ('type', '=', 'bank'), "
|
||||
"('bank_account_id', '=', False)]",
|
||||
required=True,
|
||||
check_company=True,
|
||||
tracking=True,
|
||||
)
|
||||
in_hand_check_account_id = fields.Many2one(
|
||||
comodel_name="account.account",
|
||||
compute="_compute_in_hand_check_account_id",
|
||||
store=True,
|
||||
)
|
||||
currency_id = fields.Many2one(
|
||||
comodel_name="res.currency",
|
||||
compute="_compute_currency_id",
|
||||
store=True,
|
||||
precompute=True,
|
||||
readonly=False,
|
||||
required=True,
|
||||
tracking=True,
|
||||
)
|
||||
state = fields.Selection(
|
||||
selection=[("draft", "Draft"), ("done", "Done")],
|
||||
string="Status",
|
||||
default="draft",
|
||||
readonly=True,
|
||||
tracking=True,
|
||||
)
|
||||
move_id = fields.Many2one(
|
||||
comodel_name="account.move",
|
||||
string="Journal Entry",
|
||||
readonly=True,
|
||||
check_company=True,
|
||||
)
|
||||
bank_journal_id = fields.Many2one(
|
||||
comodel_name="account.journal",
|
||||
string="Bank Account",
|
||||
required=True,
|
||||
domain="[('company_id', '=', company_id), ('type', '=', 'bank'), "
|
||||
"('bank_account_id', '!=', False)]",
|
||||
check_company=True,
|
||||
tracking=True,
|
||||
)
|
||||
line_ids = fields.One2many(
|
||||
comodel_name="account.move.line",
|
||||
related="move_id.line_ids",
|
||||
string="Lines",
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
comodel_name="res.company",
|
||||
required=True,
|
||||
default=lambda self: self.env.company,
|
||||
tracking=True,
|
||||
)
|
||||
total_amount = fields.Monetary(
|
||||
compute="_compute_check_deposit",
|
||||
store=True,
|
||||
currency_field="currency_id",
|
||||
tracking=True,
|
||||
)
|
||||
check_count = fields.Integer(
|
||||
compute="_compute_check_deposit",
|
||||
store=True,
|
||||
string="Number of Checks",
|
||||
tracking=True,
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
(
|
||||
"name_company_unique",
|
||||
"unique(company_id, name)",
|
||||
"A check deposit with this reference already exists in this company.",
|
||||
)
|
||||
]
|
||||
|
||||
@api.depends(
|
||||
"company_id",
|
||||
"currency_id",
|
||||
"check_payment_ids.debit",
|
||||
"check_payment_ids.amount_currency",
|
||||
"move_id.line_ids.reconciled",
|
||||
)
|
||||
def _compute_check_deposit(self):
|
||||
rg_res = self.env["account.move.line"]._read_group(
|
||||
[("check_deposit_id", "in", self.ids)],
|
||||
groupby=["check_deposit_id"],
|
||||
aggregates=["amount_currency:sum", "debit:sum", "id:count"],
|
||||
)
|
||||
mapped_data = {
|
||||
deposit.id: {
|
||||
"debit": total_debit,
|
||||
"amount_currency": total_amount_currency,
|
||||
"count": line_count,
|
||||
}
|
||||
for (deposit, total_amount_currency, total_debit, line_count) in rg_res
|
||||
}
|
||||
|
||||
for deposit in self:
|
||||
if deposit.company_id.currency_id != deposit.currency_id:
|
||||
total = mapped_data.get(deposit.id, {"amount_currency": 0.0})[
|
||||
"amount_currency"
|
||||
]
|
||||
else:
|
||||
total = mapped_data.get(deposit.id, {"debit": 0.0})["debit"]
|
||||
count = mapped_data.get(deposit.id, {"count": 0})["count"]
|
||||
deposit.total_amount = deposit.currency_id.round(total)
|
||||
deposit.check_count = count
|
||||
|
||||
@api.depends("journal_id")
|
||||
def _compute_currency_id(self):
|
||||
for deposit in self:
|
||||
company = deposit.company_id
|
||||
deposit.currency_id = deposit.journal_id.currency_id or company.currency_id
|
||||
|
||||
@api.depends("journal_id")
|
||||
def _compute_in_hand_check_account_id(self):
|
||||
for rec in self:
|
||||
account = rec.journal_id.inbound_payment_method_line_ids.filtered(
|
||||
lambda line: line.payment_method_id.code == "manual"
|
||||
).payment_account_id
|
||||
rec.in_hand_check_account_id = account
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
ajo = self.env["account.journal"]
|
||||
company_id = res.get("company_id")
|
||||
# pre-set journal_id and bank_journal_id is there is only one
|
||||
domain = [("company_id", "=", company_id), ("type", "=", "bank")]
|
||||
journals = ajo.search(domain + [("bank_account_id", "=", False)])
|
||||
if len(journals) == 1:
|
||||
res["journal_id"] = journals.id
|
||||
bank_journals = ajo.search(domain + [("bank_account_id", "!=", False)])
|
||||
if len(bank_journals) == 1:
|
||||
res["bank_journal_id"] = bank_journals.id
|
||||
return res
|
||||
|
||||
@api.constrains("currency_id", "check_payment_ids")
|
||||
def _check_deposit(self):
|
||||
for deposit in self:
|
||||
deposit_currency = deposit.currency_id
|
||||
for line in deposit.check_payment_ids:
|
||||
if line.currency_id != deposit_currency:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"The check with amount %(amount)s and reference '%(ref)s' "
|
||||
"is in currency %(check_currency)s but the deposit is in "
|
||||
"currency %(deposit_currency)s.",
|
||||
amount=line.debit,
|
||||
ref=line.ref or "",
|
||||
check_currency=line.currency_id.name,
|
||||
deposit_currency=deposit_currency.name,
|
||||
)
|
||||
)
|
||||
|
||||
def unlink(self):
|
||||
for deposit in self.filtered(lambda x: x.state == "done"):
|
||||
raise UserError(
|
||||
_(
|
||||
"The deposit '%s' is in valid state, so you must "
|
||||
"cancel it before deleting it."
|
||||
)
|
||||
% deposit.display_name
|
||||
)
|
||||
return super().unlink()
|
||||
|
||||
def backtodraft(self):
|
||||
amlo = self.env["account.move.line"]
|
||||
for deposit in self:
|
||||
if deposit.move_id:
|
||||
move = deposit.move_id
|
||||
check_move_lines = amlo
|
||||
counterpart_move_line = amlo
|
||||
for move_line in move.line_ids:
|
||||
if move_line.account_id.id == deposit.in_hand_check_account_id.id:
|
||||
check_move_lines |= move_line
|
||||
else:
|
||||
counterpart_move_line |= move_line
|
||||
if counterpart_move_line.reconciled:
|
||||
raise UserError(
|
||||
_("Deposit '%s' has already been credited on the bank account.")
|
||||
% deposit.display_name
|
||||
)
|
||||
check_move_lines.remove_move_reconcile()
|
||||
if move.state == "posted":
|
||||
move.button_cancel()
|
||||
move.with_context(force_delete=True).unlink()
|
||||
deposit.write({"state": "draft"})
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if "company_id" in vals:
|
||||
self = self.with_company(vals["company_id"])
|
||||
if vals.get("name", _("New")) == _("New"):
|
||||
vals["name"] = self.env["ir.sequence"].next_by_code(
|
||||
"account.check.deposit", vals.get("deposit_date")
|
||||
) or _("New")
|
||||
return super().create(vals_list)
|
||||
|
||||
def _prepare_move_vals(self):
|
||||
self.ensure_one()
|
||||
total_debit = 0.0
|
||||
total_amount_currency = 0.0
|
||||
for line in self.check_payment_ids:
|
||||
total_debit += line.debit
|
||||
total_amount_currency += line.amount_currency
|
||||
|
||||
total_debit = self.company_id.currency_id.round(total_debit)
|
||||
total_amount_currency = self.currency_id.round(total_amount_currency)
|
||||
|
||||
counterpart_account_id = False
|
||||
for line in self.bank_journal_id.inbound_payment_method_line_ids:
|
||||
if line.payment_method_id.code == "manual" and line.payment_account_id:
|
||||
counterpart_account_id = line.payment_account_id.id
|
||||
break
|
||||
# inspired by _get_outstanding_account() on account.payment
|
||||
if not counterpart_account_id:
|
||||
chart_template = self.with_context(
|
||||
allowed_company_ids=self.company_id.root_id.ids
|
||||
).env["account.chart.template"]
|
||||
counterpart_account_id = chart_template.ref(
|
||||
"account_journal_payment_debit_account_id", raise_if_not_found=False
|
||||
).id
|
||||
if not counterpart_account_id:
|
||||
counterpart_account_id = self.company_id.transfer_account_id.id
|
||||
if not counterpart_account_id:
|
||||
raise UserError(
|
||||
_("Missing 'Internal Transfer' account on the company '%s'.")
|
||||
% self.company_id.display_name
|
||||
)
|
||||
|
||||
vals = {
|
||||
"journal_id": self.journal_id.id,
|
||||
"date": self.deposit_date,
|
||||
"ref": _("Check Deposit %s") % self.name,
|
||||
"company_id": self.company_id.id,
|
||||
"line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"account_id": self.in_hand_check_account_id.id,
|
||||
"partner_id": False,
|
||||
"credit": total_debit,
|
||||
"currency_id": self.currency_id.id,
|
||||
"amount_currency": total_amount_currency * -1,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"account_id": counterpart_account_id,
|
||||
"partner_id": False,
|
||||
"debit": total_debit,
|
||||
"currency_id": self.currency_id.id,
|
||||
"amount_currency": total_amount_currency,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
return vals
|
||||
|
||||
def validate_deposit(self):
|
||||
am_obj = self.env["account.move"]
|
||||
for deposit in self:
|
||||
move = am_obj.create(deposit._prepare_move_vals())
|
||||
move.action_post()
|
||||
lines_to_rec = self.check_payment_ids + move.line_ids.filtered(
|
||||
lambda x: x.account_id.id == self.in_hand_check_account_id.id
|
||||
)
|
||||
lines_to_rec.reconcile()
|
||||
deposit.write({"state": "done", "move_id": move.id})
|
||||
|
||||
def get_all_checks(self):
|
||||
self.ensure_one()
|
||||
if not self.in_hand_check_account_id:
|
||||
raise UserError(
|
||||
_(
|
||||
"In the configuration of journal '%s', "
|
||||
"in the 'Incoming Payments' tab, you must configure an "
|
||||
"Outstanding Receipts Account for the payment method "
|
||||
"'Manual (inbound)'."
|
||||
)
|
||||
% self.journal_id.display_name
|
||||
)
|
||||
all_pending_checks = self.env["account.move.line"].search(
|
||||
[
|
||||
("company_id", "=", self.company_id.id),
|
||||
("reconciled", "=", False),
|
||||
("account_id", "=", self.in_hand_check_account_id.id),
|
||||
("debit", ">", 0),
|
||||
("check_deposit_id", "=", False),
|
||||
("currency_id", "=", self.currency_id.id),
|
||||
("parent_state", "=", "posted"),
|
||||
]
|
||||
)
|
||||
if all_pending_checks:
|
||||
self.message_post(body=_("Get All Received Checks"))
|
||||
all_pending_checks.write({"check_deposit_id": self.id})
|
||||
else:
|
||||
raise UserError(
|
||||
_(
|
||||
"There are no received checks in account '%(account)s' in currency "
|
||||
"'%(currency)s' that are not already in this check deposit.",
|
||||
account=self.in_hand_check_account_id.display_name,
|
||||
currency=self.currency_id.display_name,
|
||||
)
|
||||
)
|
||||
20
account_check_deposit/models/account_move_line.py
Executable file
20
account_check_deposit/models/account_move_line.py
Executable file
@@ -0,0 +1,20 @@
|
||||
# Copyright 2012-2022 Akretion France (http://www.akretion.com/)
|
||||
# @author: Benoît GUILLOT <benoit.guillot@akretion.com>
|
||||
# @author: Chafique DELLI <chafique.delli@akretion.com>
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# @author: Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
|
||||
# Copyright 2018-2022 Tecnativa - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AccountMoveLine(models.Model):
|
||||
_inherit = "account.move.line"
|
||||
|
||||
check_deposit_id = fields.Many2one(
|
||||
comodel_name="account.check.deposit",
|
||||
string="Check Deposit",
|
||||
copy=False,
|
||||
check_company=True,
|
||||
)
|
||||
Reference in New Issue
Block a user