diff --git a/modules/purchase_trade/docs/business/pricing.md b/modules/purchase_trade/docs/business/pricing.md
index 2b432d3..e56865e 100644
--- a/modules/purchase_trade/docs/business/pricing.md
+++ b/modules/purchase_trade/docs/business/pricing.md
@@ -1,67 +1,436 @@
-# Pricing, basis, premium
+# Pricing, basis et fixing
-Statut: `migration partielle`
+Langue : `fr`
+Statut : `migration partielle`
+Derniere verification code : `2026-05-25`
-## BR-PT-PRI-001 - Le premium fait partie du prix economique
+Cette page consolide les regles de pricing trade autour des composants, des
+periodes de prix, des periodes d'application, du fixing manuel et du prix final
+des lignes achat / vente.
+
+## A retenir
+
+
Resume operationnelUne ligne trade peut etre en prix fixe, basis ou EFP. En basis, le prix de base vient d'un ou plusieurs composants de fixing. Chaque composant lit une courbe de prix, construit des dates de prix, applique ces prix sur des dates d'application, puis alimente le prix de la ligne via un summary.
+
+
+
+
+
+| Sujet |
+Regle courte |
+
+
+
+
+| Composant |
+Un pricing.component appartient a une ligne achat ou vente. |
+
+
+| Courbe |
+La courbe principale est price_index. |
+
+
+| Matrix |
+La matrix existe dans le modele mais n'est pas encore le moteur principal du fixing automatique. |
+
+
+| Pricing period |
+Definit les dates ou lire les prix sur la courbe. |
+
+
+| Application period |
+Definit les dates ou appliquer les tranches de fixing. |
+
+
+| AVG |
+Utilise la moyenne progressive des prix lus. |
+
+
+| LAST |
+Autorise la courbe a reprendre le dernier prix connu si la date n'a pas de prix. |
+
+
+| Pricing rows |
+Les lignes pricing.pricing portent quantite fixee, non fixee et prix EOD. |
+
+
+| Summary |
+Le summary remonte la derniere ligne de pricing du groupe. |
+
+
+| Prix ligne |
+En basis, unit_price est le prix base hors premium. |
+
+
+
+
+pricing.component
+ |
+ v
+pricing.trigger
+ |
+ +--> pricing period --> dates de lecture curve
+ |
+ +--> application period --> dates de fixing
+ |
+ v
+ pricing.pricing
+ |
+ v
+ purchase/sale pricing summary
+ |
+ v
+ line.unit_price
+
+## Regles consultant
+
+### BR-PT-PRI-001 - Le premium fait partie du prix economique
Source: `BR-PT-008`
-### Regle consultant
+
+
+
+| Point |
+Regle |
+
+
+
+
+| Prix visible |
+unit_price reste le prix de base hors premium. |
+
+
+| Prix economique |
+Le montant utilise unit_price + premium. |
+
+
+| Basis |
+Le premium s'ajoute aussi quand le prix base vient du fixing. |
+
+
+| Documents commerciaux |
+Une ligne basis peut afficher le premium comme prix visible selon le contexte document. |
+
+
+| Valuation |
+Le premium doit etre pris en compte dans les lignes valorisees. |
+
+
+
-Le premium ou discount saisi sur une ligne fait partie du prix economique, que
-la ligne soit en prix fixe ou en basis.
+Point cleLe premium n'est pas un composant de fixing. Il reste porte par la ligne commerciale, mais il fait partie du prix economique utilise pour les montants.
-### Notes developpeur
-
-unit_price reste le prix de base hors premium.
-
-- Montant economique:
unit_price + premium converti si necessaire.
-
-- En basis, le premium s'applique aussi aux blocs valorises.
-
-
-
-## BR-PT-PRI-002 - Linked currency
+### BR-PT-PRI-002 - Linked currency
Source: `BR-PT-009` et `BR-PT-010`
-### Regle consultant
+
+
+
+| Point |
+Regle |
+
+
+
+
+| Activation |
+linked_price, linked_currency et linked_unit deviennent obligatoires. |
+
+
+| Saisie |
+Le prix et le premium peuvent etre saisis dans le repere lie. |
+
+
+| Conversion |
+Les calculs internes convertissent vers la devise / unite de la ligne. |
+
+
+| Basis |
+En basis + linked currency, linked_price represente le basis brut hors premium. |
+
+
+| Amount |
+Le montant ajoute le premium converti. |
+
+
+
-Quand le prix est saisi dans une devise ou unite liee, le premium est exprime
-dans ce meme repere puis converti pour les calculs internes.
-
-### Notes developpeur
-
-
-- Champs obligatoires si active:
linked_price, linked_currency, linked_unit.
-
-- En
basis + linked currency, linked_price represente le basis brut hors premium.
-
-amount ajoute le premium converti.
-
-
-
-## BR-PT-PRI-003 - Pricing manuel
+### BR-PT-PRI-003 - Pricing manuel
Source: `BR-PT-016` et doublon historique `BR-PT-015`
-### Regle consultant
+
+
+
+| Colonne |
+Role |
+
+
+
+
+pricing_date |
+Date de saisie du fixing. |
+
+
+quantity |
+Quantite fixee ce jour. |
+
+
+settl_price |
+Prix de marche saisi. |
+
+
+fixed_qt |
+Cumul des quantites fixees. |
+
+
+fixed_qt_price |
+Prix moyen pondere du cumul fixe. |
+
+
+unfixed_qt |
+Solde restant a fixer. |
+
+
+unfixed_qt_price |
+Prix de fallback du solde non fixe. |
+
+
+eod_price |
+Prix economique courant de la ligne de fixing. |
+
+
+last |
+Derniere ligne du groupe, utilisee par le summary. |
+
+
+
-En pricing manuel, l'utilisateur saisit uniquement la quantite fixee du jour et
-le prix de marche. Les cumuls et prix moyens sont calcules automatiquement.
+Saisie utilisateurEn manuel, l'utilisateur renseigne seulement quantity et settl_price. Les cumuls, le prix moyen, le solde non fixe et last sont recalcules par le systeme.
-### Notes developpeur
+
+### BR-PT-PRI-004 - Pricing automatique par composant
+
+
+
+
+| Etape |
+Effet metier |
+
+
+
+
+| Composant |
+L'utilisateur choisit une courbe, un calendrier et active Auto. |
+
+
+| Trigger |
+L'utilisateur definit une periode de prix et une periode d'application. |
+
+
+| Lecture prix |
+Le systeme lit les prix de la courbe sur les dates de pricing. |
+
+
+| Application |
+Le systeme cree une ligne de pricing par date d'application. |
+
+
+| Quota |
+La quantite fixee par date correspond a la quantite de ligne divisee par le nombre de dates d'application. |
+
+
+| Moyenne |
+Si AVG est coche, le prix fixe utilise la moyenne progressive. |
+
+
+| Fallback prix |
+Si LAST est coche, la courbe peut reprendre le dernier prix disponible. |
+
+
+| Cut-off |
+Pricing date max arrete la generation apres cette date. |
+
+
+
+
+Prix lus: P1 P2 P3 P4
+Application: A1 A2 A3 A4
+Quantite fixee: Q/4 Q/4 Q/4 Q/4
+Summary: derniere ligne marquee last
+
+### BR-PT-PRI-005 - Mode From / To manuel
+
+
+
+
+| Cas |
+Regle |
+
+
+
+
+Pas de pricing_period |
+L'utilisateur peut saisir From / To cote pricing. |
+
+
+Pas de application_period |
+L'utilisateur peut saisir From / To cote application. |
+
+
+| Application vide |
+Par defaut, l'application reprend la meme fourchette que le pricing manuel. |
+
+
+| Calendrier present |
+Les jours fermes du calendrier sont exclus. |
+
+
+| Calendrier absent |
+Tous les jours calendaires de la fourchette sont utilises. |
+
+
+| Lecture curve |
+Les prix sont lus sur les dates de la fourchette pricing. |
+
+
+| Application fixing |
+Les lignes de fixing sont creees sur les dates de la fourchette application. |
+
+
+
+
+Exemple simplePricing 01/04 -> 05/04, Application vide. Le systeme lit les prix du 1 au 5 avril et cree les applications sur ces memes dates, sauf jours exclus par le calendrier si un calendrier est renseigne.
+
+
+## Section developpeur
+
+### Modeles pivots
-- Champs saisis:
quantity, settl_price.
+ - Composant :
pricing.component
-- Champs derives:
fixed_qt, fixed_qt_price, unfixed_qt, unfixed_qt_price, eod_price, last.
+ - Trigger :
pricing.trigger
-- Groupe metier:
line + component ou sale_line + component.
+ - Periode relative :
pricing.period
-- Le composant choisi doit appartenir a la ligne courante.
+
- Ligne de fixing :
pricing.pricing
+
+- Summary achat :
purchase.pricing.summary
+
+- Summary vente :
sale.pricing.summary
+
+- Ligne achat :
purchase.line
+
+- Ligne vente :
sale.line
+
+- Courbe :
price.price
+
+- Valeur de courbe :
price.price_value
+
+- Calendrier :
price.calendar
+
+
+
+### Methodes principales
+
+
+pricing.trigger.getPricingListDates()
+
+pricing.trigger.getApplicationListDates()
+
+pricing.trigger.getListDates()
+
+pricing.trigger.getprice()
+
+purchase.line.check_pricing()
+
+sale.line.check_pricing()
+
+purchase.line.generate_pricing()
+
+sale.line.generate_pricing()
+
+pricing.pricing._sync_manual_values()
+
+pricing.pricing._sync_manual_last()
+
+purchase.pricing.summary.table_query()
+
+sale.pricing.summary.table_query()
+
+
+
+### Points d'attention actuels
+
+
+
+
+| Sujet |
+Etat |
+
+
+
+
+fallback composant |
+Champ present, logique metier encore portee par trigger.last. |
+
+
+last trigger |
+Signifie dernier prix disponible sur la curve. |
+
+
+last pricing |
+Signifie derniere ligne du groupe pour le summary. |
+
+
+| Matrix |
+Disponible dans le modele et le MTM, pas encore completement integree au fixing auto. |
+
+
+prDate / apPrice |
+Variables intermediaires historiques peu exploitees. |
+
+
+| AVG |
+Moyenne progressive calculee sur la liste des prix lus. |
+
+
+
+
+## Tests proches
+
+
+modules/purchase_trade/tests/test_module.py
+
+- Couverture existante :
+
+- champs manuels readonly / editable ;
+
+- recalcul du pricing manuel ;
+
+- unicite logique du
last par groupe ;
+
+- fallback
quantity si quantity_theorical est vide ;
+
+- controle que le composant appartient a la ligne courante.
+
+
+
+- Tests a maintenir :
+
+- From / To manuel sans calendrier ;
+
+- From / To manuel avec calendrier ;
+
+- application vide qui reprend la fourchette pricing ;
+
+- comportement AVG / LAST.
+
+
diff --git a/modules/purchase_trade/docs_source/business/pricing.md b/modules/purchase_trade/docs_source/business/pricing.md
index 3ebee56..03c6eb4 100644
--- a/modules/purchase_trade/docs_source/business/pricing.md
+++ b/modules/purchase_trade/docs_source/business/pricing.md
@@ -1,53 +1,195 @@
-# Pricing, basis, premium
+# Pricing, basis et fixing
-Statut: `migration partielle`
+Langue : `fr`
+Statut : `migration partielle`
+Derniere verification code : `2026-05-25`
-## BR-PT-PRI-001 - Le premium fait partie du prix economique
+Cette page consolide les regles de pricing trade autour des composants, des
+periodes de prix, des periodes d'application, du fixing manuel et du prix final
+des lignes achat / vente.
+
+## A retenir
+
+> **Resume operationnel**
+> Une ligne trade peut etre en prix fixe, basis ou EFP. En basis, le prix de
+> base vient d'un ou plusieurs composants de fixing. Chaque composant lit une
+> courbe de prix, construit des dates de prix, applique ces prix sur des dates
+> d'application, puis alimente le prix de la ligne via un summary.
+
+| Sujet | Regle courte |
+| --- | --- |
+| Composant | Un `pricing.component` appartient a une ligne achat ou vente. |
+| Courbe | La courbe principale est `price_index`. |
+| Matrix | La matrix existe dans le modele mais n'est pas encore le moteur principal du fixing automatique. |
+| Pricing period | Definit les dates ou lire les prix sur la courbe. |
+| Application period | Definit les dates ou appliquer les tranches de fixing. |
+| AVG | Utilise la moyenne progressive des prix lus. |
+| LAST | Autorise la courbe a reprendre le dernier prix connu si la date n'a pas de prix. |
+| Pricing rows | Les lignes `pricing.pricing` portent quantite fixee, non fixee et prix EOD. |
+| Summary | Le summary remonte la derniere ligne de pricing du groupe. |
+| Prix ligne | En `basis`, `unit_price` est le prix base hors premium. |
+
+```text
+pricing.component
+ |
+ v
+pricing.trigger
+ |
+ +--> pricing period --> dates de lecture curve
+ |
+ +--> application period --> dates de fixing
+ |
+ v
+ pricing.pricing
+ |
+ v
+ purchase/sale pricing summary
+ |
+ v
+ line.unit_price
+```
+
+## Regles consultant
+
+### BR-PT-PRI-001 - Le premium fait partie du prix economique
Source: `BR-PT-008`
-### Regle consultant
+| Point | Regle |
+| --- | --- |
+| Prix visible | `unit_price` reste le prix de base hors premium. |
+| Prix economique | Le montant utilise `unit_price + premium`. |
+| Basis | Le premium s'ajoute aussi quand le prix base vient du fixing. |
+| Documents commerciaux | Une ligne `basis` peut afficher le premium comme prix visible selon le contexte document. |
+| Valuation | Le premium doit etre pris en compte dans les lignes valorisees. |
-Le premium ou discount saisi sur une ligne fait partie du prix economique, que
-la ligne soit en prix fixe ou en basis.
+> **Point cle**
+> Le premium n'est pas un composant de fixing. Il reste porte par la ligne
+> commerciale, mais il fait partie du prix economique utilise pour les montants.
-### Notes developpeur
-
-- `unit_price` reste le prix de base hors premium.
-- Montant economique: `unit_price + premium converti si necessaire`.
-- En basis, le premium s'applique aussi aux blocs valorises.
-
-## BR-PT-PRI-002 - Linked currency
+### BR-PT-PRI-002 - Linked currency
Source: `BR-PT-009` et `BR-PT-010`
-### Regle consultant
+| Point | Regle |
+| --- | --- |
+| Activation | `linked_price`, `linked_currency` et `linked_unit` deviennent obligatoires. |
+| Saisie | Le prix et le premium peuvent etre saisis dans le repere lie. |
+| Conversion | Les calculs internes convertissent vers la devise / unite de la ligne. |
+| Basis | En `basis + linked currency`, `linked_price` represente le basis brut hors premium. |
+| Amount | Le montant ajoute le premium converti. |
-Quand le prix est saisi dans une devise ou unite liee, le premium est exprime
-dans ce meme repere puis converti pour les calculs internes.
-
-### Notes developpeur
-
-- Champs obligatoires si active: `linked_price`, `linked_currency`,
- `linked_unit`.
-- En `basis + linked currency`, `linked_price` represente le basis brut hors
- premium.
-- `amount` ajoute le premium converti.
-
-## BR-PT-PRI-003 - Pricing manuel
+### BR-PT-PRI-003 - Pricing manuel
Source: `BR-PT-016` et doublon historique `BR-PT-015`
-### Regle consultant
+| Colonne | Role |
+| --- | --- |
+| `pricing_date` | Date de saisie du fixing. |
+| `quantity` | Quantite fixee ce jour. |
+| `settl_price` | Prix de marche saisi. |
+| `fixed_qt` | Cumul des quantites fixees. |
+| `fixed_qt_price` | Prix moyen pondere du cumul fixe. |
+| `unfixed_qt` | Solde restant a fixer. |
+| `unfixed_qt_price` | Prix de fallback du solde non fixe. |
+| `eod_price` | Prix economique courant de la ligne de fixing. |
+| `last` | Derniere ligne du groupe, utilisee par le summary. |
-En pricing manuel, l'utilisateur saisit uniquement la quantite fixee du jour et
-le prix de marche. Les cumuls et prix moyens sont calcules automatiquement.
+> **Saisie utilisateur**
+> En manuel, l'utilisateur renseigne seulement `quantity` et `settl_price`.
+> Les cumuls, le prix moyen, le solde non fixe et `last` sont recalcules par le
+> systeme.
-### Notes developpeur
+### BR-PT-PRI-004 - Pricing automatique par composant
-- Champs saisis: `quantity`, `settl_price`.
-- Champs derives: `fixed_qt`, `fixed_qt_price`, `unfixed_qt`,
- `unfixed_qt_price`, `eod_price`, `last`.
-- Groupe metier: `line + component` ou `sale_line + component`.
-- Le composant choisi doit appartenir a la ligne courante.
+| Etape | Effet metier |
+| --- | --- |
+| Composant | L'utilisateur choisit une courbe, un calendrier et active `Auto`. |
+| Trigger | L'utilisateur definit une periode de prix et une periode d'application. |
+| Lecture prix | Le systeme lit les prix de la courbe sur les dates de pricing. |
+| Application | Le systeme cree une ligne de pricing par date d'application. |
+| Quota | La quantite fixee par date correspond a la quantite de ligne divisee par le nombre de dates d'application. |
+| Moyenne | Si `AVG` est coche, le prix fixe utilise la moyenne progressive. |
+| Fallback prix | Si `LAST` est coche, la courbe peut reprendre le dernier prix disponible. |
+| Cut-off | `Pricing date max` arrete la generation apres cette date. |
+```text
+Prix lus: P1 P2 P3 P4
+Application: A1 A2 A3 A4
+Quantite fixee: Q/4 Q/4 Q/4 Q/4
+Summary: derniere ligne marquee last
+```
+
+### BR-PT-PRI-005 - Mode From / To manuel
+
+| Cas | Regle |
+| --- | --- |
+| Pas de `pricing_period` | L'utilisateur peut saisir `From` / `To` cote pricing. |
+| Pas de `application_period` | L'utilisateur peut saisir `From` / `To` cote application. |
+| Application vide | Par defaut, l'application reprend la meme fourchette que le pricing manuel. |
+| Calendrier present | Les jours fermes du calendrier sont exclus. |
+| Calendrier absent | Tous les jours calendaires de la fourchette sont utilises. |
+| Lecture curve | Les prix sont lus sur les dates de la fourchette pricing. |
+| Application fixing | Les lignes de fixing sont creees sur les dates de la fourchette application. |
+
+> **Exemple simple**
+> Pricing `01/04 -> 05/04`, Application vide. Le systeme lit les prix du 1 au
+> 5 avril et cree les applications sur ces memes dates, sauf jours exclus par le
+> calendrier si un calendrier est renseigne.
+
+## Section developpeur
+
+### Modeles pivots
+
+- Composant : `pricing.component`
+- Trigger : `pricing.trigger`
+- Periode relative : `pricing.period`
+- Ligne de fixing : `pricing.pricing`
+- Summary achat : `purchase.pricing.summary`
+- Summary vente : `sale.pricing.summary`
+- Ligne achat : `purchase.line`
+- Ligne vente : `sale.line`
+- Courbe : `price.price`
+- Valeur de courbe : `price.price_value`
+- Calendrier : `price.calendar`
+
+### Methodes principales
+
+- `pricing.trigger.getPricingListDates()`
+- `pricing.trigger.getApplicationListDates()`
+- `pricing.trigger.getListDates()`
+- `pricing.trigger.getprice()`
+- `purchase.line.check_pricing()`
+- `sale.line.check_pricing()`
+- `purchase.line.generate_pricing()`
+- `sale.line.generate_pricing()`
+- `pricing.pricing._sync_manual_values()`
+- `pricing.pricing._sync_manual_last()`
+- `purchase.pricing.summary.table_query()`
+- `sale.pricing.summary.table_query()`
+
+### Points d'attention actuels
+
+| Sujet | Etat |
+| --- | --- |
+| `fallback` composant | Champ present, logique metier encore portee par `trigger.last`. |
+| `last` trigger | Signifie dernier prix disponible sur la curve. |
+| `last` pricing | Signifie derniere ligne du groupe pour le summary. |
+| Matrix | Disponible dans le modele et le MTM, pas encore completement integree au fixing auto. |
+| `prDate` / `apPrice` | Variables intermediaires historiques peu exploitees. |
+| AVG | Moyenne progressive calculee sur la liste des prix lus. |
+
+## Tests proches
+
+- `modules/purchase_trade/tests/test_module.py`
+- Couverture existante :
+ - champs manuels readonly / editable ;
+ - recalcul du pricing manuel ;
+ - unicite logique du `last` par groupe ;
+ - fallback `quantity` si `quantity_theorical` est vide ;
+ - controle que le composant appartient a la ligne courante.
+- Tests a maintenir :
+ - From / To manuel sans calendrier ;
+ - From / To manuel avec calendrier ;
+ - application vide qui reprend la fourchette pricing ;
+ - comportement AVG / LAST.
diff --git a/modules/purchase_trade/pricing.py b/modules/purchase_trade/pricing.py
index adf1fa5..710280a 100755
--- a/modules/purchase_trade/pricing.py
+++ b/modules/purchase_trade/pricing.py
@@ -1088,10 +1088,20 @@ class Trigger(ModelSQL,ModelView):
'readonly': Eval('application_period') != None,
})
- @fields.depends('pricing_period')
- def on_change_with_application_period(self):
- if not self.application_period and self.pricing_period:
- return self.pricing_period
+ @fields.depends('pricing_period')
+ def on_change_with_application_period(self):
+ if not self.application_period and self.pricing_period:
+ return self.pricing_period
+
+ @fields.depends('from_p', 'from_a', 'application_period')
+ def on_change_from_p(self):
+ if not self.application_period and not self.from_a:
+ self.from_a = self.from_p
+
+ @fields.depends('to_p', 'to_a', 'application_period')
+ def on_change_to_p(self):
+ if not self.application_period and not self.to_a:
+ self.to_a = self.to_p
def getDateWithEstTrigger(self, period):
PP = Pool().get('pricing.period')
@@ -1108,59 +1118,58 @@ class Trigger(ModelSQL,ModelView):
date_from,date_to,dates = pp.getDates(d)
return date_from,date_to,d,pp.include,dates
- def getApplicationListDates(self, cal):
- ld = []
- if self.application_period:
- date_from, date_to, d, include,dates = self.getDateWithEstTrigger(2)
- else:
- date_from = self.from_a
- date_to = self.to_a
- d = None
- include = False
- ld, lprice = self.getListDates(date_from,date_to,d,include,cal,2,dates)
- return ld, lprice
-
- def getPricingListDates(self,cal):
- ld = []
- if self.pricing_period:
- date_from, date_to, d, include,dates = self.getDateWithEstTrigger(1)
- else:
- date_from = self.from_p#datetime.datetime(self.from_p.year, self.from_p.month, self.from_p.day)
- date_to = self.to_p#datetime.datetime(self.to_p.year, self.to_p.month, self.to_p.day)
+ def getApplicationListDates(self, cal):
+ ld = []
+ dates = []
+ if self.application_period:
+ date_from, date_to, d, include,dates = self.getDateWithEstTrigger(2)
+ else:
+ date_from = self.from_a or self.from_p
+ date_to = self.to_a or self.to_p
+ d = None
+ include = False
+ ld, lprice = self.getListDates(date_from,date_to,d,include,cal,2,dates)
+ return ld, lprice
+
+ def getPricingListDates(self,cal):
+ ld = []
+ dates = []
+ if self.pricing_period:
+ date_from, date_to, d, include,dates = self.getDateWithEstTrigger(1)
+ else:
+ date_from = self.from_p#datetime.datetime(self.from_p.year, self.from_p.month, self.from_p.day)
+ date_to = self.to_p#datetime.datetime(self.to_p.year, self.to_p.month, self.to_p.day)
d = None
include = False
ld, lprice = self.getListDates(date_from,date_to,d,include,cal,1,dates)
return ld, lprice
- def getListDates(self,df,dt,t,i,cal,pricing,dates):
- l = []
- lprice = []
- CAL = Pool().get('price.calendar')
- if cal:
- cal = CAL(cal)
- if dates:
- for d in dates:
- if cal.IsQuote(d):
- l.append(d)
- if pricing == 1:
- lprice.append(self.getprice(d))
- return l, lprice
- if df and dt:
- current_date = datetime.datetime(df.year,df.month,df.day)
- dt = datetime.datetime(dt.year,dt.month,dt.day)
- while current_date <= dt:
- if i or (not i and current_date != t):
- if cal:
- if cal.IsQuote(current_date):
- l.append(current_date)
- if pricing == 1:
- lprice.append(self.getprice(current_date))
- else:
- l.append(current_date)
- if pricing == 1:
- lprice.append(self.getprice(current_date))
- current_date += datetime.timedelta(days=1)
- return l, lprice
+ def getListDates(self,df,dt,t,i,cal,pricing,dates):
+ l = []
+ lprice = []
+ def append_date(date):
+ if cal:
+ if not cal.IsQuote(date):
+ return
+ l.append(date)
+ if pricing == 1:
+ lprice.append(self.getprice(date))
+
+ if cal:
+ CAL = Pool().get('price.calendar')
+ cal = CAL(cal)
+ if dates:
+ for d in dates:
+ append_date(d)
+ return l, lprice
+ if df and dt:
+ current_date = datetime.datetime(df.year,df.month,df.day)
+ dt = datetime.datetime(dt.year,dt.month,dt.day)
+ while current_date <= dt:
+ if i or (not i and current_date != t):
+ append_date(current_date)
+ current_date += datetime.timedelta(days=1)
+ return l, lprice
def getprice(self,current_date):
PI = Pool().get('price.price')
diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py
index bfe28c7..679323a 100644
--- a/modules/purchase_trade/tests/test_module.py
+++ b/modules/purchase_trade/tests/test_module.py
@@ -1586,6 +1586,69 @@ class PurchaseTradeTestCase(ModuleTestCase):
self.assertEqual(second_values['eod_price'], Decimal('106.0000'))
self.assertTrue(second_values['last'])
+ def test_pricing_trigger_manual_from_to_generates_dates_without_calendar(self):
+ 'manual pricing From/To uses calendar days when no calendar is selected'
+ Trigger = Pool().get('pricing.trigger')
+ trigger = Trigger()
+ trigger.pricing_period = None
+ trigger.from_p = datetime.date(2026, 4, 1)
+ trigger.to_p = datetime.date(2026, 4, 3)
+ trigger.getprice = Mock(side_effect=lambda date: {
+ 'date': date,
+ 'price': Decimal('100'),
+ 'avg': Decimal('100'),
+ 'avg_minus_1': Decimal('100'),
+ 'isAvg': False,
+ })
+
+ dates, prices = trigger.getPricingListDates(None)
+
+ self.assertEqual(
+ [date.date() for date in dates],
+ [
+ datetime.date(2026, 4, 1),
+ datetime.date(2026, 4, 2),
+ datetime.date(2026, 4, 3),
+ ])
+ self.assertEqual(len(prices), 3)
+
+ def test_pricing_trigger_manual_application_defaults_to_pricing_from_to(self):
+ 'empty manual application From/To falls back to manual pricing From/To'
+ Trigger = Pool().get('pricing.trigger')
+ trigger = Trigger()
+ trigger.pricing_period = None
+ trigger.application_period = None
+ trigger.from_p = datetime.date(2026, 4, 1)
+ trigger.to_p = datetime.date(2026, 4, 2)
+ trigger.from_a = None
+ trigger.to_a = None
+
+ dates, prices = trigger.getApplicationListDates(None)
+
+ self.assertEqual(
+ [date.date() for date in dates],
+ [
+ datetime.date(2026, 4, 1),
+ datetime.date(2026, 4, 2),
+ ])
+ self.assertEqual(prices, [])
+
+ def test_pricing_trigger_on_change_copies_manual_pricing_dates_to_application(self):
+ 'manual pricing From/To is copied to empty application From/To in the UI'
+ Trigger = Pool().get('pricing.trigger')
+ trigger = Trigger()
+ trigger.application_period = None
+ trigger.from_p = datetime.date(2026, 4, 1)
+ trigger.to_p = datetime.date(2026, 4, 30)
+ trigger.from_a = None
+ trigger.to_a = None
+
+ trigger.on_change_from_p()
+ trigger.on_change_to_p()
+
+ self.assertEqual(trigger.from_a, datetime.date(2026, 4, 1))
+ self.assertEqual(trigger.to_a, datetime.date(2026, 4, 30))
+
def test_sale_and_purchase_trader_operator_domains_use_explicit_categories(self):
'sale and purchase trader/operator fields are filtered by TRADER/OPERATOR categories'
Sale = Pool().get('sale.sale')