kalenislims/lims_production/stock.py
2022-01-12 11:25:58 -03:00

381 lines
14 KiB
Python

# -*- coding: utf-8 -*-
# This file is part of lims_production module for Tryton.
# The COPYRIGHT file at the top level of this repository contains
# the full copyright notices and license terms.
from trytond.model import ModelView, ModelSQL, fields
from trytond.wizard import Wizard, StateAction
from trytond.pool import PoolMeta, Pool
from trytond.pyson import PYSONEncoder, Eval, Equal, Bool, Not
from trytond.transaction import Transaction
from trytond.modules.product import price_digits
class Template(metaclass=PoolMeta):
__name__ = 'product.template'
common_name = fields.Char('Common name')
chemical_name = fields.Char('Chemical name')
commercial_name = fields.Char('Commercial name')
cas_number = fields.Char('CAS number')
commercial_brand = fields.Many2One('lims.brand', 'Commercial Brand')
purity_degree = fields.Many2One('lims.purity.degree', 'Purity Degree')
family_equivalent = fields.Many2One('lims.family.equivalent',
'Family/Equivalent',
domain=[('uom.category', '=', Eval('default_uom_category'))],
depends=['default_uom_category'],
help='The UoM\'s Category of Family/Equivalent which you can '
'select here will match the UoM\'s Category of this Product.')
controlled = fields.Boolean('Controlled')
reference_material = fields.Boolean('Reference Material')
certified = fields.Boolean('Certified')
@classmethod
def search_rec_name(cls, name, clause):
Product = Pool().get('product.product')
products = Product.search(['OR',
[('code',) + tuple(clause[1:])],
[('barcode',) + tuple(clause[1:])],
], order=[])
if products:
return [('id', 'in', list(map(int, [product.template.id
for product in products])))]
return super().search_rec_name(name, clause)
class Product(metaclass=PoolMeta):
__name__ = 'product.product'
catalog = fields.Char('Catalog', depends=['active'],
states={'readonly': ~Eval('active', True)})
barcode = fields.Char('Bar Code', depends=['active'],
states={'readonly': ~Eval('active', True)})
common_name = fields.Function(fields.Char('Common name'),
'get_template_field', searcher='search_template_field')
chemical_name = fields.Function(fields.Char('Chemical name'),
'get_template_field', searcher='search_template_field')
commercial_name = fields.Function(fields.Char('Commercial name'),
'get_template_field', searcher='search_template_field')
cas_number = fields.Function(fields.Char('CAS number'),
'get_template_field', searcher='search_template_field')
commercial_brand = fields.Function(fields.Many2One('lims.brand',
'Commercial Brand'), 'get_template_field',
searcher='search_template_field')
purity_degree = fields.Function(fields.Many2One('lims.purity.degree',
'Purity Degree'), 'get_template_field',
searcher='search_template_field')
family_equivalent = fields.Function(fields.Many2One(
'lims.family.equivalent', 'Family/Equivalent'), 'get_template_field',
searcher='search_template_field')
controlled = fields.Function(fields.Boolean('Controlled'),
'get_template_field', searcher='search_template_field')
reference_material = fields.Function(fields.Boolean('Reference Material'),
'get_template_field', searcher='search_template_field')
certified = fields.Function(fields.Boolean('Certified'),
'get_template_field', searcher='search_template_field')
@classmethod
def search_rec_name(cls, name, clause):
res = super().search_rec_name(name, clause)
return ['OR',
res,
[('barcode', ) + tuple(clause[1:])]
]
@classmethod
def get_template_field(cls, products, names):
result = {}
for name in names:
result[name] = {}
if name in ('commercial_brand', 'purity_degree',
'family_equivalent'):
for p in products:
field = getattr(p.template, name, None)
result[name][p.id] = field.id if field else None
else:
for p in products:
result[name][p.id] = getattr(p.template, name, None)
return result
@classmethod
def search_template_field(cls, name, clause):
return [('template.' + name,) + tuple(clause[1:])]
class LotCategory(ModelSQL, ModelView):
"Lot Category"
__name__ = "stock.lot.category"
_rec_name = 'name'
name = fields.Char('Name', required=True)
@classmethod
def __setup__(cls):
super().__setup__()
cls._order.insert(0, ('name', 'ASC'))
class Lot(metaclass=PoolMeta):
__name__ = 'stock.lot'
category = fields.Many2One('stock.lot.category', 'Category')
special_category = fields.Function(fields.Char('Category'),
'on_change_with_special_category')
stability = fields.Char('Stability', depends=['special_category'],
states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'input_prod'))),
})
homogeneity = fields.Char('Homogeneity', depends=['special_category'],
states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'input_prod'))),
})
concentration = fields.Char('Concentration',
depends=['special_category'], states={
'invisible': ~Eval('special_category').in_(
['input_prod', 'domestic_use']),
})
reception_date = fields.Date('Reception date',
depends=['special_category'], states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'input_prod'))),
})
preparation_date = fields.Date('Preparation date',
depends=['special_category'], states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'domestic_use'))),
})
common_name = fields.Function(fields.Char('Common name',
depends=['special_category'], states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'input_prod'))),
}), 'get_common_name')
chemical_name = fields.Function(fields.Char('Chemical name',
depends=['special_category'], states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'input_prod'))),
}), 'get_chemical_name')
commercial_name = fields.Function(fields.Char('Commercial name',
depends=['special_category'], states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'input_prod'))),
}), 'get_commercial_name')
cas_number = fields.Function(fields.Char('CAS number',
depends=['special_category'], states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'input_prod'))),
}), 'get_cas_number', searcher='search_cas_number')
commercial_brand = fields.Function(fields.Many2One('lims.brand',
'Commercial Brand', depends=['special_category'], states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'input_prod'))),
}), 'get_commercial_brand')
catalog = fields.Function(fields.Char('Catalog',
depends=['special_category'], states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'input_prod'))),
}), 'get_catalog')
purity_degree = fields.Function(fields.Many2One('lims.purity.degree',
'Purity Degree', depends=['special_category'], states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'input_prod'))),
}), 'get_purity_degree')
solvent = fields.Many2One('product.product', 'Solvent',
depends=['special_category'], states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'domestic_use'))),
})
technician = fields.Many2One('lims.laboratory.professional', 'Technician',
depends=['special_category'], states={
'invisible': ~Eval('special_category').in_(
['domestic_use', 'prod_sale']),
})
account_category = fields.Function(fields.Many2One('product.category',
'Account Category', depends=['special_category'], states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'input_prod'))),
}), 'get_account_category', searcher='search_account_category')
exclusive_glp = fields.Boolean('Exclusive use GLP',
depends=['special_category'], states={
'invisible': Not(Bool(Equal(Eval('special_category'),
'input_prod')))})
production = fields.Many2One('production', 'Production origin',
readonly=True)
@classmethod
def __setup__(cls):
super().__setup__()
cls.expiration_date.states['invisible'] = False
@staticmethod
def default_exclusive_glp():
return False
@fields.depends('category', 'product', '_parent_product.purchasable',
'_parent_product.salable')
def on_change_with_special_category(self, name=None):
Config = Pool().get('lims.configuration')
if self.category:
config = Config(1)
if self.category == config.lot_category_input_prod:
return 'input_prod'
elif self.category == config.lot_category_prod_sale:
return 'prod_sale'
elif self.category == config.lot_category_prod_domestic_use:
return 'domestic_use'
elif self.product:
if (self.product.purchasable and not self.product.salable):
return 'input_prod'
elif (not self.product.purchasable and self.product.salable):
return 'prod_sale'
elif (not self.product.purchasable and not self.product.salable):
return 'domestic_use'
else:
return ''
def get_common_name(self, name=None):
if self.product:
return self.product.common_name
return ''
def get_chemical_name(self, name=None):
if self.product:
return self.product.chemical_name
return ''
def get_commercial_name(self, name=None):
if self.product:
return self.product.commercial_name
return ''
def get_cas_number(self, name=None):
if self.product:
return self.product.cas_number
return ''
@classmethod
def search_cas_number(cls, name, clause):
return [('product.cas_number',) + tuple(clause[1:])]
def get_commercial_brand(self, name=None):
if self.product and self.product.commercial_brand:
return self.product.commercial_brand.id
return None
def get_catalog(self, name=None):
if self.product:
return self.product.catalog
return ''
def get_purity_degree(self, name=None):
if self.product and self.product.purity_degree:
return self.product.purity_degree.id
return None
def get_account_category(self, name=None):
if self.product:
return self.product.account_category.id
return None
@classmethod
def create(cls, vlist):
pool = Pool()
Product = pool.get('product.product')
Config = pool.get('lims.configuration')
config = Config(1)
vlist = [x.copy() for x in vlist]
for values in vlist:
if not values.get('category'):
product = Product(values['product'])
lot_category_id = None
if (hasattr(product, 'purchasable') and
product.purchasable and not product.salable):
lot_category_id = (config.lot_category_input_prod.id
if config.lot_category_input_prod else None)
elif (not product.purchasable and product.salable):
lot_category_id = (config.lot_category_prod_sale.id
if config.lot_category_prod_sale else None)
elif (not product.purchasable and not product.salable):
lot_category_id = (
config.lot_category_prod_domestic_use.id if
config.lot_category_prod_domestic_use else None)
if lot_category_id:
values['category'] = lot_category_id
return super().create(vlist)
@classmethod
def search_account_category(cls, name, clause):
return [('product.' + name,) + tuple(clause[1:])]
class Move(metaclass=PoolMeta):
__name__ = 'stock.move'
label_quantity = fields.Float("Label Quantity",
digits=(16, Eval('unit_digits', 2)), depends=['unit_digits'])
origin_purchase_unit_price = fields.Numeric('Unit Price',
digits=price_digits)
origin_purchase_currency = fields.Many2One('currency.currency',
'Currency')
@fields.depends('quantity')
def on_change_quantity(self):
if self.quantity:
self.label_quantity = self.quantity
@classmethod
def _get_origin(cls):
models = super()._get_origin()
models.append('production')
return models
class ShipmentIn(metaclass=PoolMeta):
__name__ = 'stock.shipment.in'
@classmethod
def __setup__(cls):
super().__setup__()
cls.inventory_moves.states['readonly'] = Eval('state').in_(
['draft', 'cancel'])
def _get_inventory_move(self, incoming_move):
move = super()._get_inventory_move(incoming_move)
if not move:
return None
if not incoming_move.origin:
return None
move.label_quantity = move.quantity
move.origin_purchase_currency = \
incoming_move.origin.purchase.currency.id
move.origin_purchase_unit_price = incoming_move.origin.unit_price
return move
class MoveProductionRelated(Wizard):
'Related Productions'
__name__ = 'lims.move.production_related'
start = StateAction('lims_production.act_production_related')
def do_start(self, action):
Move = Pool().get('stock.move')
move = Move(Transaction().context['active_id'])
production_id = None
if move.production_input:
production_id = move.production_input.id
elif move.production_output:
production_id = move.production_output.id
action['pyson_domain'] = PYSONEncoder().encode([
('id', '=', production_id),
])
return action, {}