trytonpsk-stock_co/product.py

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'))