02.04.26
This commit is contained in:
@@ -79,15 +79,27 @@ de negoce physique:
|
||||
- `mtm_price` doit afficher le prix brut de valorisation (sans ratio), alors
|
||||
que `mtm` reste le montant calcule selon la logique de strategie
|
||||
- En pricing:
|
||||
- le `premium` doit impacter le prix total et donc le `amount`, aussi bien
|
||||
en `priced` qu'en `basis`
|
||||
- le `unit_price` doit rester un prix de base, hors `premium`
|
||||
- le `premium` doit impacter le prix total economique et donc le `amount`,
|
||||
aussi bien en `priced` qu'en `basis`
|
||||
- si `linked currency` est active, le `premium` est saisi dans la devise /
|
||||
unite liee (ex: `USC/LB`) puis converti vers le `unit_price` de la ligne
|
||||
unite liee (ex: `USC/LB`) puis converti vers le repere de la ligne pour le
|
||||
calcul du `amount`
|
||||
- en `basis + linked currency`, le `linked_price` doit representer le prix
|
||||
basis brut (hors premium) dans la devise liee; le `unit_price` final
|
||||
ajoute ensuite le premium converti
|
||||
basis brut (hors premium) dans la devise liee; le `unit_price` reste ce
|
||||
prix brut converti, et le `premium` converti est ajoute seulement dans
|
||||
l'`amount`
|
||||
- si `linked currency` est cochee, `linked_price`, `linked_currency` et
|
||||
`linked_unit` sont requis
|
||||
- dans les forms, presenter le bloc prix dans l'ordre:
|
||||
`price_type` -> linked fields -> `premium` -> `unit_price` -> `amount`
|
||||
- en valuation `basis`, le premium s'applique a chaque composant, pas
|
||||
uniquement a une ligne de resume
|
||||
- pour une ligne `basis` sans `price_summary`, la valuation fallback doit
|
||||
utiliser `unit_price + premium` (et pas `unit_price` seul)
|
||||
- a la validation d'une `sale.line`, si un lot virtuel est cree et qu'aucun
|
||||
matching purchase n'existe, il faut lancer `generate_from_sale_line()` pour
|
||||
alimenter le PnL sale-first
|
||||
|
||||
## 5) Conventions de modification
|
||||
|
||||
|
||||
@@ -199,12 +199,12 @@ Owner technique: `a completer`
|
||||
- Le `premium` d'une `purchase.line` ou `sale.line` doit impacter le prix
|
||||
total quelle que soit la `price_type`.
|
||||
- Cette regle vaut pour:
|
||||
- le `unit_price`
|
||||
- les calculs de `amount`
|
||||
- la valuation / PnL
|
||||
- Resultat attendu:
|
||||
- en `priced`, le prix total = prix de base + premium
|
||||
- en `basis`, le premium s'ajoute aussi au prix total
|
||||
- le `unit_price` reste le prix de base, hors premium
|
||||
- en `priced`, le montant economique = `unit_price + premium`
|
||||
- en `basis`, le premium s'ajoute aussi au prix total economique
|
||||
- en valuation `basis`, le premium s'applique a chaque composant valorise
|
||||
(ex: meme premium repete sur chaque bloc ICE)
|
||||
- Exemple metier:
|
||||
@@ -221,13 +221,14 @@ Owner technique: `a completer`
|
||||
- Description:
|
||||
- Quand `enable_linked_currency` est coche, le `premium` est saisi dans la
|
||||
devise / unite liee, pas dans la devise / unite native de la ligne.
|
||||
- Le systeme doit convertir ce premium vers le `unit_price` de la ligne pour
|
||||
les calculs internes.
|
||||
- Le systeme doit convertir ce premium vers le repere de la ligne pour les
|
||||
calculs internes de montant et de valuation.
|
||||
- Resultat attendu:
|
||||
- `premium` est interprete dans le repere `linked_currency` / `linked_unit`
|
||||
- le `unit_price` converti integre ce premium
|
||||
- les `amount` et valuations bases sur `unit_price` reflectent donc ce
|
||||
premium converti
|
||||
- le `unit_price` ne doit pas absorber ce premium
|
||||
- les `amount` et valuations doivent refleter ce premium converti
|
||||
- si `linked currency` est cochee, `linked_price`, `linked_currency` et
|
||||
`linked_unit` sont obligatoires
|
||||
- Priorite:
|
||||
- `structurante`
|
||||
|
||||
@@ -238,12 +239,47 @@ Owner technique: `a completer`
|
||||
- Quand une ligne est en `basis` et `linked currency`, le bloc
|
||||
`linked_price` doit etre recalcule automatiquement.
|
||||
- Ce `linked_price` doit representer le prix basis brut, hors premium.
|
||||
- Le `unit_price` final de la ligne est ensuite obtenu en ajoutant le premium
|
||||
converti.
|
||||
- Le `unit_price` de la ligne doit rester ce prix brut converti.
|
||||
- Le premium converti n'est ajoute qu'au niveau du `amount`.
|
||||
- Resultat attendu:
|
||||
- modification du basis -> mise a jour automatique du `linked_price`
|
||||
- `linked_price` = base market / basis
|
||||
- `unit_price` = `linked_price` converti + premium converti
|
||||
- `unit_price` = `linked_price` converti
|
||||
- `amount` = quantite * (`unit_price` + premium converti)
|
||||
- Priorite:
|
||||
- `importante`
|
||||
|
||||
### BR-PT-011 - Une sale line non matchee avec lot virtuel doit generer une valuation sale-first des la validation
|
||||
|
||||
- Intent: ne pas attendre un matching purchase pour afficher le PnL d'une sale
|
||||
ouverte.
|
||||
- Description:
|
||||
- Lors de la validation d'une `sale.line`, le systeme peut creer un lot
|
||||
`virtual`.
|
||||
- Si aucun `lot.qt` ne relie ce lot a une `purchase.line`, il faut tout de
|
||||
meme generer la valuation cote sale.
|
||||
- Resultat attendu:
|
||||
- apres creation du lot virtuel, si aucun matching purchase n'existe:
|
||||
- appeler `Valuation.generate_from_sale_line(line)`
|
||||
- creer au moins la ligne `sale priced` fallback si la ligne porte un prix
|
||||
economique via le premium
|
||||
- Priorite:
|
||||
- `importante`
|
||||
|
||||
### BR-PT-012 - Fallback valuation basis sans summary: utiliser le prix economique de la ligne
|
||||
|
||||
- Intent: eviter qu'une valuation `basis` ouverte sorte a zero alors que la
|
||||
ligne a bien une valeur economique via le premium.
|
||||
- Description:
|
||||
- Une ligne `basis` peut ne pas avoir encore de `price_summary`.
|
||||
- Dans ce cas, la valuation fallback ne doit pas prendre `unit_price` seul si
|
||||
celui-ci est brut et hors premium.
|
||||
- Resultat attendu:
|
||||
- le fallback valuation `basis` doit utiliser:
|
||||
- `unit_price + premium converti`
|
||||
- cette regle vaut au minimum pour:
|
||||
- `sale.line` non matchee
|
||||
- `purchase.line` sans summary
|
||||
- Priorite:
|
||||
- `importante`
|
||||
|
||||
|
||||
@@ -239,6 +239,7 @@ Source code: `modules/purchase_trade/invoice.py`
|
||||
Source code: `modules/purchase_trade/sale.py`
|
||||
|
||||
- `report_terms`
|
||||
- `report_crop_name`
|
||||
- `report_gross`
|
||||
- `report_net`
|
||||
- `report_qt`
|
||||
|
||||
@@ -352,19 +352,25 @@ class Sale(metaclass=PoolMeta):
|
||||
return ''
|
||||
|
||||
@property
|
||||
def report_nb_bale(self):
|
||||
text_bale = 'NB BALES: '
|
||||
nb_bale = 0
|
||||
if self.lines:
|
||||
for line in self.lines:
|
||||
if line.lots:
|
||||
nb_bale += sum([l.lot_qt for l in line.lots if l.lot_type == 'physic'])
|
||||
return text_bale + str(int(nb_bale))
|
||||
|
||||
@property
|
||||
def report_deal(self):
|
||||
if self.lines and self.lines[0].lots and len(self.lines[0].lots)>1:
|
||||
return self.lines[0].lots[1].line.purchase.number + ' ' + self.number
|
||||
def report_nb_bale(self):
|
||||
text_bale = 'NB BALES: '
|
||||
nb_bale = 0
|
||||
if self.lines:
|
||||
for line in self.lines:
|
||||
if line.lots:
|
||||
nb_bale += sum([l.lot_qt for l in line.lots if l.lot_type == 'physic'])
|
||||
return text_bale + str(int(nb_bale))
|
||||
|
||||
@property
|
||||
def report_crop_name(self):
|
||||
if self.crop:
|
||||
return self.crop.name or ''
|
||||
return ''
|
||||
|
||||
@property
|
||||
def report_deal(self):
|
||||
if self.lines and self.lines[0].lots and len(self.lines[0].lots)>1:
|
||||
return self.lines[0].lots[1].line.purchase.number + ' ' + self.number
|
||||
else:
|
||||
''
|
||||
|
||||
|
||||
@@ -142,5 +142,17 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
{'type': 'derivative', 'amount': Decimal('30')},
|
||||
])
|
||||
|
||||
def test_sale_report_crop_name_handles_missing_crop(self):
|
||||
'sale report crop name returns an empty string when crop is missing'
|
||||
Sale = Pool().get('sale.sale')
|
||||
|
||||
sale = Sale()
|
||||
sale.crop = None
|
||||
self.assertEqual(sale.report_crop_name, '')
|
||||
|
||||
sale.crop = Mock(name='crop')
|
||||
sale.crop.name = 'Main Crop'
|
||||
self.assertEqual(sale.report_crop_name, 'Main Crop')
|
||||
|
||||
|
||||
del ModuleTestCase
|
||||
|
||||
@@ -4069,7 +4069,7 @@
|
||||
<text:s />
|
||||
<text:span text:style-name="T21">CROP </text:span>
|
||||
<text:span text:style-name="T21">
|
||||
<text:placeholder text:placeholder-type="text"><sale.crop.name></text:placeholder>
|
||||
<text:placeholder text:placeholder-type="text"><sale.report_crop_name></text:placeholder>
|
||||
</text:span>
|
||||
</text:p>
|
||||
</table:table-cell>
|
||||
|
||||
Reference in New Issue
Block a user