an expiry date computed from the request/receipt date and the sample shelf life;
-
a simple cupping score and physical quality values.
+
physical quality values and links to cupping sessions.
+
+
+
+Coffee compatibility is disabled by default and must be enabled on
+`purchase_trade.configuration` with the `Active coffee compatibility` field.
+While the option is disabled, coffee menus and coffee quality pages on lines
+must not be visible.
+
+Cupping results are entered through sessions:
+
+
+
cupping properties/criteria are configurable;
+
+
a session defines the room cup capacity and the number of cups per sample;
+
+
each sample added to the session generates several blind-coded cups;
+
+
multiple cuppers can enter a result for each cup;
+
+
cuppers see only the origin and coffee type, not the contract or supplier;
+
+
the preparation order proposes arabicas first, blends/other coffees next and robustas at the end of the session;
+
+
the final decision remains global on the session sample: approved, rejected or re-cup.
@@ -39,6 +63,20 @@ defect count and minimum cup score.
modules/purchase_trade/view/sale_line_form.xml
@@ -67,7 +107,9 @@ defect count and minimum cup score.
phase 1 does not block shipment or contract validation;
-
lab delegation is a tracking field, not a complete lab workflow yet.
+
lab delegation is a tracking field, not a complete lab workflow yet;
+
+
coffee menus are inactive by default and synchronized when the configuration is saved.
diff --git a/modules/purchase_trade/docs/business/coffee.md b/modules/purchase_trade/docs/business/coffee.md
index 97956d1..4f7a415 100644
--- a/modules/purchase_trade/docs/business/coffee.md
+++ b/modules/purchase_trade/docs/business/coffee.md
@@ -25,7 +25,31 @@ Chaque echantillon porte:
une date d'expiration calculee depuis la date de demande/reception et la duree de vie de l'echantillon;
-
une notation de cupping simple et des donnees de qualite physique.
+
des donnees de qualite physique et des liens vers les seances de cupping.
+
+
+
+La compatibilite cafe est inactive par defaut et doit etre activee dans la
+configuration `purchase_trade.configuration` avec le champ `Active coffee
+compatibility`. Tant que l'option est inactive, les menus cafe et les pages
+qualite cafe des lignes ne doivent pas etre visibles.
+
+Les resultats de cupping sont saisis dans des seances:
+
+
+
les proprietes/criteres de cupping sont parametrables;
+
+
une seance definit une capacite de salle en nombre de tasses et un nombre de tasses par echantillon;
+
+
chaque echantillon inscrit a la seance genere plusieurs tasses avec un code aveugle;
+
+
plusieurs personnes peuvent saisir un resultat par tasse;
+
+
les degustateurs voient uniquement l'origine et le type de cafe, pas le contrat ni le fournisseur;
+
+
l'ordre de preparation propose les arabicas avant les blends/autres cafes et garde les robustas en fin de seance;
+
+
la decision finale reste globale a l'echantillon de seance: approved, rejected ou re-cup.
@@ -40,6 +64,20 @@ maximum, nombre de defauts maximum et score cup minimum.
modules/purchase_trade/view/sale_line_form.xml
@@ -68,7 +108,9 @@ maximum, nombre de defauts maximum et score cup minimum.
aucun blocage shipment/validation n'est introduit en phase 1;
-
la delegation labo reste une information de suivi, sans workflow labo complet.
+
la delegation labo reste une information de suivi, sans workflow labo complet;
+
+
les menus cafe sont inactifs par defaut et synchronises quand la configuration est sauvegardee.
diff --git a/modules/purchase_trade/docs_source/business/coffee.en.md b/modules/purchase_trade/docs_source/business/coffee.en.md
index c7808ad..e4e21b3 100644
--- a/modules/purchase_trade/docs_source/business/coffee.en.md
+++ b/modules/purchase_trade/docs_source/business/coffee.en.md
@@ -20,7 +20,24 @@ Each sample stores:
rejected, expired, archived;
- an expiry date computed from the request/receipt date and the sample shelf
life;
-- a simple cupping score and physical quality values.
+- physical quality values and links to cupping sessions.
+
+Coffee compatibility is disabled by default and must be enabled on
+`purchase_trade.configuration` with the `Active coffee compatibility` field.
+While the option is disabled, coffee menus and coffee quality pages on lines
+must not be visible.
+
+Cupping results are entered through sessions:
+
+- cupping properties/criteria are configurable;
+- a session defines the room cup capacity and the number of cups per sample;
+- each sample added to the session generates several blind-coded cups;
+- multiple cuppers can enter a result for each cup;
+- cuppers see only the origin and coffee type, not the contract or supplier;
+- the preparation order proposes arabicas first, blends/other coffees next and
+ robustas at the end of the session;
+- the final decision remains global on the session sample: approved, rejected
+ or re-cup.
`purchase.line` and `sale.line` store the target coffee quality specifications:
origin, process, variety, crop year, screen size, maximum moisture, maximum
@@ -30,6 +47,13 @@ defect count and minimum cup score.
- Models/fields:
- `coffee.sample`
+ - `coffee.cupping.criterion`
+ - `coffee.cupping.session`
+ - `coffee.cupping.session.sample`
+ - `coffee.cupping.cup`
+ - `coffee.cupping.result`
+ - `coffee.cupping.result.line`
+ - `purchase_trade.configuration.active_coffee_compatibility`
- `purchase.line.coffee_samples`
- `sale.line.coffee_samples`
- `coffee_*` fields on `purchase.line` and `sale.line`
@@ -37,9 +61,12 @@ defect count and minimum cup score.
- `modules/purchase_trade/coffee.py`
- `modules/purchase_trade/coffee.xml`
- `modules/purchase_trade/view/coffee_sample_*.xml`
+ - `modules/purchase_trade/view/coffee_cupping_*.xml`
- `modules/purchase_trade/view/purchase_line_form.xml`
- `modules/purchase_trade/view/sale_line_form.xml`
- Caveats:
- expiry is monitored through the `Expired` and `Expiring soon` domains;
- phase 1 does not block shipment or contract validation;
- - lab delegation is a tracking field, not a complete lab workflow yet.
+ - lab delegation is a tracking field, not a complete lab workflow yet;
+ - coffee menus are inactive by default and synchronized when the
+ configuration is saved.
diff --git a/modules/purchase_trade/docs_source/business/coffee.md b/modules/purchase_trade/docs_source/business/coffee.md
index 79bd2cc..5b0bba5 100644
--- a/modules/purchase_trade/docs_source/business/coffee.md
+++ b/modules/purchase_trade/docs_source/business/coffee.md
@@ -21,7 +21,27 @@ Chaque echantillon porte:
rejected, expired, archived;
- une date d'expiration calculee depuis la date de demande/reception et la
duree de vie de l'echantillon;
-- une notation de cupping simple et des donnees de qualite physique.
+- des donnees de qualite physique et des liens vers les seances de cupping.
+
+La compatibilite cafe est inactive par defaut et doit etre activee dans la
+configuration `purchase_trade.configuration` avec le champ `Active coffee
+compatibility`. Tant que l'option est inactive, les menus cafe et les pages
+qualite cafe des lignes ne doivent pas etre visibles.
+
+Les resultats de cupping sont saisis dans des seances:
+
+- les proprietes/criteres de cupping sont parametrables;
+- une seance definit une capacite de salle en nombre de tasses et un nombre de
+ tasses par echantillon;
+- chaque echantillon inscrit a la seance genere plusieurs tasses avec un code
+ aveugle;
+- plusieurs personnes peuvent saisir un resultat par tasse;
+- les degustateurs voient uniquement l'origine et le type de cafe, pas le
+ contrat ni le fournisseur;
+- l'ordre de preparation propose les arabicas avant les blends/autres cafes et
+ garde les robustas en fin de seance;
+- la decision finale reste globale a l'echantillon de seance: approved,
+ rejected ou re-cup.
Les lignes `purchase.line` et `sale.line` portent les specifications qualite
cibles du cafe: origine, process, variete, crop year, screen size, humidite
@@ -31,6 +51,13 @@ maximum, nombre de defauts maximum et score cup minimum.
- Modeles/champs:
- `coffee.sample`
+ - `coffee.cupping.criterion`
+ - `coffee.cupping.session`
+ - `coffee.cupping.session.sample`
+ - `coffee.cupping.cup`
+ - `coffee.cupping.result`
+ - `coffee.cupping.result.line`
+ - `purchase_trade.configuration.active_coffee_compatibility`
- `purchase.line.coffee_samples`
- `sale.line.coffee_samples`
- champs `coffee_*` sur `purchase.line` et `sale.line`
@@ -38,10 +65,13 @@ maximum, nombre de defauts maximum et score cup minimum.
- `modules/purchase_trade/coffee.py`
- `modules/purchase_trade/coffee.xml`
- `modules/purchase_trade/view/coffee_sample_*.xml`
+ - `modules/purchase_trade/view/coffee_cupping_*.xml`
- `modules/purchase_trade/view/purchase_line_form.xml`
- `modules/purchase_trade/view/sale_line_form.xml`
- Points de vigilance:
- l'expiration est pilotee par les domaines `Expired` et `Expiring soon`;
- aucun blocage shipment/validation n'est introduit en phase 1;
- la delegation labo reste une information de suivi, sans workflow labo
- complet.
+ complet;
+ - les menus cafe sont inactifs par defaut et synchronises quand la
+ configuration est sauvegardee.
diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py
index 5093f38..9d1529b 100644
--- a/modules/purchase_trade/tests/test_module.py
+++ b/modules/purchase_trade/tests/test_module.py
@@ -31,20 +31,53 @@ class PurchaseTradeTestCase(ModuleTestCase):
'Test purchase_trade module'
module = 'purchase_trade'
- def test_coffee_sample_cup_score_sums_cupping_criteria(self):
- 'coffee sample cup score sums criteria and subtracts defects'
- score_fields = [
- 'aroma', 'flavor', 'aftertaste', 'acidity', 'body', 'balance',
- 'sweetness', 'clean_cup', 'uniformity', 'overall']
- sample = SimpleNamespace(
- defects=Decimal('2.00'),
- _score_fields=lambda: score_fields)
- for field_name in score_fields:
- setattr(sample, field_name, Decimal('8.00'))
+ def test_coffee_cupping_result_score_sums_configured_criteria(self):
+ 'coffee cupping result score sums criteria and subtracts defects'
+ score = SimpleNamespace(subtract_from_score=False)
+ defect = SimpleNamespace(subtract_from_score=True)
+ result = SimpleNamespace(lines=[
+ SimpleNamespace(score=Decimal('8.00'), criterion=score),
+ SimpleNamespace(score=Decimal('8.25'), criterion=score),
+ SimpleNamespace(score=Decimal('2.00'), criterion=defect),
+ ])
self.assertEqual(
- coffee_module.CoffeeSample.get_total_score(sample),
- Decimal('78.00'))
+ coffee_module.CoffeeCuppingResult.get_total_score(result),
+ Decimal('14.25'))
+
+ def test_coffee_cupping_session_counts_requested_cups(self):
+ 'coffee cupping session capacity is based on sample cups'
+ session = SimpleNamespace(cups_per_sample=3)
+ lines = [
+ SimpleNamespace(cups_per_sample=None, session=session),
+ SimpleNamespace(cups_per_sample=4, session=session),
+ ]
+
+ self.assertEqual(
+ coffee_module.CoffeeCuppingSession._total_requested_cups(lines),
+ 7)
+
+ def test_coffee_cupping_session_orders_arabica_before_robusta(self):
+ 'coffee cupping session tasting order keeps robusta last'
+ arabica = SimpleNamespace(
+ id=2,
+ reference='A',
+ get_public_origin=lambda: 'Colombia',
+ get_public_coffee_type=lambda: 'arabica')
+ robusta = SimpleNamespace(
+ id=1,
+ reference='R',
+ get_public_origin=lambda: 'Vietnam',
+ get_public_coffee_type=lambda: 'robusta')
+ lines = [
+ SimpleNamespace(sample=robusta),
+ SimpleNamespace(sample=arabica),
+ ]
+
+ ordered = sorted(
+ lines, key=coffee_module.CoffeeCuppingSession._line_sort_key)
+
+ self.assertEqual([line.sample.reference for line in ordered], ['A', 'R'])
def test_coffee_sample_default_expiry_date_uses_shelf_life(self):
'coffee sample expiry date defaults from request date and shelf life'
diff --git a/modules/purchase_trade/view/coffee_cupping_criterion_form.xml b/modules/purchase_trade/view/coffee_cupping_criterion_form.xml
new file mode 100644
index 0000000..5e14793
--- /dev/null
+++ b/modules/purchase_trade/view/coffee_cupping_criterion_form.xml
@@ -0,0 +1,17 @@
+
+
diff --git a/modules/purchase_trade/view/coffee_cupping_criterion_tree.xml b/modules/purchase_trade/view/coffee_cupping_criterion_tree.xml
new file mode 100644
index 0000000..3fc1d33
--- /dev/null
+++ b/modules/purchase_trade/view/coffee_cupping_criterion_tree.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/modules/purchase_trade/view/coffee_cupping_cup_form.xml b/modules/purchase_trade/view/coffee_cupping_cup_form.xml
new file mode 100644
index 0000000..d52cf50
--- /dev/null
+++ b/modules/purchase_trade/view/coffee_cupping_cup_form.xml
@@ -0,0 +1,18 @@
+
+
diff --git a/modules/purchase_trade/view/coffee_cupping_cup_tree.xml b/modules/purchase_trade/view/coffee_cupping_cup_tree.xml
new file mode 100644
index 0000000..e3eeab2
--- /dev/null
+++ b/modules/purchase_trade/view/coffee_cupping_cup_tree.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/modules/purchase_trade/view/coffee_cupping_result_form.xml b/modules/purchase_trade/view/coffee_cupping_result_form.xml
new file mode 100644
index 0000000..9cc6852
--- /dev/null
+++ b/modules/purchase_trade/view/coffee_cupping_result_form.xml
@@ -0,0 +1,18 @@
+
+
diff --git a/modules/purchase_trade/view/coffee_cupping_result_line_tree.xml b/modules/purchase_trade/view/coffee_cupping_result_line_tree.xml
new file mode 100644
index 0000000..8f14e90
--- /dev/null
+++ b/modules/purchase_trade/view/coffee_cupping_result_line_tree.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/modules/purchase_trade/view/coffee_cupping_result_tree.xml b/modules/purchase_trade/view/coffee_cupping_result_tree.xml
new file mode 100644
index 0000000..3f193de
--- /dev/null
+++ b/modules/purchase_trade/view/coffee_cupping_result_tree.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/modules/purchase_trade/view/coffee_cupping_session_form.xml b/modules/purchase_trade/view/coffee_cupping_session_form.xml
new file mode 100644
index 0000000..adfc3e9
--- /dev/null
+++ b/modules/purchase_trade/view/coffee_cupping_session_form.xml
@@ -0,0 +1,31 @@
+
+
diff --git a/modules/purchase_trade/view/coffee_cupping_session_sample_form.xml b/modules/purchase_trade/view/coffee_cupping_session_sample_form.xml
new file mode 100644
index 0000000..95813a7
--- /dev/null
+++ b/modules/purchase_trade/view/coffee_cupping_session_sample_form.xml
@@ -0,0 +1,26 @@
+
+
diff --git a/modules/purchase_trade/view/coffee_cupping_session_sample_tree.xml b/modules/purchase_trade/view/coffee_cupping_session_sample_tree.xml
new file mode 100644
index 0000000..8ed3f9e
--- /dev/null
+++ b/modules/purchase_trade/view/coffee_cupping_session_sample_tree.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/purchase_trade/view/coffee_cupping_session_tree.xml b/modules/purchase_trade/view/coffee_cupping_session_tree.xml
new file mode 100644
index 0000000..57cc343
--- /dev/null
+++ b/modules/purchase_trade/view/coffee_cupping_session_tree.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/purchase_trade/view/coffee_sample_form.xml b/modules/purchase_trade/view/coffee_sample_form.xml
index 655bb13..1127bee 100644
--- a/modules/purchase_trade/view/coffee_sample_form.xml
+++ b/modules/purchase_trade/view/coffee_sample_form.xml
@@ -28,6 +28,10 @@
+
+
+
+
@@ -61,32 +65,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -95,6 +73,10 @@
+
+
+
diff --git a/modules/purchase_trade/view/coffee_sample_tree.xml b/modules/purchase_trade/view/coffee_sample_tree.xml
index 510a3a0..770e388 100644
--- a/modules/purchase_trade/view/coffee_sample_tree.xml
+++ b/modules/purchase_trade/view/coffee_sample_tree.xml
@@ -6,8 +6,9 @@
+
+
-
diff --git a/modules/purchase_trade/view/configuration_form.xml b/modules/purchase_trade/view/configuration_form.xml
index af617d4..2fa1698 100644
--- a/modules/purchase_trade/view/configuration_form.xml
+++ b/modules/purchase_trade/view/configuration_form.xml
@@ -2,4 +2,6 @@
diff --git a/modules/purchase_trade/view/purchase_line_form.xml b/modules/purchase_trade/view/purchase_line_form.xml
index f3dadb6..49cdd4a 100755
--- a/modules/purchase_trade/view/purchase_line_form.xml
+++ b/modules/purchase_trade/view/purchase_line_form.xml
@@ -134,11 +134,15 @@ this repository contains the full copyright notices and license terms. -->
-
+
+
+
+
diff --git a/modules/purchase_trade/view/sale_line_form.xml b/modules/purchase_trade/view/sale_line_form.xml
index 84af746..ad14a42 100755
--- a/modules/purchase_trade/view/sale_line_form.xml
+++ b/modules/purchase_trade/view/sale_line_form.xml
@@ -127,11 +127,15 @@ this repository contains the full copyright notices and license terms. -->
-
+
+
+
+