128 lines
4.5 KiB
Python
128 lines
4.5 KiB
Python
# 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 datetime import date, timedelta
|
|
|
|
from trytond.model import fields, ModelSQL, ModelView
|
|
from trytond.pool import Pool, PoolMeta
|
|
from trytond.pyson import Eval
|
|
from trytond.transaction import Transaction
|
|
|
|
STATES = {'invisible': (Eval('type') != 'goods')}
|
|
|
|
TIME_HISTORY = 90 # Days
|
|
|
|
|
|
class Product(metaclass=PoolMeta):
|
|
__name__ = 'product.product'
|
|
|
|
stock_duration = fields.Function(fields.Integer('Stock Duration',
|
|
states=STATES), 'get_stock_duration')
|
|
stock_level = fields.Function(fields.Selection([
|
|
('point_order', 'Point Order'),
|
|
('overstock', 'Overstock'),
|
|
('exhausted', 'Exhausted'),
|
|
('normal', 'Normal'),
|
|
], 'Stock Level', states=STATES), 'get_stock_level')
|
|
avg_cost_price = fields.Function(fields.Numeric("Average Cost Price",
|
|
required=True, digits=(16, 4)), 'get_avg_cost_price')
|
|
amount_cost = fields.Function(fields.Numeric("Amiunt Cost",
|
|
required=True, digits=(16, 4)), 'get_amount_cost')
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(Product, cls).__setup__()
|
|
|
|
def get_amount_cost(self, name=None):
|
|
if self.avg_cost_price and self.quantity:
|
|
return float(self.avg_cost_price) * self.quantity
|
|
return
|
|
|
|
def get_avg_cost_price(self, name=None):
|
|
target_date = date.today()
|
|
stock_date_end = Transaction().context.get('stock_date_end')
|
|
if stock_date_end:
|
|
target_date = stock_date_end
|
|
|
|
AverageCost = Pool().get('product.average_cost')
|
|
avg_product = AverageCost.search([
|
|
('product', '=', self.id),
|
|
('effective_date', '<=', target_date),
|
|
], order=[('effective_date', 'DESC')], limit=1)
|
|
print(' product >>>> ', avg_product)
|
|
if avg_product:
|
|
return avg_product[0].cost_price
|
|
else:
|
|
return self.cost_price
|
|
|
|
def get_stock_duration(self, name):
|
|
res = None
|
|
if Transaction().context.get('stock_date_end'):
|
|
today = Transaction().context.get('stock_date_end')
|
|
else:
|
|
today = date.today()
|
|
start_date = today - timedelta(TIME_HISTORY)
|
|
Move = Pool().get('stock.move')
|
|
domain = [
|
|
('effective_date', '>=', start_date),
|
|
('effective_date', '<=', today),
|
|
('state', '=', 'done'),
|
|
('product', '=', self.id),
|
|
('to_location.type', 'in', ['customer', 'production']),
|
|
]
|
|
if Transaction().context.get('locations'):
|
|
domain.append(('from_location', 'in', Transaction().context.get('locations')))
|
|
|
|
move_history_quantity = 0
|
|
real_historical_time = None
|
|
for move in Move.search(domain, order=[('effective_date', 'ASC')]):
|
|
move_history_quantity += move.quantity
|
|
if not real_historical_time:
|
|
real_historical_time = (today-move.effective_date).days
|
|
if move_history_quantity > 0:
|
|
res = int((real_historical_time * self.quantity) / move_history_quantity)
|
|
return res
|
|
|
|
def get_stock_level(self, name):
|
|
res = 'normal'
|
|
#FIXME
|
|
"""
|
|
if self.max_stock and self.quantity >= self.max_stock:
|
|
res = 'overstock'
|
|
elif self.min_stock and self.quantity <= self.min_stock:
|
|
if self.quantity >= (self.min_stock * 0.5):
|
|
res = 'point_order'
|
|
else:
|
|
res = 'exhausted'
|
|
"""
|
|
return res
|
|
|
|
|
|
class Template(metaclass=PoolMeta):
|
|
__name__ = 'product.template'
|
|
positions = fields.One2Many('product_template.position','template', 'Positions')
|
|
|
|
@classmethod
|
|
def copy(cls, records, default=None):
|
|
if default is None:
|
|
default = {}
|
|
else:
|
|
default = default.copy()
|
|
default.setdefault('positions', None)
|
|
return super(Template, cls).copy(records, default=default)
|
|
|
|
|
|
class AverageCost(ModelSQL, ModelView):
|
|
"Average Cost"
|
|
__name__ = "product.average_cost"
|
|
product = fields.Many2One('product.product', 'Product',
|
|
required=True, domain=[('template.type', '=', 'goods')]
|
|
)
|
|
effective_date = fields.Date('Effective Date', required=True)
|
|
cost_price = fields.Numeric("Cost Price", required=True, digits=(16, 4))
|
|
stock_move = fields.Many2One('stock.move', 'Move')
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(AverageCost, cls).__setup__()
|
|
cls._order.insert(0, ('effective_date', 'DESC'))
|