first commit
This commit is contained in:
354
modules/sale_secondary_unit/sale.py
Normal file
354
modules/sale_secondary_unit/sale.py
Normal file
@@ -0,0 +1,354 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
from trytond.model import fields
|
||||
from trytond.modules.currency.fields import Monetary
|
||||
from trytond.modules.product import price_digits, round_price
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.pyson import Eval, If
|
||||
|
||||
|
||||
class Line(metaclass=PoolMeta):
|
||||
__name__ = 'sale.line'
|
||||
|
||||
secondary_quantity = fields.Function(fields.Float(
|
||||
"Secondary Quantity", digits='secondary_unit',
|
||||
states={
|
||||
'invisible': ((Eval('type') != 'line')
|
||||
| ~Eval('secondary_unit')),
|
||||
'readonly': Eval('sale_state') != 'draft',
|
||||
},
|
||||
depends=['secondary_uom_factor', 'secondary_uom_rate']),
|
||||
'on_change_with_secondary_quantity', setter='set_secondary')
|
||||
secondary_unit = fields.Many2One(
|
||||
'product.uom', "Secondary Unit", ondelete='RESTRICT',
|
||||
domain=[
|
||||
If(Eval('sale_state') == 'draft',
|
||||
('category', '=', Eval('product_secondary_uom_category')),
|
||||
()),
|
||||
],
|
||||
states={
|
||||
'invisible': ((Eval('type') != 'line')
|
||||
| ~Eval('product_secondary_uom_category')),
|
||||
'readonly': Eval('sale_state') != 'draft',
|
||||
})
|
||||
secondary_unit_price = fields.Function(Monetary(
|
||||
"Secondary Unit Price", currency='currency', digits=price_digits,
|
||||
states={
|
||||
'invisible': ((Eval('type') != 'line')
|
||||
| ~Eval('secondary_unit')),
|
||||
'readonly': Eval('sale_state') != 'draft',
|
||||
}),
|
||||
'on_change_with_secondary_unit_price', setter='set_secondary')
|
||||
|
||||
secondary_uom_factor = fields.Float(
|
||||
"Secondary UoM Factor",
|
||||
states={
|
||||
'readonly': True,
|
||||
'required': (Eval('type') == 'line') & Eval('secondary_unit'),
|
||||
},
|
||||
help="The factor for the secondary Unit of Measure.")
|
||||
secondary_uom_rate = fields.Float(
|
||||
"Secondary UoM Rate",
|
||||
states={
|
||||
'readonly': True,
|
||||
'required': (Eval('type') == 'line') & Eval('secondary_unit'),
|
||||
},
|
||||
help="The rate for the secondary Unit of Measure.")
|
||||
|
||||
product_secondary_uom_category = fields.Function(
|
||||
fields.Many2One(
|
||||
'product.uom.category', "Product Secondary UoM Category",
|
||||
help="The category of secondary Unit of Measure for the product."),
|
||||
'on_change_with_product_secondary_uom_category')
|
||||
|
||||
@fields.depends('product')
|
||||
def _secondary_record(self):
|
||||
if self.product and self.product.sale_secondary_uom:
|
||||
return self.product
|
||||
|
||||
@fields.depends('quantity', 'unit', 'secondary_unit',
|
||||
'secondary_uom_factor', 'secondary_uom_rate')
|
||||
def on_change_with_secondary_quantity(self, name=None):
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
if (self.quantity and self.unit and self.secondary_unit
|
||||
and (self.secondary_uom_factor or self.secondary_uom_rate)):
|
||||
return Uom.compute_qty(
|
||||
self.unit, self.quantity,
|
||||
self.secondary_unit, round=True,
|
||||
factor=self.secondary_uom_factor, rate=self.secondary_uom_rate)
|
||||
else:
|
||||
return None
|
||||
|
||||
@fields.depends('secondary_quantity', 'secondary_unit', 'unit',
|
||||
'secondary_uom_factor', 'secondary_uom_rate',
|
||||
methods=['on_change_quantity', 'on_change_with_amount'])
|
||||
def on_change_secondary_quantity(self):
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
if (self.secondary_quantity and self.secondary_unit and self.unit
|
||||
and (self.secondary_uom_factor or self.secondary_uom_rate)):
|
||||
self.quantity = Uom.compute_qty(
|
||||
self.secondary_unit, self.secondary_quantity,
|
||||
self.unit, round=True,
|
||||
factor=self.secondary_uom_rate, rate=self.secondary_uom_factor)
|
||||
self.on_change_quantity()
|
||||
self.amount = self.on_change_with_amount()
|
||||
|
||||
@fields.depends('unit_price', 'unit', 'secondary_unit',
|
||||
'secondary_uom_factor', 'secondary_uom_rate')
|
||||
def on_change_with_secondary_unit_price(self, name=None):
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
if (self.unit_price is not None and self.unit and self.secondary_unit
|
||||
and (self.secondary_uom_factor or self.secondary_uom_rate)):
|
||||
unit_price = Uom.compute_price(
|
||||
self.unit, self.unit_price, self.secondary_unit,
|
||||
factor=self.secondary_uom_factor, rate=self.secondary_uom_rate)
|
||||
return round_price(unit_price)
|
||||
else:
|
||||
return None
|
||||
|
||||
@fields.depends('secondary_unit_price', 'secondary_unit', 'unit',
|
||||
'secondary_uom_factor', 'secondary_uom_rate',
|
||||
methods=['on_change_with_amount'])
|
||||
def on_change_secondary_unit_price(self, name=None):
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
if (self.secondary_unit_price is not None
|
||||
and self.secondary_unit and self.unit
|
||||
and (self.secondary_uom_factor or self.secondary_uom_rate)):
|
||||
self.unit_price = Uom.compute_price(
|
||||
self.secondary_unit, self.secondary_unit_price, self.unit,
|
||||
factor=self.secondary_uom_rate, rate=self.secondary_uom_factor)
|
||||
self.unit_price = round_price(self.unit_price)
|
||||
self.amount = self.on_change_with_amount()
|
||||
|
||||
@fields.depends(methods=[
|
||||
'on_change_secondary_quantity', 'on_change_secondary_unit_price'])
|
||||
def on_change_secondary_unit(self):
|
||||
self.on_change_secondary_quantity()
|
||||
self.on_change_secondary_unit_price()
|
||||
|
||||
@fields.depends(methods=['_secondary_record'])
|
||||
def on_change_with_product_secondary_uom_category(self, name=None):
|
||||
secondary_record = self._secondary_record()
|
||||
if secondary_record:
|
||||
return secondary_record.sale_secondary_uom.category
|
||||
|
||||
@classmethod
|
||||
def set_secondary(cls, lines, name, value):
|
||||
pass
|
||||
|
||||
@fields.depends(
|
||||
'secondary_unit', 'product',
|
||||
methods=['on_change_with_secondary_quantity', '_secondary_record'])
|
||||
def on_change_product(self):
|
||||
super().on_change_product()
|
||||
secondary_record = self._secondary_record()
|
||||
if secondary_record:
|
||||
secondary_uom = secondary_record.sale_secondary_uom
|
||||
if self.secondary_unit and secondary_uom:
|
||||
if self.secondary_unit.category != secondary_uom.category:
|
||||
self.secondary_unit = None
|
||||
if not self.secondary_unit and secondary_record != self.product:
|
||||
self.secondary_unit = secondary_uom
|
||||
|
||||
if secondary_record:
|
||||
self.secondary_uom_factor = (
|
||||
secondary_record.sale_secondary_uom_normal_factor)
|
||||
self.secondary_uom_rate = (
|
||||
secondary_record.sale_secondary_uom_normal_rate)
|
||||
else:
|
||||
self.secondary_unit = None
|
||||
self.secondary_uom_factor = None
|
||||
self.secondary_uom_rate = None
|
||||
self.secondary_quantity = self.on_change_with_secondary_quantity()
|
||||
|
||||
def get_invoice_line(self):
|
||||
pool = Pool()
|
||||
InvoiceLine = pool.get('account.invoice.line')
|
||||
lines = super().get_invoice_line()
|
||||
if hasattr(InvoiceLine, 'secondary_unit'):
|
||||
for line in lines:
|
||||
if line.type != 'line':
|
||||
continue
|
||||
if line.unit == self.unit:
|
||||
line.secondary_unit = self.secondary_unit
|
||||
return lines
|
||||
|
||||
def get_move(self, shipment_type):
|
||||
move = super().get_move(shipment_type)
|
||||
if move and hasattr(move.__class__, 'secondary_unit'):
|
||||
if move.unit == self.unit:
|
||||
move.secondary_unit = self.secondary_unit
|
||||
return move
|
||||
|
||||
|
||||
class Line_ProductCustomer(metaclass=PoolMeta):
|
||||
__name__ = 'sale.line'
|
||||
|
||||
@fields.depends('product_customer')
|
||||
def _secondary_record(self):
|
||||
if self.product_customer and self.product_customer.sale_secondary_uom:
|
||||
return self.product_customer
|
||||
return super()._secondary_record()
|
||||
|
||||
|
||||
class OpportunityLine(metaclass=PoolMeta):
|
||||
__name__ = 'sale.opportunity.line'
|
||||
|
||||
def _set_sale_line_quantity(self, sale_line):
|
||||
super()._set_sale_line_quantity(sale_line)
|
||||
if self.unit.category != self.product.sale_uom.category:
|
||||
sale_line.unit = self.product.sale_uom
|
||||
sale_line.secondary_quantity = self.quantity
|
||||
sale_line.secondary_unit = self.unit
|
||||
sale_line.on_change_secondary_quantity()
|
||||
|
||||
|
||||
class BlanketAgreementLine(metaclass=PoolMeta):
|
||||
__name__ = 'sale.blanket_agreement.line'
|
||||
|
||||
product_secondary_uom_category = fields.Function(
|
||||
fields.Many2One(
|
||||
'product.uom.category', "Product Secondary UoM Category",
|
||||
help="The category of the secondary Unit of Measure "
|
||||
"for the product."),
|
||||
'on_change_with_product_secondary_uom_category')
|
||||
|
||||
@classmethod
|
||||
def _unit_categories(cls):
|
||||
return super()._unit_categories() + ['product_secondary_uom_category']
|
||||
|
||||
def is_same_uom_category(self, sale_line):
|
||||
return super().is_same_uom_category(sale_line) or (
|
||||
sale_line.secondary_unit and (
|
||||
self.unit.category == sale_line.secondary_unit.category))
|
||||
|
||||
def remainig_quantity_for_sale(self, line, round=True):
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
remaining_quantity = super().remainig_quantity_for_sale(
|
||||
line, round=round)
|
||||
if (self.remaining_quantity is not None
|
||||
and line.secondary_unit
|
||||
and self.unit.category == line.secondary_unit.category):
|
||||
remaining_quantity = Uom.compute_qty(
|
||||
self.unit, self.remaining_quantity, line.unit,
|
||||
factor=line.secondary_uom_rate,
|
||||
rate=line.secondary_uom_factor,
|
||||
round=round)
|
||||
return remaining_quantity
|
||||
|
||||
@fields.depends('product')
|
||||
def on_change_with_product_secondary_uom_category(self, name=None):
|
||||
if self.product and self.product.sale_secondary_uom:
|
||||
return self.product.sale_secondary_uom.category
|
||||
|
||||
def _set_sale_line_quantity(self, sale_line):
|
||||
super()._set_sale_line_quantity(sale_line)
|
||||
secondary_uom = self.product.sale_secondary_uom
|
||||
if (secondary_uom
|
||||
and self.unit.category == secondary_uom.category):
|
||||
sale_line.unit = self.product.sale_uom
|
||||
sale_line.secondary_quantity = self.remaining_quantity or 0
|
||||
sale_line.secondary_unit = self.unit
|
||||
sale_line.secondary_unit_price = self.unit_price
|
||||
sale_line.on_change_secondary_quantity()
|
||||
|
||||
|
||||
class LineBlanketAgreement(metaclass=PoolMeta):
|
||||
__name__ = 'sale.line'
|
||||
|
||||
@fields.depends(
|
||||
'blanket_agreement_line', '_parent_blanket_agreement_line.unit',
|
||||
'_parent_blanket_agreement_line.unit_price', 'unit', 'secondary_unit',
|
||||
'secondary_uom_rate', 'secondary_uom_factor')
|
||||
def compute_unit_price(self):
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
unit_price = super().compute_unit_price()
|
||||
line = self.blanket_agreement_line
|
||||
if (line
|
||||
and self.unit
|
||||
and self.secondary_unit
|
||||
and line.unit
|
||||
and self.secondary_unit.category == line.unit.category):
|
||||
secondary_unit_price = Uom.compute_price(
|
||||
line.unit, line.unit_price, self.secondary_unit)
|
||||
unit_price = Uom.compute_price(
|
||||
self.secondary_unit, secondary_unit_price, self.unit,
|
||||
factor=self.secondary_uom_rate, rate=self.secondary_uom_factor)
|
||||
unit_price = round_price(unit_price)
|
||||
return unit_price
|
||||
|
||||
@fields.depends(
|
||||
'blanket_agreement_line',
|
||||
'_parent_blanket_agreement_line.unit',
|
||||
'_parent_blanket_agreement_line.remaining_quantity',
|
||||
'sale', 'unit', 'secondary_quantity', 'secondary_unit',
|
||||
'secondary_unit_price', methods=['on_change_secondary_quantity'])
|
||||
def on_change_blanket_agreement_line(self):
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
super().on_change_blanket_agreement_line()
|
||||
if self.blanket_agreement_line:
|
||||
line = self.blanket_agreement_line
|
||||
if (self.secondary_unit and line.unit
|
||||
and self.secondary_unit.category == line.unit.category):
|
||||
if line.remaining_quantity is not None:
|
||||
remaining_quantity = Uom.compute_qty(
|
||||
line.unit, line.remaining_quantity,
|
||||
self.secondary_unit)
|
||||
if (self.secondary_quantity is None
|
||||
or self.secondary_quantity > remaining_quantity):
|
||||
self.secondary_quantity = remaining_quantity
|
||||
self.on_change_secondary_quantity()
|
||||
|
||||
def quantity_for_blanket_agreement(self, line, round=True):
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
quantity = super().quantity_for_blanket_agreement(line, round=round)
|
||||
if (self.secondary_unit
|
||||
and self.secondary_unit.category == line.unit.category):
|
||||
sale_line_quantity = (
|
||||
self.actual_quantity if self.actual_quantity is not None
|
||||
else self.quantity)
|
||||
quantity = Uom.compute_qty(
|
||||
self.unit, sale_line_quantity, line.unit,
|
||||
factor=self.secondary_uom_factor,
|
||||
rate=self.secondary_uom_rate,
|
||||
round=round)
|
||||
return quantity
|
||||
|
||||
|
||||
class AmendmentLine(metaclass=PoolMeta):
|
||||
__name__ = 'sale.amendment.line'
|
||||
|
||||
product_secondary_uom_category = fields.Function(
|
||||
fields.Many2One(
|
||||
'product.uom.category', "Product Secondary UoM Category",
|
||||
help="The category of the secondary Unit of Measure "
|
||||
"for the product."),
|
||||
'on_change_with_product_secondary_uom_category')
|
||||
|
||||
@classmethod
|
||||
def _unit_categories(cls):
|
||||
return super()._unit_categories() + ['product_secondary_uom_category']
|
||||
|
||||
@fields.depends('product')
|
||||
def on_change_with_product_secondary_uom_category(self, name=None):
|
||||
if self.product and self.product.sale_secondary_uom:
|
||||
return self.product.sale_secondary_uom.category
|
||||
|
||||
def _apply_line(self, sale, sale_line):
|
||||
super()._apply_line(sale, sale_line)
|
||||
if (self.unit and self.product
|
||||
and self.unit.category != self.product.sale_uom.category):
|
||||
sale_line.unit = self.line.unit
|
||||
sale_line.secondary_quantity = self.quantity
|
||||
sale_line.secondary_unit = self.unit
|
||||
sale_line.on_change_secondary_quantity()
|
||||
sale_line.secondary_unit_price = self.unit_price
|
||||
sale_line.on_change_secondary_unit_price()
|
||||
Reference in New Issue
Block a user