add country to sla cost
This commit is contained in:
@@ -166,6 +166,16 @@ de negoce physique:
|
||||
virtuel, puis uniquement les physiques.
|
||||
- detail durable:
|
||||
`modules/purchase_trade/docs/business-rules.md` BR-PT-020 / BR-PT-021.
|
||||
- En execution controller / SLA:
|
||||
- les objectifs de repartition controller utilisent `party.execution.area`
|
||||
(`country.region`).
|
||||
- les couts SLA utilisent `party.execution.place` et peuvent matcher par
|
||||
`country`, par `location`, ou par couple `country + location`.
|
||||
- la creation du fee controller depuis shipment part de
|
||||
`shipment.to_location`; le pays de matching est
|
||||
`shipment.to_location.country`.
|
||||
- priorite cout SLA: couple pays+location, puis location seule, puis pays
|
||||
seul.
|
||||
|
||||
## 5) Conventions de modification
|
||||
|
||||
|
||||
@@ -346,6 +346,34 @@ Owner technique: `a completer`
|
||||
- Priorite:
|
||||
- `importante`
|
||||
|
||||
### BR-PT-014-bis - Les couts SLA controller peuvent cibler pays et/ou lieu
|
||||
|
||||
- Intent: permettre de definir le cout d'un controller soit pour un pays, soit
|
||||
pour une location, soit pour un couple pays + location.
|
||||
- Description:
|
||||
- Dans l'onglet `Execution` de `party.party`, les lignes SLA
|
||||
(`party.execution.place`) peuvent porter:
|
||||
- `country`
|
||||
- `location`
|
||||
- ou les deux.
|
||||
- Lors de la creation automatique du fee controller sur un
|
||||
`stock.shipment.in`, le systeme continue de partir de
|
||||
`shipment.to_location`.
|
||||
- Le pays utilise pour le matching est `shipment.to_location.country`.
|
||||
- Priorite de matching:
|
||||
- couple `country + location`
|
||||
- puis `location` seule
|
||||
- puis `country` seul
|
||||
- Resultat attendu:
|
||||
- un cout defini uniquement sur un pays s'applique a toutes les destinations
|
||||
de ce pays.
|
||||
- un cout defini uniquement sur une location s'applique a cette destination,
|
||||
quel que soit le pays porte par la location.
|
||||
- un cout defini sur le couple pays + location est le plus specifique et
|
||||
prime les deux autres.
|
||||
- Priorite:
|
||||
- `importante`
|
||||
|
||||
### BR-PT-015 - Les weight reports distants par lot partent du weight report global attache au shipment
|
||||
|
||||
- Intent: separer la creation du `weight.report` global et l'export detaille
|
||||
|
||||
@@ -87,13 +87,14 @@ class PartyExecutionSla(ModelSQL,ModelView):
|
||||
date_to = fields.Date("To")
|
||||
places = fields.One2Many('party.execution.place','pes',"")
|
||||
|
||||
class PartyExecutionPlace(ModelSQL,ModelView):
|
||||
"Party Sla Place"
|
||||
__name__ = 'party.execution.place'
|
||||
|
||||
pes = fields.Many2One('party.execution.sla',"Sla")
|
||||
location = fields.Many2One('stock.location',"Location")
|
||||
cost = fields.Numeric("Cost",digits=(16,4))
|
||||
class PartyExecutionPlace(ModelSQL,ModelView):
|
||||
"Party Sla Place"
|
||||
__name__ = 'party.execution.place'
|
||||
|
||||
pes = fields.Many2One('party.execution.sla',"Sla")
|
||||
country = fields.Many2One('country.country',"Country")
|
||||
location = fields.Many2One('stock.location',"Location")
|
||||
cost = fields.Numeric("Cost",digits=(16,4))
|
||||
mode = fields.Selection([
|
||||
('lumpsum', 'Lump sum'),
|
||||
('perqt', 'Per qt'),
|
||||
@@ -139,11 +140,38 @@ class Party(metaclass=PoolMeta):
|
||||
best_rule = execution
|
||||
return best_gap, best_rule
|
||||
|
||||
def get_sla_cost(self,location):
|
||||
def get_sla_cost(self, location):
|
||||
if self.sla:
|
||||
country = getattr(location, 'country', None)
|
||||
for sla in self.sla:
|
||||
SlaPlace = Pool().get('party.execution.place')
|
||||
sp = SlaPlace.search([('pes','=', sla.id),('location','=',location)])
|
||||
domain = [
|
||||
('pes', '=', sla.id),
|
||||
[
|
||||
'OR',
|
||||
('location', '=', location),
|
||||
('location', '=', None),
|
||||
],
|
||||
]
|
||||
if country:
|
||||
domain.append([
|
||||
'OR',
|
||||
('country', '=', country),
|
||||
('country', '=', None),
|
||||
])
|
||||
else:
|
||||
domain.append(('country', '=', None))
|
||||
sp = SlaPlace.search(domain)
|
||||
sp = [
|
||||
place for place in sp
|
||||
if place.location or place.country
|
||||
]
|
||||
sp.sort(
|
||||
key=lambda place: (
|
||||
0 if place.location and place.country else
|
||||
1 if place.location else
|
||||
2 if place.country else
|
||||
3))
|
||||
if sp:
|
||||
return sp[0].cost,sp[0].mode,sp[0].currency,sp[0].unit
|
||||
return None, None, None, None
|
||||
|
||||
@@ -662,6 +662,79 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
party.get_sla_cost(Mock()),
|
||||
(None, None, None, None))
|
||||
|
||||
def test_get_sla_cost_matches_country_without_location(self):
|
||||
'controller sla helper can match a destination country'
|
||||
Party = Pool().get('party.party')
|
||||
party = Party()
|
||||
sla = Mock(id=1)
|
||||
party.sla = [sla]
|
||||
country = Mock(id=10)
|
||||
location = Mock(country=country)
|
||||
country_place = Mock(
|
||||
country=country,
|
||||
location=None,
|
||||
cost=Decimal('12'),
|
||||
mode='ppack',
|
||||
currency=Mock(id=1),
|
||||
unit=Mock(id=2),
|
||||
)
|
||||
place_model = Mock()
|
||||
place_model.search.return_value = [country_place]
|
||||
|
||||
with patch('trytond.modules.purchase_trade.party.Pool') as PoolMock:
|
||||
PoolMock.return_value.get.return_value = place_model
|
||||
|
||||
self.assertEqual(
|
||||
party.get_sla_cost(location),
|
||||
(
|
||||
country_place.cost,
|
||||
country_place.mode,
|
||||
country_place.currency,
|
||||
country_place.unit,
|
||||
))
|
||||
|
||||
def test_get_sla_cost_prioritizes_country_location_pair(self):
|
||||
'controller sla helper prefers country and location over either alone'
|
||||
Party = Pool().get('party.party')
|
||||
party = Party()
|
||||
sla = Mock(id=1)
|
||||
party.sla = [sla]
|
||||
country = Mock(id=10)
|
||||
location = Mock(country=country)
|
||||
country_only = Mock(
|
||||
country=country,
|
||||
location=None,
|
||||
cost=Decimal('12'),
|
||||
mode='ppack',
|
||||
currency=Mock(id=1),
|
||||
unit=Mock(id=2),
|
||||
)
|
||||
location_only = Mock(
|
||||
country=None,
|
||||
location=location,
|
||||
cost=Decimal('14'),
|
||||
mode='perqt',
|
||||
currency=Mock(id=3),
|
||||
unit=Mock(id=4),
|
||||
)
|
||||
pair = Mock(
|
||||
country=country,
|
||||
location=location,
|
||||
cost=Decimal('16'),
|
||||
mode='rate',
|
||||
currency=Mock(id=5),
|
||||
unit=Mock(id=6),
|
||||
)
|
||||
place_model = Mock()
|
||||
place_model.search.return_value = [country_only, location_only, pair]
|
||||
|
||||
with patch('trytond.modules.purchase_trade.party.Pool') as PoolMock:
|
||||
PoolMock.return_value.get.return_value = place_model
|
||||
|
||||
self.assertEqual(
|
||||
party.get_sla_cost(location),
|
||||
(pair.cost, pair.mode, pair.currency, pair.unit))
|
||||
|
||||
def test_get_party_by_name_adds_missing_category_to_existing_party(self):
|
||||
'existing parties found by automation gain the requested category when missing'
|
||||
Party = Pool().get('party.party')
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<tree editable="1">
|
||||
<field name="country"/>
|
||||
<field name="location"/>
|
||||
<field name="mode"/>
|
||||
<field name="cost"/>
|
||||
<field name="currency"/>
|
||||
<field name="unit"/>
|
||||
</tree>
|
||||
</tree>
|
||||
|
||||
Reference in New Issue
Block a user