Delete dependency with field cost_lines from stock_lot_cost module. (#3)
Task #068419
This commit is contained in:
parent
a3300f6297
commit
bca59513ed
|
@ -6,13 +6,6 @@ from . import production
|
|||
def register():
|
||||
Pool.register(
|
||||
production.BOM,
|
||||
production.Lot,
|
||||
production.Production,
|
||||
production.StockMove,
|
||||
module='production_lot_cost', type_='model')
|
||||
Pool.register(
|
||||
production.LotCostLine,
|
||||
production.Operation,
|
||||
depends=['production_operation'],
|
||||
module='production_lot_cost', type_='model')
|
||||
|
||||
|
|
229
production.py
229
production.py
|
@ -2,13 +2,7 @@
|
|||
# copyright notices and license terms.
|
||||
from decimal import Decimal
|
||||
from trytond.model import fields
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.exceptions import UserError
|
||||
from trytond.i18n import gettext
|
||||
from trytond.modules.product import price_digits, round_price
|
||||
|
||||
__all__ = ['BOM', 'Lot', 'Production', 'StockMove', 'LotCostLine', 'Operation']
|
||||
from trytond.pool import PoolMeta
|
||||
|
||||
|
||||
class BOM(metaclass=PoolMeta):
|
||||
|
@ -18,22 +12,6 @@ class BOM(metaclass=PoolMeta):
|
|||
help='Infrastructure cost per lot unit')
|
||||
|
||||
|
||||
class Lot(metaclass=PoolMeta):
|
||||
__name__ = 'stock.lot'
|
||||
|
||||
def _on_change_product_cost_lines(self):
|
||||
pool = Pool()
|
||||
Move = pool.get('stock.move')
|
||||
|
||||
context = Transaction().context
|
||||
if context.get('from_move'):
|
||||
move = Move(context['from_move'])
|
||||
if getattr(move, 'production_output', False):
|
||||
return {}
|
||||
|
||||
return super(Lot, self)._on_change_product_cost_lines()
|
||||
|
||||
|
||||
class Production(metaclass=PoolMeta):
|
||||
__name__ = 'production'
|
||||
|
||||
|
@ -66,208 +44,3 @@ class Production(metaclass=PoolMeta):
|
|||
cost += (Decimal(str(output.internal_quantity)) *
|
||||
self.infrastructure_cost)
|
||||
return cost
|
||||
|
||||
#def explode_bom(self):
|
||||
#super(Production, self).explode_bom()
|
||||
#outputs = self.outputs
|
||||
#for move in outputs:
|
||||
#if self.infrastructure_cost and move.product == self.product:
|
||||
#move.unit_price += self.infrastructure_cost
|
||||
|
||||
@classmethod
|
||||
def set_cost(cls, productions):
|
||||
pool = Pool()
|
||||
Lot = pool.get('stock.lot')
|
||||
CostLot = pool.get('stock.lot.cost_line')
|
||||
try:
|
||||
Operation = pool.get('production.operation')
|
||||
except:
|
||||
pass
|
||||
|
||||
super(Production, cls).set_cost(productions)
|
||||
|
||||
to_save = []
|
||||
to_check = []
|
||||
for production in productions:
|
||||
output_quantity = sum([x.internal_quantity for x in
|
||||
production.outputs if x.product == production.product])
|
||||
|
||||
if hasattr(production, 'operations') and hasattr(cls, 'lot'):
|
||||
ops = []
|
||||
for output in production.outputs:
|
||||
ops += [x for x in production.operations if
|
||||
output.lot and x.lot == output.lot]
|
||||
|
||||
for output in production.outputs:
|
||||
cost_lines = []
|
||||
if not output.lot:
|
||||
continue
|
||||
if not output.lot.cost_lines:
|
||||
cost_lines = output._get_production_output_lot_cost_lines()
|
||||
if hasattr(production, 'operations') and hasattr(cls, 'lot'):
|
||||
operations = [x for x in production.operations if
|
||||
output.lot and x.lot == output.lot]
|
||||
cost_lines += Operation._get_operation_lot_cost_line(
|
||||
operations, output.internal_quantity, output)
|
||||
operations = [x for x in production.operations if
|
||||
(x.lot is None or x not in ops)]
|
||||
cost_lines += Operation._get_operation_lot_cost_line(
|
||||
operations, output_quantity, output)
|
||||
to_save += cost_lines
|
||||
to_check.append((output, output.lot))
|
||||
|
||||
if to_save:
|
||||
CostLot.save(to_save)
|
||||
if to_check:
|
||||
for move, lot in to_check:
|
||||
move.check_lot_cost(lot)
|
||||
|
||||
class LotCostLine(metaclass=PoolMeta):
|
||||
__name__ = 'stock.lot.cost_line'
|
||||
|
||||
@classmethod
|
||||
def _get_origin(cls):
|
||||
return super()._get_origin() + ['production.operation',]
|
||||
|
||||
|
||||
class Operation(metaclass=PoolMeta):
|
||||
__name__ = 'production.operation'
|
||||
|
||||
@classmethod
|
||||
def _get_operation_lot_cost_line(cls, operations, quantity, move):
|
||||
pool = Pool()
|
||||
Category = pool.get('stock.lot.cost_category')
|
||||
LotCostLine = pool.get('stock.lot.cost_line')
|
||||
|
||||
categories = dict((x.name, x) for x in Category.search([]))
|
||||
|
||||
vals = {}
|
||||
for operation in operations:
|
||||
cat = operation.operation_type.name
|
||||
if cat not in categories:
|
||||
category = Category(name=cat)
|
||||
category.save()
|
||||
categories[cat] = category
|
||||
else:
|
||||
category = categories[cat]
|
||||
if category not in vals:
|
||||
vals[category] = 0
|
||||
|
||||
vals[category] += operation.cost
|
||||
|
||||
cost_lines = []
|
||||
for category, cost in vals.items():
|
||||
cost_line = LotCostLine(
|
||||
category=category.id,
|
||||
lot = move.lot,
|
||||
unit_price=Decimal(float(cost)/quantity if quantity else 0),
|
||||
origin=str(move),
|
||||
)
|
||||
cost_lines += [cost_line]
|
||||
return cost_lines
|
||||
|
||||
|
||||
class StockMove(metaclass=PoolMeta):
|
||||
__name__ = 'stock.move'
|
||||
|
||||
def check_lot_cost(self, lot):
|
||||
'''
|
||||
If production output quantity is changed manually, it cannot be
|
||||
computed the lot cost, so lot must be created manually.
|
||||
'''
|
||||
production = self.production_output
|
||||
|
||||
if self.uom != production.uom:
|
||||
unit_price = self.uom.compute_price(self.uom, self.unit_price,
|
||||
production.uom)
|
||||
else:
|
||||
unit_price = self.unit_price
|
||||
|
||||
cost_price = round_price(lot.cost_price)
|
||||
unit_price = round_price(unit_price)
|
||||
|
||||
if unit_price != cost_price:
|
||||
raise UserError(gettext('production_lot_cost.msg_uneven_costs',
|
||||
move=self.rec_name,
|
||||
move_unit_price=self.unit_price,
|
||||
lot=self.lot,
|
||||
lot_unit_price=lot.cost_price,
|
||||
))
|
||||
|
||||
def get_production_output_lot(self):
|
||||
lot = super(StockMove, self).get_production_output_lot()
|
||||
if lot:
|
||||
cost_lines = self._get_production_output_lot_cost_lines()
|
||||
if cost_lines and not getattr(lot, 'cost_lines', False):
|
||||
lot.cost_lines = cost_lines
|
||||
return lot
|
||||
|
||||
def _get_production_output_lot_cost_lines(self):
|
||||
'''
|
||||
Return a list of unpersistent stock.lot.cost_line instances to be
|
||||
writen in cost_lines field of output_move's lot (the returned lines
|
||||
doesn't have the lot's field)
|
||||
'''
|
||||
pool = Pool()
|
||||
ModelData = pool.get('ir.model.data')
|
||||
|
||||
inputs_category_id = ModelData.get_id('production_lot_cost',
|
||||
'cost_category_inputs_cost')
|
||||
infrastructure_category_id = ModelData.get_id('production_lot_cost',
|
||||
'cost_category_infrastructure_cost')
|
||||
|
||||
# Unit price of cost_line should not include infrastructure_cost but
|
||||
# as production.cost computed method is overriden and it includes this
|
||||
# cost, here we must compute the original production cost again
|
||||
production = self.production_output
|
||||
cost = Decimal(0)
|
||||
for input_ in production.inputs:
|
||||
if input_.lot and input_.lot.cost_price:
|
||||
cost_price = input_.lot.cost_price
|
||||
elif input_.cost_price is not None:
|
||||
cost_price = input_.cost_price
|
||||
else:
|
||||
cost_price = input_.product.cost_price
|
||||
cost += (Decimal(str(input_.internal_quantity)) * cost_price)
|
||||
|
||||
factor = 1
|
||||
res = []
|
||||
if production.bom:
|
||||
factor = production.bom.compute_factor(production.product,
|
||||
production.quantity or 0, production.uom)
|
||||
for output in production.bom and production.bom.outputs or []:
|
||||
quantity = output.compute_quantity(factor)
|
||||
if output.product == self.product and quantity:
|
||||
res.append(
|
||||
self._get_production_output_lot_cost_line(
|
||||
inputs_category_id,
|
||||
Decimal(cost / Decimal(str(quantity))), self.lot)
|
||||
)
|
||||
|
||||
elif (self.product == production.product and self.quantity):
|
||||
quantity = production.output_qty
|
||||
if quantity:
|
||||
res.append(
|
||||
self._get_production_output_lot_cost_line(
|
||||
inputs_category_id,
|
||||
Decimal(cost / Decimal(str(quantity))), self.lot)
|
||||
)
|
||||
|
||||
if (self.product == production.product and
|
||||
production.infrastructure_cost):
|
||||
infrastructure_cost = self._get_production_output_lot_cost_line(
|
||||
infrastructure_category_id, production.infrastructure_cost,
|
||||
self.lot)
|
||||
res.append(infrastructure_cost)
|
||||
|
||||
return res
|
||||
|
||||
def _get_production_output_lot_cost_line(self, category_id, cost, lot):
|
||||
pool = Pool()
|
||||
LotCostLine = pool.get('stock.lot.cost_line')
|
||||
return LotCostLine(
|
||||
category=category_id,
|
||||
unit_price=cost,
|
||||
origin=str(self),
|
||||
lot=lot,
|
||||
)
|
||||
|
|
|
@ -211,8 +211,6 @@ Make a production with infrastructure cost::
|
|||
>>> output, = production.outputs
|
||||
>>> output.state
|
||||
'done'
|
||||
>>> len(output.lot.cost_lines)
|
||||
2
|
||||
>>> production.cost == Decimal('27')
|
||||
True
|
||||
>>> output, = production.outputs
|
||||
|
|
|
@ -183,8 +183,6 @@ production is Running::
|
|||
>>> output, = production.outputs
|
||||
>>> output.state
|
||||
'done'
|
||||
>>> len(output.lot.cost_lines)
|
||||
2
|
||||
>>> production.cost == Decimal('27')
|
||||
True
|
||||
>>> output.unit_price
|
||||
|
@ -231,7 +229,5 @@ production is done::
|
|||
True
|
||||
>>> output.unit_price
|
||||
Decimal('13.5000')
|
||||
>>> len(output.lot.cost_lines)
|
||||
2
|
||||
>>> output.lot.cost_price == Decimal('13.5')
|
||||
True
|
||||
|
|
|
@ -5,7 +5,6 @@ depends:
|
|||
stock_lot_cost
|
||||
extras_depend:
|
||||
production_output_lot
|
||||
production_operation
|
||||
xml:
|
||||
production.xml
|
||||
message.xml
|
||||
|
|
Loading…
Reference in New Issue