-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce new carrier format based on pydantic models.
Implement mondialrelay get_label as an example.
- Loading branch information
1 parent
22adbb0
commit 52aaa6c
Showing
10 changed files
with
559 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .mondialrelay import transporter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# Copyright 2024 Akretion (http://www.akretion.com). | ||
# @author Florian Mounier <[email protected]> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from functools import wraps | ||
import logging | ||
import typing | ||
from ..roulier import factory | ||
from ..exception import InvalidApiInput | ||
|
||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
class MetaTransporter(type): | ||
""" | ||
Metaclass for Transporter classes. | ||
Used to register transporter actions in the roulier factory. | ||
""" | ||
|
||
def __new__(cls, name, bases, dct): | ||
transporter = super().__new__(cls, name, bases, dct) | ||
|
||
name = getattr(transporter, "__key__", transporter.__name__.lower()) | ||
|
||
for key, value in dct.items(): | ||
if getattr(value, "__action__", False): | ||
log.debug(f"Registering {key} for {name}") | ||
factory.register_builder(name, key, transporter) | ||
|
||
return transporter | ||
|
||
|
||
class Transporter(metaclass=MetaTransporter): | ||
""" | ||
Base class for pydantic transporters. | ||
""" | ||
|
||
def __init__(self, carrier_type, action, **kwargs): | ||
"""This is unused, but required by the factory.""" | ||
self.carrier_type = carrier_type | ||
self.action = action | ||
|
||
|
||
def action(f): | ||
""" | ||
Decorator for transporter actions. Use it to register an action in the | ||
factory and to validate input and output data. | ||
The decorated method must have an `input` argument decorated with a type hint | ||
and a return type hint. | ||
Example: | ||
```python | ||
@action | ||
def get_label(self, input: TransporterLabelInput) -> TransporterLabelOutput: | ||
return TransporterLabelOutput.from_response( | ||
self.fetch(input.to_request()) | ||
) | ||
``` | ||
""" | ||
|
||
@wraps(f) | ||
def wrapper(self, carrier_type, action, data): | ||
hints = typing.get_type_hints(f) | ||
if "input" not in hints: | ||
raise ValueError(f"Missing input argument or type hint for {f}") | ||
if "return" not in hints: | ||
raise ValueError(f"Missing return type hint for {f}") | ||
|
||
try: | ||
input = hints["input"](**data) | ||
except Exception as e: | ||
raise InvalidApiInput(f"Invalid input data {data!r}") from e | ||
|
||
rv = f(self, input) | ||
|
||
if isinstance(rv, hints["return"]): | ||
return rv.dict() | ||
|
||
return rv | ||
|
||
# Mark the function as an action for the metaclass | ||
wrapper.__action__ = True | ||
return wrapper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Copyright 2024 Akretion (http://www.akretion.com). | ||
# @author Florian Mounier <[email protected]> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from typing import ClassVar | ||
|
||
REMOVED = ClassVar[None] # Hack to remove a field from inherited class | ||
|
||
|
||
def prefix(data, prefix): | ||
return {f"{prefix}{k}": v for k, v in data.items()} | ||
|
||
|
||
def suffix(data, suffix): | ||
return {f"{k}{suffix}": v for k, v in data.items()} | ||
|
||
|
||
def clean_empty(data): | ||
return {k: v for k, v in data.items() if v is not None and v != ""} | ||
|
||
|
||
def none_as_empty(data): | ||
return {k: v if v is not None else "" for k, v in data.items()} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
STATUSES = { | ||
0: "Opération effectuée avec succès", | ||
1: "Enseigne invalide", | ||
2: "Numéro d'enseigne vide ou inexistant", | ||
3: "Numéro de compte enseigne invalide", | ||
4: "", | ||
5: "Numéro de dossier enseigne invalide", | ||
6: "", | ||
7: "Numéro de client enseigne invalide (champ NCLIENT)", | ||
8: "Mot de passe ou hachage invalide", | ||
9: "Ville non reconnu ou non unique", | ||
10: "Type de collecte invalide", | ||
11: "Numéro de Relais de Collecte invalide", | ||
12: "Pays de Relais de collecte invalide", | ||
13: "Type de livraison invalide", | ||
14: "Numéro de Relais de livraison invalide", | ||
15: "Pays de Relais de livraison invalide", | ||
16: "", | ||
17: "", | ||
18: "", | ||
19: "", | ||
20: "Poids du colis invalide", | ||
21: "Taille (Longueur + Hauteur) du colis invalide", | ||
22: "Taille du Colis invalide", | ||
23: "", | ||
24: "Numéro d'expédition ou de suivi invalide", | ||
25: "", | ||
26: "Temps de montage invalide", | ||
27: "Mode de collecte ou de livraison invalide", | ||
28: "Mode de collecte invalide", | ||
29: "Mode de livraison invalide", | ||
30: "Adresse (L1) invalide", | ||
31: "Adresse (L2) invalide", | ||
32: "", | ||
33: "Adresse (L3) invalide", | ||
34: "Adresse (L4) invalide", | ||
35: "Ville invalide", | ||
36: "Code postal invalide", | ||
37: "Pays invalide", | ||
38: "Numéro de téléphone invalide", | ||
39: "Adresse e-mail invalide", | ||
40: "Paramètres manquants", | ||
41: "", | ||
42: "Montant CRT invalide", | ||
43: "Devise CRT invalide", | ||
44: "Valeur du colis invalide", | ||
45: "Devise de la valeur du colis invalide", | ||
46: "Plage de numéro d'expédition épuisée", | ||
47: "Nombre de colis invalide", | ||
48: "Multi-Colis Relais Interdit", | ||
49: "Action invalide", | ||
50: "", | ||
51: "", | ||
52: "", | ||
53: "", | ||
54: "", | ||
55: "", | ||
56: "", | ||
57: "", | ||
58: "", | ||
59: "", | ||
60: "Champ texte libre invalide (Ce code erreur n'est pas invalidant)", | ||
61: "Top avisage invalide", | ||
62: "Instruction de livraison invalide", | ||
63: "Assurance invalide", | ||
64: "Temps de montage invalide", | ||
65: "Top rendez-vous invalide", | ||
66: "Top reprise invalide", | ||
67: "Latitude invalide", | ||
68: "Longitude invalide", | ||
69: "Code Enseigne invalide", | ||
70: "Numéro de Point Relais invalide", | ||
71: "Nature de point de vente non valide", | ||
72: "", | ||
73: "", | ||
74: "Langue invalide", | ||
75: "", | ||
76: "", | ||
77: "", | ||
78: "Pays de Collecte invalide", | ||
79: "Pays de Livraison invalide", | ||
80: "Code tracing : Colis enregistré", | ||
81: "Code tracing : Colis en traitement chez Mondial Relay", | ||
82: "Code tracing : Colis livré", | ||
83: "Code tracing : Anomalie", | ||
84: "(Réservé Code Tracing)", | ||
85: "(Réservé Code Tracing)", | ||
86: "(Réservé Code Tracing)", | ||
87: "(Réservé Code Tracing)", | ||
88: "(Réservé Code Tracing)", | ||
89: "(Réservé Code Tracing)", | ||
90: "", | ||
91: "", | ||
92: "Le code pays du destinataire et le code pays du Point Relais doivent être identiques ou solde insuffisant (comptes prépayés).", | ||
93: "Aucun élément retourné par le plan de tri. Si vous effectuez une collecte ou une livraison en Point Relais, vérifiez que les Point Relais sont bien disponibles. Si vous effectuez une livraison à domicile, il est probable que le code postal que vous avez indiqué n'existe pas.", | ||
94: "Colis Inexistant", | ||
95: "Compte Enseigne non activé", | ||
96: "Type d'enseigne incorrect en Base", | ||
97: "Clé de sécurité invalide", | ||
98: "Erreur générique (Paramètres invalides)", | ||
99: "Erreur générique du service", | ||
} | ||
|
||
SORTED_KEYS = [ | ||
"Enseigne", | ||
"ModeCol", | ||
"ModeLiv", | ||
"NDossier", | ||
"NClient", | ||
"Expe_Langage", | ||
"Expe_Ad1", | ||
"Expe_Ad2", | ||
"Expe_Ad3", | ||
"Expe_Ad4", | ||
"Expe_Ville", | ||
"Expe_CP", | ||
"Expe_Pays", | ||
"Expe_Tel1", | ||
"Expe_Tel2", | ||
"Expe_Mail", | ||
"Dest_Langage", | ||
"Dest_Ad1", | ||
"Dest_Ad2", | ||
"Dest_Ad3", | ||
"Dest_Ad4", | ||
"Dest_Ville", | ||
"Dest_CP", | ||
"Dest_Pays", | ||
"Dest_Tel1", | ||
"Dest_Tel2", | ||
"Dest_Mail", | ||
"Poids", | ||
"Longueur", | ||
"Taille", | ||
"NbColis", | ||
"CRT_Valeur", | ||
"CRT_Devise", | ||
"Exp_Valeur", | ||
"Exp_Devise", | ||
"COL_Rel_Pays", | ||
"COL_Rel", | ||
"LIV_Rel_Pays", | ||
"LIV_Rel", | ||
"TAvisage", | ||
"TReprise", | ||
"Montage", | ||
"Assurance", | ||
"Instructions", | ||
] |
Oops, something went wrong.