Lot virtual packing update
This commit is contained in:
@@ -1127,6 +1127,15 @@ class CoffeeLineMixin:
|
|||||||
'Package weight', digits=(16, 5))
|
'Package weight', digits=(16, 5))
|
||||||
coffee_packing_weight_unit = fields.Many2One(
|
coffee_packing_weight_unit = fields.Many2One(
|
||||||
'product.uom', 'Package weight unit')
|
'product.uom', 'Package weight unit')
|
||||||
|
coffee_packing_unit = fields.Many2One(
|
||||||
|
'product.uom', 'Package unit',
|
||||||
|
domain=[
|
||||||
|
('category', '=', Eval('coffee_packing_category')),
|
||||||
|
],
|
||||||
|
depends=['coffee_packing_category'])
|
||||||
|
coffee_packing_category = fields.Function(
|
||||||
|
fields.Many2One('product.uom.category', 'Packing Category'),
|
||||||
|
'on_change_with_coffee_packing_category')
|
||||||
coffee_packing_description = fields.Char('Packing description')
|
coffee_packing_description = fields.Char('Packing description')
|
||||||
coffee_market_reference = fields.Many2One(
|
coffee_market_reference = fields.Many2One(
|
||||||
'price.price', 'Market reference')
|
'price.price', 'Market reference')
|
||||||
@@ -1142,6 +1151,13 @@ class CoffeeLineMixin:
|
|||||||
def on_change_with_active_coffee_compatibility(self, name=None):
|
def on_change_with_active_coffee_compatibility(self, name=None):
|
||||||
return self.get_active_coffee_compatibility(name)
|
return self.get_active_coffee_compatibility(name)
|
||||||
|
|
||||||
|
@fields.depends()
|
||||||
|
def on_change_with_coffee_packing_category(self, name=None):
|
||||||
|
UnitCategory = Pool().get('product.uom.category')
|
||||||
|
packing = UnitCategory.search([('name', '=', 'Packing')], limit=1)
|
||||||
|
if packing:
|
||||||
|
return packing[0]
|
||||||
|
|
||||||
def _coffee_attributes_name(self):
|
def _coffee_attributes_name(self):
|
||||||
values = []
|
values = []
|
||||||
for field_name, selection in self._coffee_attribute_name_fields:
|
for field_name, selection in self._coffee_attribute_name_fields:
|
||||||
|
|||||||
@@ -2882,6 +2882,27 @@ class Line(metaclass=PoolMeta):
|
|||||||
def _should_regenerate_valuation(cls, values):
|
def _should_regenerate_valuation(cls, values):
|
||||||
return bool(cls._valuation_regeneration_fields() & set(values))
|
return bool(cls._valuation_regeneration_fields() & set(values))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sync_virtual_lot_packing(cls, line):
|
||||||
|
Lot = Pool().get('lot.lot')
|
||||||
|
if not getattr(line, 'lots', None):
|
||||||
|
line = cls(line.id)
|
||||||
|
virtual_lots = [
|
||||||
|
lot for lot in (line.lots or [])
|
||||||
|
if getattr(lot, 'lot_type', None) == 'virtual']
|
||||||
|
if not virtual_lots:
|
||||||
|
return
|
||||||
|
lot = virtual_lots[0]
|
||||||
|
packing_count = getattr(line, 'coffee_packing_count', None)
|
||||||
|
packing_unit = getattr(line, 'coffee_packing_unit', None)
|
||||||
|
lot_unit_id = getattr(lot.lot_unit, 'id', lot.lot_unit)
|
||||||
|
packing_unit_id = getattr(packing_unit, 'id', packing_unit)
|
||||||
|
if lot.lot_qt == packing_count and lot_unit_id == packing_unit_id:
|
||||||
|
return
|
||||||
|
lot.lot_qt = packing_count
|
||||||
|
lot.lot_unit = packing_unit
|
||||||
|
Lot.save([lot])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def write(cls, *args):
|
def write(cls, *args):
|
||||||
actions = iter(args)
|
actions = iter(args)
|
||||||
@@ -3104,17 +3125,18 @@ class Line(metaclass=PoolMeta):
|
|||||||
if Decimal(str(line.quantity_theorical or 0)) > 0:
|
if Decimal(str(line.quantity_theorical or 0)) > 0:
|
||||||
Lot.save([lot])
|
Lot.save([lot])
|
||||||
#check if fees need to be updated
|
#check if fees need to be updated
|
||||||
if line.fees:
|
if line.fees:
|
||||||
for fee in line.fees:
|
for fee in line.fees:
|
||||||
fl_check = FeeLots.search([('fee','=',fee.id),('lot','=',lot.id),('line','=',line.id)])
|
fl_check = FeeLots.search([('fee','=',fee.id),('lot','=',lot.id),('line','=',line.id)])
|
||||||
if not fl_check:
|
if not fl_check:
|
||||||
fl = FeeLots()
|
fl = FeeLots()
|
||||||
fl.fee = fee.id
|
fl.fee = fee.id
|
||||||
fl.lot = lot.id
|
fl.lot = lot.id
|
||||||
fl.line = line.id
|
fl.line = line.id
|
||||||
FeeLots.save([fl])
|
FeeLots.save([fl])
|
||||||
|
cls._sync_virtual_lot_packing(line)
|
||||||
if line.fee_:
|
|
||||||
|
if line.fee_:
|
||||||
if not line.fee_.purchase:
|
if not line.fee_.purchase:
|
||||||
Fee = Pool().get('fee.fee')
|
Fee = Pool().get('fee.fee')
|
||||||
f = Fee(line.fee_)
|
f = Fee(line.fee_)
|
||||||
|
|||||||
@@ -3002,6 +3002,27 @@ class SaleLine(metaclass=PoolMeta):
|
|||||||
default.setdefault('quantity_theorical', None)
|
default.setdefault('quantity_theorical', None)
|
||||||
default.setdefault('price_pricing', None)
|
default.setdefault('price_pricing', None)
|
||||||
return super().copy(lines, default=default)
|
return super().copy(lines, default=default)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sync_virtual_lot_packing(cls, line):
|
||||||
|
Lot = Pool().get('lot.lot')
|
||||||
|
if not getattr(line, 'lots', None):
|
||||||
|
line = cls(line.id)
|
||||||
|
virtual_lots = [
|
||||||
|
lot for lot in (line.lots or [])
|
||||||
|
if getattr(lot, 'lot_type', None) == 'virtual']
|
||||||
|
if not virtual_lots:
|
||||||
|
return
|
||||||
|
lot = virtual_lots[0]
|
||||||
|
packing_count = getattr(line, 'coffee_packing_count', None)
|
||||||
|
packing_unit = getattr(line, 'coffee_packing_unit', None)
|
||||||
|
lot_unit_id = getattr(lot.lot_unit, 'id', lot.lot_unit)
|
||||||
|
packing_unit_id = getattr(packing_unit, 'id', packing_unit)
|
||||||
|
if lot.lot_qt == packing_count and lot_unit_id == packing_unit_id:
|
||||||
|
return
|
||||||
|
lot.lot_qt = packing_count
|
||||||
|
lot.lot_unit = packing_unit
|
||||||
|
Lot.save([lot])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate(cls, salelines):
|
def validate(cls, salelines):
|
||||||
@@ -3061,6 +3082,7 @@ class SaleLine(metaclass=PoolMeta):
|
|||||||
fl.lot = lot.id
|
fl.lot = lot.id
|
||||||
fl.sale_line = line.id
|
fl.sale_line = line.id
|
||||||
FeeLots.save([fl])
|
FeeLots.save([fl])
|
||||||
|
cls._sync_virtual_lot_packing(line)
|
||||||
|
|
||||||
#generate valuation for purchase and sale
|
#generate valuation for purchase and sale
|
||||||
LotQt = Pool().get('lot.qt')
|
LotQt = Pool().get('lot.qt')
|
||||||
|
|||||||
@@ -210,6 +210,62 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
line.get_coffee_quality_status(), 'approved')
|
line.get_coffee_quality_status(), 'approved')
|
||||||
|
|
||||||
|
def test_purchase_line_syncs_packing_to_virtual_lot(self):
|
||||||
|
'purchase line packing updates the existing virtual lot'
|
||||||
|
package_unit = Mock(id=60)
|
||||||
|
lot = Mock(lot_type='virtual', lot_qt=None, lot_unit=None)
|
||||||
|
line = Mock(
|
||||||
|
lots=[lot],
|
||||||
|
coffee_packing_count=440,
|
||||||
|
coffee_packing_unit=package_unit)
|
||||||
|
lot_model = Mock()
|
||||||
|
pool = Mock()
|
||||||
|
pool.get.return_value = lot_model
|
||||||
|
|
||||||
|
with patch.object(purchase_module, 'Pool', return_value=pool):
|
||||||
|
purchase_module.Line._sync_virtual_lot_packing(line)
|
||||||
|
|
||||||
|
self.assertEqual(lot.lot_qt, 440)
|
||||||
|
self.assertEqual(lot.lot_unit, package_unit)
|
||||||
|
lot_model.save.assert_called_once_with([lot])
|
||||||
|
|
||||||
|
def test_sale_line_syncs_packing_to_virtual_lot(self):
|
||||||
|
'sale line packing updates the existing virtual lot'
|
||||||
|
package_unit = Mock(id=90)
|
||||||
|
old_unit = Mock(id=60)
|
||||||
|
lot = Mock(lot_type='virtual', lot_qt=440, lot_unit=old_unit)
|
||||||
|
line = Mock(
|
||||||
|
lots=[lot],
|
||||||
|
coffee_packing_count=300,
|
||||||
|
coffee_packing_unit=package_unit)
|
||||||
|
lot_model = Mock()
|
||||||
|
pool = Mock()
|
||||||
|
pool.get.return_value = lot_model
|
||||||
|
|
||||||
|
with patch.object(sale_module, 'Pool', return_value=pool):
|
||||||
|
sale_module.SaleLine._sync_virtual_lot_packing(line)
|
||||||
|
|
||||||
|
self.assertEqual(lot.lot_qt, 300)
|
||||||
|
self.assertEqual(lot.lot_unit, package_unit)
|
||||||
|
lot_model.save.assert_called_once_with([lot])
|
||||||
|
|
||||||
|
def test_purchase_line_does_not_resave_aligned_virtual_lot_packing(self):
|
||||||
|
'aligned purchase packing does not resave the virtual lot'
|
||||||
|
package_unit = Mock(id=60)
|
||||||
|
lot = Mock(lot_type='virtual', lot_qt=440, lot_unit=Mock(id=60))
|
||||||
|
line = Mock(
|
||||||
|
lots=[lot],
|
||||||
|
coffee_packing_count=440,
|
||||||
|
coffee_packing_unit=package_unit)
|
||||||
|
lot_model = Mock()
|
||||||
|
pool = Mock()
|
||||||
|
pool.get.return_value = lot_model
|
||||||
|
|
||||||
|
with patch.object(purchase_module, 'Pool', return_value=pool):
|
||||||
|
purchase_module.Line._sync_virtual_lot_packing(line)
|
||||||
|
|
||||||
|
lot_model.save.assert_not_called()
|
||||||
|
|
||||||
def test_itsa_book_year_suffix_uses_april_fiscal_start(self):
|
def test_itsa_book_year_suffix_uses_april_fiscal_start(self):
|
||||||
'ITSA book year changes on April 1st'
|
'ITSA book year changes on April 1st'
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
|||||||
@@ -45,12 +45,11 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
col_widths="min-content,1fr,min-content,1fr">
|
col_widths="min-content,1fr,min-content,1fr">
|
||||||
<label name="coffee_packing_count"/>
|
<label name="coffee_packing_count"/>
|
||||||
<field name="coffee_packing_count" width="120" xexpand="0" xfill="0"/>
|
<field name="coffee_packing_count" width="120" xexpand="0" xfill="0"/>
|
||||||
<label name="coffee_packing_unit_weight"/>
|
<label name="coffee_packing_unit"/>
|
||||||
<field name="coffee_packing_unit_weight" width="120" xexpand="0" xfill="0"/>
|
<field name="coffee_packing_unit"/>
|
||||||
<label name="coffee_packing_weight_unit"/>
|
|
||||||
<field name="coffee_packing_weight_unit"/>
|
|
||||||
<label name="coffee_packing_description"/>
|
<label name="coffee_packing_description"/>
|
||||||
<field name="coffee_packing_description"/>
|
<field name="coffee_packing_description"/>
|
||||||
|
<field name="coffee_packing_category" invisible="1" colspan="4"/>
|
||||||
</group>
|
</group>
|
||||||
<group id="tolerances" string="Tolerances & Inheritance"
|
<group id="tolerances" string="Tolerances & Inheritance"
|
||||||
colspan="1" col="4" panel="card" icon="tryton-switch"
|
colspan="1" col="4" panel="card" icon="tryton-switch"
|
||||||
|
|||||||
@@ -42,12 +42,11 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
col_widths="min-content,1fr,min-content,1fr">
|
col_widths="min-content,1fr,min-content,1fr">
|
||||||
<label name="coffee_packing_count"/>
|
<label name="coffee_packing_count"/>
|
||||||
<field name="coffee_packing_count" width="120" xexpand="0" xfill="0"/>
|
<field name="coffee_packing_count" width="120" xexpand="0" xfill="0"/>
|
||||||
<label name="coffee_packing_unit_weight"/>
|
<label name="coffee_packing_unit"/>
|
||||||
<field name="coffee_packing_unit_weight" width="120" xexpand="0" xfill="0"/>
|
<field name="coffee_packing_unit"/>
|
||||||
<label name="coffee_packing_weight_unit"/>
|
|
||||||
<field name="coffee_packing_weight_unit"/>
|
|
||||||
<label name="coffee_packing_description"/>
|
<label name="coffee_packing_description"/>
|
||||||
<field name="coffee_packing_description"/>
|
<field name="coffee_packing_description"/>
|
||||||
|
<field name="coffee_packing_category" invisible="1" colspan="4"/>
|
||||||
</group>
|
</group>
|
||||||
<group id="tolerances" string="Tolerances & Inheritance"
|
<group id="tolerances" string="Tolerances & Inheritance"
|
||||||
colspan="1" col="4" panel="card" icon="tryton-switch"
|
colspan="1" col="4" panel="card" icon="tryton-switch"
|
||||||
|
|||||||
Reference in New Issue
Block a user