Initial commit: Odoo 18.0-20251222 extra-addons
This commit is contained in:
1
sale_partner_primeship/models/__init__.py
Executable file
1
sale_partner_primeship/models/__init__.py
Executable file
@@ -0,0 +1 @@
|
||||
from . import product_template, res_partner, sale_primeship, sale_order
|
||||
13
sale_partner_primeship/models/product_template.py
Executable file
13
sale_partner_primeship/models/product_template.py
Executable file
@@ -0,0 +1,13 @@
|
||||
# Copyright 2021 Akretion France (http://www.akretion.com/)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = "product.template"
|
||||
|
||||
primeship_activation = fields.Boolean(string="Activates primeship", default=False)
|
||||
primeship_duration = fields.Integer(
|
||||
string="Primeship duration (in months)", default=12
|
||||
)
|
||||
47
sale_partner_primeship/models/res_partner.py
Executable file
47
sale_partner_primeship/models/res_partner.py
Executable file
@@ -0,0 +1,47 @@
|
||||
# Copyright 2021 Akretion France (http://www.akretion.com/)
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class ResPartner(models.Model):
|
||||
_inherit = "res.partner"
|
||||
|
||||
primeship_ids = fields.One2many(
|
||||
comodel_name="sale.primeship",
|
||||
inverse_name="partner_id",
|
||||
required=True,
|
||||
)
|
||||
|
||||
# store True allow to filter on active_primeship.
|
||||
# There is a cron job to set it to False when the customer has no active
|
||||
# primeship anymore.
|
||||
active_primeship = fields.Boolean(
|
||||
compute="_compute_active_primeship",
|
||||
store=True,
|
||||
)
|
||||
primeship_count = fields.Integer(
|
||||
string="Primeships Count", compute="_compute_primeship_count"
|
||||
)
|
||||
|
||||
@api.depends(
|
||||
"commercial_partner_id.primeship_ids",
|
||||
"commercial_partner_id.primeship_ids.current",
|
||||
)
|
||||
def _compute_active_primeship(self):
|
||||
for record in self:
|
||||
record.active_primeship = (
|
||||
record.commercial_partner_id.primeship_ids.filtered("current")
|
||||
)
|
||||
|
||||
@api.depends("commercial_partner_id.primeship_ids")
|
||||
def _compute_primeship_count(self):
|
||||
for record in self:
|
||||
record.primeship_count = len(record.commercial_partner_id.primeship_ids)
|
||||
|
||||
@api.model
|
||||
def _check_expired_primeships(self):
|
||||
self.with_context(
|
||||
active_test=False,
|
||||
).search([("active_primeship", "=", True)])._compute_active_primeship()
|
||||
111
sale_partner_primeship/models/sale_order.py
Executable file
111
sale_partner_primeship/models/sale_order.py
Executable file
@@ -0,0 +1,111 @@
|
||||
# Copyright 2021 Akretion France (http://www.akretion.com/)
|
||||
# Copyright 2024 Akretion France (http://www.akretion.com/)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = "sale.order"
|
||||
|
||||
def _action_confirm(self):
|
||||
super()._action_confirm()
|
||||
sale_primeship = self.env["sale.primeship"]
|
||||
for record in self:
|
||||
partner = record.partner_id.commercial_partner_id
|
||||
|
||||
for line in record.order_line:
|
||||
product_template = line.product_template_id
|
||||
|
||||
if product_template.primeship_activation:
|
||||
# We do not take in account product_qty for now:
|
||||
duration = product_template.primeship_duration
|
||||
start = fields.Date.context_today(record)
|
||||
end = start + relativedelta(months=duration)
|
||||
|
||||
# If we have already some primeships, we need to check for overlaps
|
||||
if partner.primeship_ids:
|
||||
# We assume no overlaps between partner primeships
|
||||
for primeship in partner.primeship_ids.sorted("start_date"):
|
||||
if primeship.overlaps(start, end):
|
||||
start = primeship.end_date
|
||||
end = start + relativedelta(months=duration)
|
||||
|
||||
vals = {
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"partner_id": partner.id,
|
||||
"order_line_id": line.id,
|
||||
# this is to reactivate a maybe deactivated existing primeship
|
||||
"active": True,
|
||||
}
|
||||
if line.primeship_id:
|
||||
# Hm... something seems to have gone wrong here,
|
||||
# but we handle it nonetheless.
|
||||
line.primeship_id.write(vals)
|
||||
else:
|
||||
# We may have a deactivated primeship because of an order
|
||||
# cancellation.
|
||||
primeship = sale_primeship.with_context(
|
||||
active_test=False,
|
||||
).search([("order_line_id", "=", line.id)])
|
||||
if primeship:
|
||||
primeship.write(vals)
|
||||
else:
|
||||
sale_primeship.create(vals)
|
||||
|
||||
return True
|
||||
|
||||
def _action_cancel(self):
|
||||
rv = super()._action_cancel()
|
||||
for record in self:
|
||||
record.order_line.mapped("primeship_id").active = False
|
||||
return rv
|
||||
|
||||
|
||||
class SaleOrderLine(models.Model):
|
||||
_inherit = "sale.order.line"
|
||||
|
||||
primeship_id = fields.Many2one(
|
||||
string="Primeships",
|
||||
comodel_name="sale.primeship",
|
||||
compute="_compute_primeship_id",
|
||||
inverse="_inverse_primeship_id",
|
||||
)
|
||||
|
||||
# One2one impl
|
||||
primeship_ids = fields.One2many(
|
||||
comodel_name="sale.primeship", inverse_name="order_line_id"
|
||||
)
|
||||
|
||||
@api.depends("primeship_ids")
|
||||
def _compute_primeship_id(self):
|
||||
for record in self:
|
||||
record.primeship_id = record.primeship_ids[:1]
|
||||
|
||||
def _inverse_primeship_id(self):
|
||||
for record in self:
|
||||
if record.primeship_ids:
|
||||
primeship = record.env["sale.primeship"].browse(
|
||||
record.primeship_ids[0].id
|
||||
)
|
||||
primeship.order_line_id = record
|
||||
|
||||
record.primeship_id.order_line_id = record
|
||||
|
||||
def _prepare_invoice_line(self, **optional_values):
|
||||
"""Update invoice start/end dates.
|
||||
Set invoice start/end dates to primeship start/end dates
|
||||
In case of multi quantity, this assumes continuous date ranges."""
|
||||
self.ensure_one()
|
||||
res = super()._prepare_invoice_line(**optional_values)
|
||||
if self.primeship_id:
|
||||
res.update(
|
||||
{
|
||||
"start_date": self.primeship_id.start_date,
|
||||
"end_date": self.primeship_id.end_date,
|
||||
}
|
||||
)
|
||||
return res
|
||||
77
sale_partner_primeship/models/sale_primeship.py
Executable file
77
sale_partner_primeship/models/sale_primeship.py
Executable file
@@ -0,0 +1,77 @@
|
||||
# Copyright 2021 Akretion France (http://www.akretion.com/)
|
||||
# Copyright 2024 Akretion France (http://www.akretion.com/)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class SalePrimeship(models.Model):
|
||||
_name = "sale.primeship"
|
||||
_description = "Sale Prime Memberships"
|
||||
|
||||
active = fields.Boolean(default=True)
|
||||
name = fields.Char(compute="_compute_name")
|
||||
|
||||
start_date = fields.Date(required=True)
|
||||
# End date day is not included in primeship date range
|
||||
end_date = fields.Date(required=True)
|
||||
|
||||
partner_id = fields.Many2one(
|
||||
comodel_name="res.partner",
|
||||
required=True,
|
||||
ondelete="cascade",
|
||||
index=True,
|
||||
)
|
||||
order_line_id = fields.Many2one(
|
||||
comodel_name="sale.order.line",
|
||||
string="Sale Order Line",
|
||||
)
|
||||
order_id = fields.Many2one(string="Sale Order", related="order_line_id.order_id")
|
||||
|
||||
current = fields.Boolean(string="Currently Active", compute="_compute_current")
|
||||
|
||||
_sql_constraints = [
|
||||
# Constraint for One2one impl of "sale.order.line".primeship_id
|
||||
(
|
||||
"unique_order_line",
|
||||
"UNIQUE(order_line_id)",
|
||||
"A sale order line can only have one primeship!",
|
||||
)
|
||||
]
|
||||
|
||||
@api.depends("start_date", "end_date")
|
||||
def _compute_name(self):
|
||||
for record in self:
|
||||
record.name = (
|
||||
f"{record.start_date} - {record.end_date} Primeship"
|
||||
if record
|
||||
else "New Primeship"
|
||||
)
|
||||
|
||||
@api.depends("active", "start_date", "end_date")
|
||||
def _compute_current(self):
|
||||
for record in self:
|
||||
record.current = (
|
||||
record.active
|
||||
and record.start_date
|
||||
<= fields.Date.context_today(record)
|
||||
< record.end_date
|
||||
)
|
||||
|
||||
@api.constrains("end_date")
|
||||
def _check_end_date(self):
|
||||
for record in self:
|
||||
if record.end_date < record.start_date:
|
||||
raise ValidationError(_("The end date cannot be before start date"))
|
||||
|
||||
if any(
|
||||
primeship.overlaps(record.start_date, record.end_date)
|
||||
for primeship in record.partner_id.primeship_ids
|
||||
if primeship.id != record.id
|
||||
):
|
||||
raise ValidationError(_("Primeships cannot overlaps"))
|
||||
|
||||
def overlaps(self, start, end):
|
||||
self.ensure_one()
|
||||
return self.start_date < end and self.end_date > start
|
||||
Reference in New Issue
Block a user