You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

196 lines
6.8 KiB

# -*- coding: utf-8 -*-
import logging
from openerp import models, fields, api
from openerp.exceptions import ValidationError
_logger = logging.getLogger(__name__)
class ComputedPurchaseOrderLine(models.Model):
_description = 'Computed Purchase Order Line'
_name = 'computed.purchase.order.line'
computed_purchase_order_id = fields.Many2one(
'computed.purchase.order',
string='Computed Purchase Order',
)
product_template_id = fields.Many2one(
'product.template',
string='Linked Product Template',
required=True,
help='Product')
name = fields.Char(
string='Product Name',
related='product_template_id.name',
read_only=True)
supplierinfo_id = fields.Many2one(
'product.supplierinfo',
string='Supplier information',
compute='_compute_supplierinfo',
store=True,
readonly=True,
)
category_id = fields.Many2one(
'product.category',
string='Internal Category',
related='product_template_id.categ_id',
read_only=True)
uom_id = fields.Many2one(
'product.uom',
string='Unit of Measure',
read_only=True,
related='product_template_id.uom_id',
help="Default Unit of Measure used for all stock operation.")
qty_available = fields.Float(
string='Stock Quantity',
related='product_template_id.qty_available',
read_only=True,
help='Quantity currently in stock. Does not take '
'into account incoming orders.')
virtual_available = fields.Float(
string='Forecast Quantity',
related='product_template_id.virtual_available',
read_only=True,
help='Virtual quantity taking into account current stock, incoming '
'orders and outgoing sales.')
average_consumption = fields.Float(
string='Average Consumption',
related='product_template_id.average_consumption',
read_only=True)
stock_coverage = fields.Float(
string='Stock Coverage',
related='product_template_id.estimated_stock_coverage',
read_only=True,
)
minimum_purchase_qty = fields.Float(
string='Minimum Purchase Quantity',
compute='_depends_on_product_template',
)
purchase_quantity = fields.Float(
string='Purchase Quantity',
required=True,
default=0.)
uom_po_id = fields.Many2one(
'product.uom',
string='Purchase Unit of Measure',
read_only=True,
related='product_template_id.uom_po_id',
help="Default Unit of Measure used for all stock operation.")
product_price = fields.Float(
string='Product Price (w/o VAT)',
compute='_depends_on_product_template',
read_only=True,
help='Supplier Product Price by buying unit. Price is without VAT')
virtual_coverage = fields.Float(
string='Expected Stock Coverage',
compute='_depends_on_purchase_quantity',
help='Expected stock coverage (in days) based on current stocks and average daily consumption') # noqa
subtotal = fields.Float(
string='Subtotal (w/o VAT)',
compute='_depends_on_purchase_quantity')
@api.multi
@api.depends('product_template_id')
def _depends_on_product_template(self):
for cpol in self:
# get supplier info
cpol.minimum_purchase_qty = cpol.supplierinfo_id.min_qty
cpol.product_price = cpol.supplierinfo_id.price
@api.multi
@api.onchange('product_template_id')
def _onchange_purchase_quantity(self):
for cpol in self:
cpol.purchase_quantity = cpol.supplierinfo_id.min_qty
@api.depends('purchase_quantity')
@api.multi
def _depends_on_purchase_quantity(self):
for cpol in self:
cpol.subtotal = cpol.product_price * cpol.purchase_quantity
avg = cpol.average_consumption
if avg > 0:
qty = ((cpol.virtual_available / cpol.uom_id.factor)
+ (cpol.purchase_quantity / cpol.uom_po_id.factor))
cpol.virtual_coverage = qty / avg
else:
# todo what would be a good default value? (not float(inf))
cpol.virtual_coverage = 9999
return True
@api.multi
@api.depends('product_template_id')
@api.onchange('product_template_id')
def _compute_supplierinfo(self):
for cpol in self:
if not cpol.product_template_id:
cpol.supplierinfo_id = False
else:
SupplierInfo = self.env['product.supplierinfo']
si = SupplierInfo.search([
('product_tmpl_id', '=', cpol.product_template_id.id),
('name', '=', cpol.product_template_id.main_supplier_id.id) # noqa
])
if len(si) == 0:
raise ValidationError(
u'No supplier information set for {name}'
.format(name=cpol.product_template_id.name))
elif len(si) == 1:
cpol.supplierinfo_id = si
else:
_logger.warning(
u'product {name} has several suppliers, chose last'
.format(name=cpol.product_template_id.name)
)
si = si.sorted(key=lambda r: r.create_date, reverse=True)
cpol.supplierinfo_id = si[0]
@api.constrains('purchase_quantity')
def _check_minimum_purchase_quantity(self):
for cpol in self:
if cpol.purchase_quantity < 0:
raise ValidationError(u'Purchase quantity for {product_name} must be greater than 0' # noqa
.format(product_name=cpol.product_template_id.name))
elif 0 < cpol.purchase_quantity < cpol.minimum_purchase_qty:
raise ValidationError(u'Purchase quantity for {product_name} must be greater than {min_qty}' # noqa
.format(product_name=cpol.product_template_id.name,
min_qty=cpol.minimum_purchase_qty))
@api.multi
def get_default_product_product(self):
self.ensure_one()
ProductProduct = self.env['product.product']
products = ProductProduct.search([
('product_tmpl_id', '=', self.product_template_id.id)
])
products = products.sorted(
key=lambda product: product.create_date,
reverse=True
)
if products:
return products[0]
else:
raise ValidationError(
u'%s:%s template has no variant set'
% (self.product_template_id.id, self.product_template_id.name)
)