add purchase_rappel. manage rappel commission for vendors
This commit is contained in:
parent
4fbf3284f4
commit
4c07dd042d
24 changed files with 1458 additions and 0 deletions
201
purchase_rappel/wizard/account_move_rappel_wizard.py
Normal file
201
purchase_rappel/wizard/account_move_rappel_wizard.py
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from collections import defaultdict
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class AccountMoveRappelWizard(models.TransientModel):
|
||||
"""Wizard to generate rappel commission (sale) invoices from selected vendor bills.
|
||||
|
||||
One sale invoice is created per vendor. Each original bill becomes one invoice
|
||||
line whose amount is computed as: taxable_base × commission_rate / 100.
|
||||
"""
|
||||
|
||||
_name = "account.move.rappel.wizard"
|
||||
_description = "Create Rappel Commission Invoice"
|
||||
|
||||
move_ids = fields.Many2many(
|
||||
comodel_name="account.move",
|
||||
string="Vendor Bills",
|
||||
readonly=True,
|
||||
)
|
||||
invoice_date = fields.Date(
|
||||
string="Invoice Date",
|
||||
default=fields.Date.context_today,
|
||||
required=True,
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
comodel_name="res.company",
|
||||
default=lambda self: self.env.company,
|
||||
required=True,
|
||||
)
|
||||
journal_id = fields.Many2one(
|
||||
comodel_name="account.journal",
|
||||
string="Journal",
|
||||
domain="[('type', '=', 'sale'), ('company_id', '=', company_id)]",
|
||||
required=True,
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
comodel_name="product.product",
|
||||
string="Commission Product",
|
||||
required=True,
|
||||
)
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
company = self.env.company
|
||||
active_ids = self.env.context.get("active_ids", [])
|
||||
moves = self.env["account.move"].browse(active_ids)
|
||||
|
||||
# Filter only posted vendor bills
|
||||
valid_moves = moves.filtered(
|
||||
lambda m: m.move_type == "in_invoice" and m.state == "posted"
|
||||
)
|
||||
if not valid_moves:
|
||||
raise UserError(
|
||||
_(
|
||||
"No posted vendor bills found in the selection. "
|
||||
"Only posted (validated) vendor bills can be used to create "
|
||||
"rappel commission invoices."
|
||||
)
|
||||
)
|
||||
|
||||
# Filter only pending bills
|
||||
pending_moves = valid_moves.filtered(lambda m: m.rappel_pending)
|
||||
if not pending_moves:
|
||||
raise UserError(
|
||||
_(
|
||||
"None of the selected vendor bills are pending commission. "
|
||||
"They may have already been commissioned."
|
||||
)
|
||||
)
|
||||
|
||||
# Warn about bills whose partner has no rappel configured
|
||||
no_rappel = pending_moves.filtered(lambda m: not m.partner_id.rappel_commission)
|
||||
if no_rappel and len(no_rappel) == len(pending_moves):
|
||||
raise UserError(
|
||||
_(
|
||||
"None of the selected vendors have the rappel commission enabled. "
|
||||
"Please configure the commission rate on the vendor contact first."
|
||||
)
|
||||
)
|
||||
|
||||
res.update(
|
||||
{
|
||||
"move_ids": [(6, 0, pending_moves.ids)],
|
||||
"journal_id": company.rappel_journal_id.id or False,
|
||||
"product_id": company.rappel_product_id.id or False,
|
||||
}
|
||||
)
|
||||
return res
|
||||
|
||||
def action_create_rappel_invoices(self):
|
||||
self.ensure_one()
|
||||
|
||||
if not self.journal_id:
|
||||
raise UserError(
|
||||
_(
|
||||
"Please select a journal for the rappel commission invoices, or "
|
||||
"configure a default one in Purchase Settings."
|
||||
)
|
||||
)
|
||||
if not self.product_id:
|
||||
raise UserError(
|
||||
_(
|
||||
"Please select a product for the rappel commission invoices, or "
|
||||
"configure a default one in Purchase Settings."
|
||||
)
|
||||
)
|
||||
|
||||
# Group eligible bills by partner (only partners with rappel enabled)
|
||||
bills_by_partner = defaultdict(lambda: self.env["account.move"])
|
||||
for bill in self.move_ids:
|
||||
if (
|
||||
bill.partner_id.rappel_commission
|
||||
and bill.partner_id.rappel_commission_rate
|
||||
):
|
||||
bills_by_partner[bill.partner_id] |= bill
|
||||
|
||||
if not bills_by_partner:
|
||||
raise UserError(
|
||||
_(
|
||||
"None of the selected vendor bills belong to vendors with a rappel "
|
||||
"commission rate configured."
|
||||
)
|
||||
)
|
||||
|
||||
created_invoices = self.env["account.move"]
|
||||
|
||||
for partner, bills in bills_by_partner.items():
|
||||
rate = partner.rappel_commission_rate
|
||||
invoice_lines = []
|
||||
|
||||
for bill in bills:
|
||||
taxable_base = bill.amount_untaxed
|
||||
commission_amount = taxable_base * rate / 100.0
|
||||
name = _(
|
||||
"Rappel commission %(rate)s%% — Bill %(bill)s "
|
||||
"(taxable base: %(base)s %(currency)s)",
|
||||
rate=rate,
|
||||
bill=bill.name,
|
||||
base=f"{taxable_base:,.2f}",
|
||||
currency=bill.currency_id.name,
|
||||
)
|
||||
invoice_lines.append(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product_id.id,
|
||||
"name": name,
|
||||
"quantity": 1,
|
||||
"price_unit": commission_amount,
|
||||
"tax_ids": [
|
||||
(
|
||||
6,
|
||||
0,
|
||||
self.product_id.taxes_id.filtered(
|
||||
lambda t: t.company_id == self.company_id
|
||||
).ids,
|
||||
)
|
||||
],
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
invoice_vals = {
|
||||
"move_type": "out_invoice",
|
||||
"partner_id": partner.id,
|
||||
"invoice_date": self.invoice_date,
|
||||
"journal_id": self.journal_id.id,
|
||||
"company_id": self.company_id.id,
|
||||
"invoice_line_ids": invoice_lines,
|
||||
"narration": _(
|
||||
"Rappel commission invoice generated from %d vendor bill(s).",
|
||||
len(bills),
|
||||
),
|
||||
}
|
||||
created_invoice = self.env["account.move"].create(invoice_vals)
|
||||
created_invoices |= created_invoice
|
||||
|
||||
# Mark source bills as commissioned
|
||||
bills.write({"rappel_pending": False})
|
||||
|
||||
# Open the created invoices
|
||||
if len(created_invoices) == 1:
|
||||
return {
|
||||
"type": "ir.actions.act_window",
|
||||
"res_model": "account.move",
|
||||
"res_id": created_invoices.id,
|
||||
"view_mode": "form",
|
||||
"views": [(False, "form")],
|
||||
}
|
||||
return {
|
||||
"type": "ir.actions.act_window",
|
||||
"res_model": "account.move",
|
||||
"domain": [("id", "in", created_invoices.ids)],
|
||||
"view_mode": "list,form",
|
||||
"name": _("Rappel Commission Invoices"),
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue