mirror of
https://github.com/NaN-tic/trytond-sale_product_package.git
synced 2023-12-14 03:03:09 +01:00
181 lines
6.9 KiB
Python
181 lines
6.9 KiB
Python
# 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.pool import PoolMeta
|
|
from trytond.pyson import Eval
|
|
from trytond.transaction import Transaction
|
|
from trytond.i18n import gettext
|
|
from trytond.exceptions import UserError
|
|
|
|
__all__ = ['Sale', 'SaleLine',
|
|
'HandleShipmentException', 'HandleInvoiceException', 'ReturnSale']
|
|
|
|
|
|
class Sale(metaclass=PoolMeta):
|
|
__name__ = 'sale.sale'
|
|
|
|
@classmethod
|
|
def _check_product_has_package_required(cls, sales):
|
|
for sale in sales:
|
|
for line in sale.lines:
|
|
if line.type != 'line':
|
|
continue
|
|
if (line.product and line.product_has_packages
|
|
and not line.product_package):
|
|
return False
|
|
return True
|
|
|
|
@classmethod
|
|
def confirm(cls, sales):
|
|
if not cls._check_product_has_package_required(sales):
|
|
raise UserError(gettext(
|
|
'sale_product_package.msg_product_has_package_required'))
|
|
super(Sale, cls).confirm(sales)
|
|
|
|
|
|
class SaleLine(metaclass=PoolMeta):
|
|
__name__ = 'sale.line'
|
|
|
|
product_has_packages = fields.Function(fields.Boolean(
|
|
'Product Has packages'),
|
|
'on_change_with_product_has_packages')
|
|
product_template = fields.Function(fields.Many2One('product.template',
|
|
"Product's template", context={
|
|
'company': Eval('company', -1),
|
|
}, depends=['company']),
|
|
'on_change_with_product_template')
|
|
product_package = fields.Many2One('product.package', 'Package',
|
|
domain=[
|
|
['OR',
|
|
('template', '=', Eval('product_template', 0)),
|
|
('product', '=', Eval('product', 0)),]
|
|
],
|
|
states={
|
|
'invisible': ~Eval('product_has_packages', False),
|
|
'readonly': Eval('sale_state').in_(['cancelled', 'processing', 'done']),
|
|
'required': (Eval('product_has_packages', False)
|
|
& ~Eval('sale_state').in_(['draft', 'quotation', 'cancelled'])),
|
|
},
|
|
depends=['sale_state', 'product_template', 'product_has_packages',
|
|
'product'])
|
|
package_quantity = fields.Integer('Package Quantity',
|
|
states={
|
|
'invisible': ~Eval('product_has_packages', False),
|
|
'readonly': Eval('sale_state').in_(['cancelled', 'processing', 'done']),
|
|
'required': (Eval('product_has_packages', False)
|
|
& ~Eval('sale_state').in_(['draft', 'quotation', 'cancelled'])),
|
|
},
|
|
depends=['sale_state', 'product_has_packages'])
|
|
|
|
@fields.depends('product_package', 'quantity', 'product')
|
|
def pre_validate(self):
|
|
try:
|
|
super(SaleLine, self).pre_validate()
|
|
except AttributeError:
|
|
pass
|
|
if (self.product_package
|
|
and Transaction().context.get('validate_package', True)):
|
|
package_quantity = ((self.quantity or 0.0) /
|
|
self.product_package.quantity)
|
|
if float(int(package_quantity)) != package_quantity:
|
|
raise UserError(gettext(
|
|
'sale_product_package.msg_package_quantity',
|
|
qty=self.quantity,
|
|
product=self.product.rec_name,
|
|
package=self.product_package.rec_name,
|
|
package_qty=self.product_package.quantity))
|
|
|
|
@fields.depends('product', 'product_package')
|
|
def on_change_product(self):
|
|
super(SaleLine, self).on_change_product()
|
|
if not self.product:
|
|
self.product_package = None
|
|
if self.product and not self.product_package:
|
|
# Check if we have a product.package (product.product level)
|
|
for package in self.product.packages:
|
|
if package.is_default:
|
|
self.product_package = package
|
|
break
|
|
if not self.product_package:
|
|
# If we dont have a default value in (product.product) we try
|
|
# to search at template level (product.template)
|
|
for package in self.product.template.packages:
|
|
if package.is_default:
|
|
self.product_package = package
|
|
break
|
|
|
|
@fields.depends('product')
|
|
def on_change_with_product_has_packages(self, name=None):
|
|
if self.product and (self.product.template.packages or
|
|
self.product.packages):
|
|
return True
|
|
return False
|
|
|
|
@fields.depends('product')
|
|
def on_change_with_product_template(self, name=None):
|
|
if self.product:
|
|
return self.product.template.id
|
|
return None
|
|
|
|
@fields.depends('product_package')
|
|
def on_change_product_package(self):
|
|
if not self.product_package:
|
|
self.quantity = None
|
|
self.package_quantity = None
|
|
|
|
@fields.depends('product_package', 'package_quantity', 'quantity', 'unit',
|
|
methods=['on_change_quantity', 'on_change_with_amount',
|
|
'on_change_with_shipping_date',])
|
|
def on_change_package_quantity(self):
|
|
if self.product_package and self.package_quantity and self.unit:
|
|
self.quantity = round((float(self.package_quantity) *
|
|
self.product_package.quantity), self.unit.digits)
|
|
self.on_change_quantity()
|
|
self.amount = self.on_change_with_amount()
|
|
|
|
@fields.depends('product_package', 'quantity')
|
|
def on_change_quantity(self):
|
|
super(SaleLine, self).on_change_quantity()
|
|
if self.product_package and self.quantity:
|
|
self.package_quantity = int(self.quantity /
|
|
self.product_package.quantity)
|
|
|
|
@fields.depends('package_quantity')
|
|
def on_change_with_shipping_date(self, name=None):
|
|
return super().on_change_with_shipping_date(name=name)
|
|
|
|
|
|
class HandleShipmentException(metaclass=PoolMeta):
|
|
__name__ = 'sale.handle.shipment.exception'
|
|
|
|
def transition_handle(self):
|
|
with Transaction().set_context(validate_package=False):
|
|
return super(HandleShipmentException, self).transition_handle()
|
|
|
|
|
|
class HandleInvoiceException(metaclass=PoolMeta):
|
|
__name__ = 'sale.handle.invoice.exception'
|
|
|
|
def transition_handle(self):
|
|
with Transaction().set_context(validate_package=False):
|
|
return super(HandleInvoiceException, self).transition_handle()
|
|
|
|
|
|
class ReturnSale(metaclass=PoolMeta):
|
|
__name__ = 'sale.return_sale'
|
|
|
|
def do_return_(self, action):
|
|
action, data = super().do_return_(action)
|
|
|
|
if data.get('res_id'):
|
|
sales = self.model.browse(data['res_id'])
|
|
|
|
for sale in sales:
|
|
for line in sale.lines:
|
|
if line.type == 'line' and line.package_quantity:
|
|
line.package_quantity *= -1
|
|
sale.lines = sale.lines # Force saving
|
|
self.model.save(sales)
|
|
|
|
return action, data
|