changes
This commit is contained in:
167
fusion_inventory/models/product_product.py
Normal file
167
fusion_inventory/models/product_product.py
Normal file
@@ -0,0 +1,167 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
import logging
|
||||
from odoo import models, fields, api
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = 'product.product'
|
||||
|
||||
x_fi_price_offset = fields.Float(
|
||||
string='Price Offset',
|
||||
default=0.0,
|
||||
help='Margin-calculated price adjustment, kept separate from '
|
||||
'manual attribute price extras.')
|
||||
x_fi_variant_margin_pct = fields.Float(
|
||||
string='Margin (%)',
|
||||
compute='_compute_variant_margin',
|
||||
inverse='_inverse_variant_margin',
|
||||
store=True, readonly=False,
|
||||
help='Profit margin based on (cost + shipping + extra cost). '
|
||||
'Extra Price from attributes is added on top, outside margin.')
|
||||
x_fi_margin_override = fields.Boolean(
|
||||
string='Margin Override',
|
||||
default=False,
|
||||
help='When set, the template "Apply Margin" button '
|
||||
'and automatic propagation skip this variant.')
|
||||
x_fi_variant_profit = fields.Float(
|
||||
string='Profit',
|
||||
compute='_compute_variant_profit',
|
||||
help='Total sale price minus total cost.')
|
||||
x_fi_shipping_cost = fields.Float(
|
||||
string='Shipping Cost',
|
||||
default=0.0,
|
||||
help='Per-unit shipping cost.')
|
||||
x_fi_cost_extra = fields.Float(
|
||||
string='Attribute Extra Cost',
|
||||
compute='_compute_cost_extra', store=True,
|
||||
help='Sum of Extra Cost from all attribute values for this variant.')
|
||||
|
||||
@api.depends('product_template_attribute_value_ids.x_fi_extra_cost')
|
||||
def _compute_cost_extra(self):
|
||||
for product in self:
|
||||
product.x_fi_cost_extra = sum(
|
||||
product.product_template_attribute_value_ids.mapped(
|
||||
'x_fi_extra_cost'))
|
||||
|
||||
# ── Include price offset in pricelist / SO pricing ──
|
||||
|
||||
def _get_attributes_extra_price(self):
|
||||
extra = super()._get_attributes_extra_price()
|
||||
return extra + (self.x_fi_price_offset or 0.0)
|
||||
|
||||
# ── Override lst_price to include our price offset ──
|
||||
|
||||
@api.depends('list_price', 'price_extra', 'x_fi_price_offset')
|
||||
@api.depends_context('uom')
|
||||
def _compute_product_lst_price(self):
|
||||
to_uom = None
|
||||
if 'uom' in self._context:
|
||||
to_uom = self.env['uom.uom'].browse(self._context['uom'])
|
||||
for product in self:
|
||||
if to_uom:
|
||||
list_price = product.uom_id._compute_price(
|
||||
product.list_price, to_uom)
|
||||
else:
|
||||
list_price = product.list_price
|
||||
product.lst_price = (
|
||||
list_price
|
||||
+ product.price_extra
|
||||
+ (product.x_fi_price_offset or 0.0))
|
||||
|
||||
def _set_product_lst_price(self):
|
||||
for product in self:
|
||||
if self._context.get('uom'):
|
||||
value = (
|
||||
float(product.lst_price) * product.uom_id.factor
|
||||
/ self.env['uom.uom'].browse(
|
||||
self._context['uom']).factor)
|
||||
else:
|
||||
value = product.lst_price
|
||||
value -= product.price_extra
|
||||
value -= (product.x_fi_price_offset or 0.0)
|
||||
product.write({'list_price': value})
|
||||
|
||||
# ── Margin / Profit ──
|
||||
# effective_cost = standard_price + shipping + extra_cost
|
||||
# base_sale_price = list_price + x_fi_price_offset (margin applies here)
|
||||
# final_price = base_sale_price + price_extra (surcharge on top)
|
||||
# margin = (base_sale_price - effective_cost) / base_sale_price
|
||||
|
||||
@api.depends('list_price', 'price_extra', 'x_fi_price_offset',
|
||||
'standard_price', 'x_fi_shipping_cost', 'x_fi_cost_extra')
|
||||
def _compute_variant_margin(self):
|
||||
for var in self:
|
||||
base = var.list_price + (var.x_fi_price_offset or 0.0)
|
||||
eff = (var.standard_price
|
||||
+ (var.x_fi_shipping_cost or 0.0)
|
||||
+ (var.x_fi_cost_extra or 0.0))
|
||||
if base > 0 and eff > 0:
|
||||
var.x_fi_variant_margin_pct = round(
|
||||
((base - eff) / base) * 100, 2)
|
||||
else:
|
||||
var.x_fi_variant_margin_pct = 0.0
|
||||
|
||||
def _inverse_variant_margin(self):
|
||||
for var in self:
|
||||
margin = var.x_fi_variant_margin_pct or 0.0
|
||||
eff = (var.standard_price
|
||||
+ (var.x_fi_shipping_cost or 0.0)
|
||||
+ (var.x_fi_cost_extra or 0.0))
|
||||
if eff > 0 and 0 < margin < 100:
|
||||
base = round(eff / (1 - margin / 100), 2)
|
||||
var.x_fi_price_offset = round(base - var.list_price, 2)
|
||||
|
||||
@api.depends('list_price', 'price_extra', 'x_fi_price_offset',
|
||||
'standard_price', 'x_fi_shipping_cost', 'x_fi_cost_extra')
|
||||
def _compute_variant_profit(self):
|
||||
for var in self:
|
||||
lst = (var.list_price
|
||||
+ var.price_extra
|
||||
+ (var.x_fi_price_offset or 0.0))
|
||||
eff = (var.standard_price
|
||||
+ (var.x_fi_shipping_cost or 0.0)
|
||||
+ (var.x_fi_cost_extra or 0.0))
|
||||
var.x_fi_variant_profit = lst - eff
|
||||
|
||||
# ── Onchange handlers ──
|
||||
|
||||
@api.onchange('x_fi_variant_margin_pct')
|
||||
def _onchange_variant_margin(self):
|
||||
for var in self:
|
||||
margin = var.x_fi_variant_margin_pct or 0.0
|
||||
eff = (var.standard_price
|
||||
+ (var.x_fi_shipping_cost or 0.0)
|
||||
+ (var.x_fi_cost_extra or 0.0))
|
||||
if eff > 0 and 0 < margin < 100:
|
||||
base = round(eff / (1 - margin / 100), 2)
|
||||
var.x_fi_price_offset = round(base - var.list_price, 2)
|
||||
|
||||
@api.onchange('standard_price', 'x_fi_shipping_cost')
|
||||
def _onchange_variant_cost(self):
|
||||
"""When cost or shipping changes, recalculate price to keep margin."""
|
||||
for var in self:
|
||||
margin = var.x_fi_variant_margin_pct or 0.0
|
||||
eff = (var.standard_price
|
||||
+ (var.x_fi_shipping_cost or 0.0)
|
||||
+ (var.x_fi_cost_extra or 0.0))
|
||||
if eff > 0 and 0 < margin < 100:
|
||||
base = round(eff / (1 - margin / 100), 2)
|
||||
var.x_fi_price_offset = round(base - var.list_price, 2)
|
||||
|
||||
def _apply_margin_to_variant(self, margin_pct):
|
||||
"""Set this variant's price offset to achieve the given margin."""
|
||||
self.ensure_one()
|
||||
eff = (self.standard_price
|
||||
+ (self.x_fi_shipping_cost or 0.0)
|
||||
+ (self.x_fi_cost_extra or 0.0))
|
||||
if eff <= 0 or margin_pct <= 0 or margin_pct >= 100:
|
||||
return
|
||||
base = round(eff / (1 - margin_pct / 100), 2)
|
||||
new_offset = round(base - self.list_price, 2)
|
||||
if abs((self.x_fi_price_offset or 0.0) - new_offset) > 0.001:
|
||||
self.x_fi_price_offset = new_offset
|
||||
Reference in New Issue
Block a user