Tried to set hours manually
This commit is contained in:
parent
fd0385d417
commit
4a642fa654
9 changed files with 193 additions and 108 deletions
24
main.py
24
main.py
|
|
@ -204,8 +204,8 @@ def creer_devis(req: DevisRequest):
|
|||
try:
|
||||
devis_data = {
|
||||
"client": {"code": req.client_id, "intitule": ""},
|
||||
"date_devis": req.date_devis or date.today(),
|
||||
"date_livraison": req.date_livraison or date.today(),
|
||||
"date_devis": req.date_devis or datetime.now(),
|
||||
"date_livraison": req.date_livraison or datetime.now(),
|
||||
"reference": req.reference,
|
||||
"lignes": req.lignes,
|
||||
}
|
||||
|
|
@ -687,8 +687,8 @@ def creer_commande_endpoint(req: CommandeCreate):
|
|||
try:
|
||||
commande_data = {
|
||||
"client": {"code": req.client_id, "intitule": ""},
|
||||
"date_commande": req.date_commande or date.today(),
|
||||
"date_livraison": req.date_livraison or date.today(),
|
||||
"date_commande": req.date_commande or datetime.now(),
|
||||
"date_livraison": req.date_livraison or datetime.now(),
|
||||
"reference": req.reference,
|
||||
"lignes": req.lignes,
|
||||
}
|
||||
|
|
@ -727,8 +727,8 @@ def creer_livraison_endpoint(req: LivraisonCreate):
|
|||
|
||||
livraison_data = {
|
||||
"client": {"code": req.client_id, "intitule": ""},
|
||||
"date_livraison": req.date_livraison or date.today(),
|
||||
"date_livraison_prevue": req.date_livraison or date.today(),
|
||||
"date_livraison": req.date_livraison or datetime.now(),
|
||||
"date_livraison_prevue": req.date_livraison or datetime.now(),
|
||||
"reference": req.reference,
|
||||
"lignes": req.lignes,
|
||||
}
|
||||
|
|
@ -767,8 +767,8 @@ def creer_avoir_endpoint(req: AvoirCreate):
|
|||
|
||||
avoir_data = {
|
||||
"client": {"code": req.client_id, "intitule": ""},
|
||||
"date_avoir": req.date_avoir or date.today(),
|
||||
"date_livraison": req.date_livraison or date.today(),
|
||||
"date_avoir": req.date_avoir or datetime.now(),
|
||||
"date_livraison": req.date_livraison or datetime.now(),
|
||||
"reference": req.reference,
|
||||
"lignes": req.lignes,
|
||||
}
|
||||
|
|
@ -810,8 +810,8 @@ def creer_facture_endpoint(req: FactureCreate):
|
|||
|
||||
facture_data = {
|
||||
"client": {"code": req.client_id, "intitule": ""},
|
||||
"date_facture": req.date_facture or date.today(),
|
||||
"date_livraison": req.date_livraison or date.today(),
|
||||
"date_facture": req.date_facture or datetime.now(),
|
||||
"date_livraison": req.date_livraison or datetime.now(),
|
||||
"reference": req.reference,
|
||||
"lignes": req.lignes,
|
||||
}
|
||||
|
|
@ -1177,7 +1177,7 @@ def creer_entree_stock(req: EntreeStock):
|
|||
)
|
||||
|
||||
entree_data = {
|
||||
"date_mouvement": req.date_entree or date.today(),
|
||||
"date_mouvement": req.date_entree or datetime.now(),
|
||||
"reference": req.reference,
|
||||
"depot_code": req.depot_code,
|
||||
"lignes": [ligne.dict() for ligne in req.lignes],
|
||||
|
|
@ -1207,7 +1207,7 @@ def creer_sortie_stock(req: SortieStock):
|
|||
)
|
||||
|
||||
sortie_data = {
|
||||
"date_mouvement": req.date_sortie or date.today(),
|
||||
"date_mouvement": req.date_sortie or datetime.now(),
|
||||
"reference": req.reference,
|
||||
"depot_code": req.depot_code,
|
||||
"lignes": [ligne.dict() for ligne in req.lignes],
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
from pydantic import BaseModel
|
||||
from typing import Optional, List, Dict
|
||||
from datetime import date
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class AvoirCreate(BaseModel):
|
||||
"""Création d'un avoir côté gateway"""
|
||||
|
||||
client_id: str
|
||||
date_avoir: Optional[date] = None
|
||||
date_livraison: Optional[date] = None
|
||||
date_avoir: Optional[datetime] = None
|
||||
date_livraison: Optional[datetime] = None
|
||||
lignes: List[Dict]
|
||||
reference: Optional[str] = None
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
from pydantic import BaseModel
|
||||
from typing import Optional, List, Dict
|
||||
from datetime import date
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class CommandeCreate(BaseModel):
|
||||
"""Création d'une commande"""
|
||||
|
||||
client_id: str
|
||||
date_commande: Optional[date] = None
|
||||
date_livraison: Optional[date] = None
|
||||
date_commande: Optional[datetime] = None
|
||||
date_livraison: Optional[datetime] = None
|
||||
reference: Optional[str] = None
|
||||
lignes: List[Dict]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
from pydantic import BaseModel
|
||||
from typing import Optional, List, Dict
|
||||
from datetime import date
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class DevisRequest(BaseModel):
|
||||
client_id: str
|
||||
date_devis: Optional[date] = None
|
||||
date_livraison: Optional[date] = None
|
||||
date_devis: Optional[datetime] = None
|
||||
date_livraison: Optional[datetime] = None
|
||||
reference: Optional[str] = None
|
||||
lignes: List[Dict]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
from pydantic import BaseModel
|
||||
from typing import Optional, List, Dict
|
||||
from datetime import date
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class FactureCreate(BaseModel):
|
||||
"""Création d'une facture côté gateway"""
|
||||
|
||||
client_id: str
|
||||
date_facture: Optional[date] = None
|
||||
date_livraison: Optional[date] = None
|
||||
date_facture: Optional[datetime] = None
|
||||
date_livraison: Optional[datetime] = None
|
||||
lignes: List[Dict]
|
||||
reference: Optional[str] = None
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
from pydantic import BaseModel
|
||||
from typing import Optional, List, Dict
|
||||
from datetime import date
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class LivraisonCreate(BaseModel):
|
||||
"""Création d'une livraison côté gateway"""
|
||||
|
||||
client_id: str
|
||||
date_livraison: Optional[date] = None
|
||||
date_livraison_prevue: Optional[date] = None
|
||||
date_livraison: Optional[datetime] = None
|
||||
date_livraison_prevue: Optional[datetime] = None
|
||||
lignes: List[Dict]
|
||||
reference: Optional[str] = None
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from utils.functions.functions import (
|
|||
_convertir_type_depuis_sql,
|
||||
_convertir_type_pour_sql,
|
||||
_safe_strip,
|
||||
_combiner_date_heure,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -106,7 +107,8 @@ def _lire_document_sql(cursor, numero: str, type_doc: int):
|
|||
d.DO_Tarif, d.DO_TypeFrais, d.DO_ValFrais,
|
||||
d.DO_TypeFranco, d.DO_ValFranco,
|
||||
c.CT_Intitule, c.CT_Adresse, c.CT_CodePostal,
|
||||
c.CT_Ville, c.CT_Telephone, c.CT_EMail
|
||||
c.CT_Ville, c.CT_Telephone, c.CT_EMail,
|
||||
d.DO_Heure
|
||||
FROM F_DOCENTETE d
|
||||
LEFT JOIN F_COMPTET c ON d.DO_Tiers = c.CT_Num
|
||||
WHERE d.DO_Piece = ? AND d.DO_Type = ?
|
||||
|
|
@ -119,19 +121,19 @@ def _lire_document_sql(cursor, numero: str, type_doc: int):
|
|||
|
||||
if not row:
|
||||
logger.warning(
|
||||
f"[SQL READ] Document {numero} (type={type_doc}) INTROUVABLE dans F_DOCENTETE"
|
||||
f"[SQL READ] Document {numero} (type={type_doc}) INTROUVABLE"
|
||||
)
|
||||
return None
|
||||
|
||||
numero_piece = _safe_strip(row[0])
|
||||
logger.info(f"[SQL READ] Document trouvé: {numero_piece}")
|
||||
logger.info(f"[SQL READ] Document trouvé: {numero_piece}")
|
||||
|
||||
doc = {
|
||||
"numero": numero_piece,
|
||||
"reference": _safe_strip(row[2]),
|
||||
"date": str(row[1]) if row[1] else "",
|
||||
"date_livraison": (str(row[7]) if row[7] else ""),
|
||||
"date_expedition": (str(row[8]) if row[8] else ""),
|
||||
"date": _combiner_date_heure(row[1], row[45]),
|
||||
"date_livraison": str(row[7]) if row[7] else "",
|
||||
"date_expedition": str(row[8]) if row[8] else "",
|
||||
"client_code": _safe_strip(row[6]),
|
||||
"client_intitule": _safe_strip(row[39]),
|
||||
"client_adresse": _safe_strip(row[40]),
|
||||
|
|
@ -144,9 +146,9 @@ def _lire_document_sql(cursor, numero: str, type_doc: int):
|
|||
"total_ht_net": float(row[10]) if row[10] else 0.0,
|
||||
"total_ttc": float(row[4]) if row[4] else 0.0,
|
||||
"net_a_payer": float(row[11]) if row[11] else 0.0,
|
||||
"montant_regle": (float(row[12]) if row[12] else 0.0),
|
||||
"montant_regle": float(row[12]) if row[12] else 0.0,
|
||||
"reliquat": float(row[13]) if row[13] else 0.0,
|
||||
"taux_escompte": (float(row[14]) if row[14] else 0.0),
|
||||
"taux_escompte": float(row[14]) if row[14] else 0.0,
|
||||
"escompte": float(row[15]) if row[15] else 0.0,
|
||||
"taxe1": float(row[16]) if row[16] else 0.0,
|
||||
"taxe2": float(row[17]) if row[17] else 0.0,
|
||||
|
|
@ -155,26 +157,22 @@ def _lire_document_sql(cursor, numero: str, type_doc: int):
|
|||
"code_taxe2": _safe_strip(row[20]),
|
||||
"code_taxe3": _safe_strip(row[21]),
|
||||
"statut": int(row[5]) if row[5] is not None else 0,
|
||||
"statut_estatut": (
|
||||
int(row[22]) if row[22] is not None else 0
|
||||
),
|
||||
"statut_estatut": int(row[22]) if row[22] is not None else 0,
|
||||
"imprime": int(row[23]) if row[23] is not None else 0,
|
||||
"valide": int(row[24]) if row[24] is not None else 0,
|
||||
"cloture": int(row[25]) if row[25] is not None else 0,
|
||||
"transfere": (int(row[26]) if row[26] is not None else 0),
|
||||
"transfere": int(row[26]) if row[26] is not None else 0,
|
||||
"souche": int(row[27]) if row[27] is not None else 0,
|
||||
"piece_origine": _safe_strip(row[28]),
|
||||
"guid": _safe_strip(row[29]),
|
||||
"ca_num": _safe_strip(row[30]),
|
||||
"cg_num": _safe_strip(row[31]),
|
||||
"expedition": (int(row[32]) if row[32] is not None else 1),
|
||||
"condition": (int(row[33]) if row[33] is not None else 1),
|
||||
"expedition": int(row[32]) if row[32] is not None else 1,
|
||||
"condition": int(row[33]) if row[33] is not None else 1,
|
||||
"tarif": int(row[34]) if row[34] is not None else 1,
|
||||
"type_frais": (int(row[35]) if row[35] is not None else 0),
|
||||
"type_frais": int(row[35]) if row[35] is not None else 0,
|
||||
"valeur_frais": float(row[36]) if row[36] else 0.0,
|
||||
"type_franco": (
|
||||
int(row[37]) if row[37] is not None else 0
|
||||
),
|
||||
"type_franco": int(row[37]) if row[37] is not None else 0,
|
||||
"valeur_franco": float(row[38]) if row[38] else 0.0,
|
||||
}
|
||||
|
||||
|
|
@ -386,7 +384,8 @@ def _lister_documents_avec_lignes_sql(
|
|||
d.CA_Num, d.CG_Num, d.DO_Expedit, d.DO_Condition, d.DO_Tarif,
|
||||
d.DO_TypeFrais, d.DO_ValFrais, d.DO_TypeFranco, d.DO_ValFranco,
|
||||
c.CT_Intitule, c.CT_Adresse, c.CT_CodePostal,
|
||||
c.CT_Ville, c.CT_Telephone, c.CT_EMail
|
||||
c.CT_Ville, c.CT_Telephone, c.CT_EMail,
|
||||
d.DO_Heure
|
||||
FROM F_DOCENTETE d
|
||||
LEFT JOIN F_COMPTET c ON d.DO_Tiers = c.CT_Num
|
||||
WHERE d.DO_Type = ?
|
||||
|
|
@ -400,7 +399,7 @@ def _lister_documents_avec_lignes_sql(
|
|||
)
|
||||
params.extend([f"%{filtre}%", f"%{filtre}%", f"%{filtre}%"])
|
||||
|
||||
query += " ORDER BY d.DO_Date DESC"
|
||||
query += " ORDER BY d.DO_Date DESC, d.DO_Heure DESC"
|
||||
|
||||
if limit:
|
||||
query = f"SELECT TOP ({limit}) * FROM ({query}) AS subquery"
|
||||
|
|
@ -455,15 +454,13 @@ def _lister_documents_avec_lignes_sql(
|
|||
"numero": numero,
|
||||
"type": type_doc_depuis_sql,
|
||||
"reference": _safe_strip(entete.DO_Ref),
|
||||
"date": str(entete.DO_Date) if entete.DO_Date else "",
|
||||
"date_livraison": (
|
||||
str(entete.DO_DateLivr) if entete.DO_DateLivr else ""
|
||||
),
|
||||
"date_expedition": (
|
||||
str(entete.DO_DateExpedition)
|
||||
if entete.DO_DateExpedition
|
||||
else ""
|
||||
),
|
||||
"date": _combiner_date_heure(entete.DO_Date, entete.DO_Heure),
|
||||
"date_livraison": str(entete.DO_DateLivr)
|
||||
if entete.DO_DateLivr
|
||||
else "",
|
||||
"date_expedition": str(entete.DO_DateExpedition)
|
||||
if entete.DO_DateExpedition
|
||||
else "",
|
||||
"client_code": _safe_strip(entete.DO_Tiers),
|
||||
"client_intitule": _safe_strip(entete.CT_Intitule),
|
||||
"client_adresse": _safe_strip(entete.CT_Adresse),
|
||||
|
|
|
|||
|
|
@ -47,9 +47,19 @@ def creer_document_vente(
|
|||
logger.info(f"✓ Document {config.nom_document} créé")
|
||||
|
||||
# ===== DATES =====
|
||||
doc.DO_Date = pywintypes.Time(
|
||||
normaliser_date(doc_data.get(config.champ_date_principale))
|
||||
date_principale = normaliser_date(
|
||||
doc_data.get(config.champ_date_principale)
|
||||
)
|
||||
doc.DO_Date = pywintypes.Time(date_principale)
|
||||
|
||||
# Heure - même datetime, Sage extrait la composante horaire
|
||||
try:
|
||||
doc.DO_Heure = pywintypes.Time(date_principale)
|
||||
logger.debug(
|
||||
f"DO_Heure défini: {date_principale.strftime('%H:%M:%S')}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug(f"DO_Heure non défini: {e}")
|
||||
|
||||
# Date secondaire (livraison, etc.)
|
||||
if config.champ_date_secondaire and doc_data.get(
|
||||
|
|
@ -407,10 +417,6 @@ def _relire_document_final(
|
|||
def modifier_document_vente(
|
||||
self, numero: str, doc_data: dict, type_document: TypeDocumentVente
|
||||
) -> Dict:
|
||||
"""
|
||||
Méthode unifiée de modification de documents de vente
|
||||
RÉUTILISE les mêmes sous-méthodes que la création
|
||||
"""
|
||||
if not self.cial:
|
||||
raise RuntimeError("Connexion Sage non établie")
|
||||
|
||||
|
|
@ -546,9 +552,14 @@ def modifier_document_vente(
|
|||
logger.info("📝 Modifications simples...")
|
||||
|
||||
if modif_date:
|
||||
doc.DO_Date = pywintypes.Time(
|
||||
normaliser_date(doc_data_temp.get(config.champ_date_principale))
|
||||
date_principale = normaliser_date(
|
||||
doc_data_temp.get(config.champ_date_principale)
|
||||
)
|
||||
doc.DO_Date = pywintypes.Time(date_principale)
|
||||
try:
|
||||
doc.DO_Heure = pywintypes.Time(date_principale)
|
||||
except Exception:
|
||||
pass
|
||||
champs_modifies.append(config.champ_date_principale)
|
||||
|
||||
if modif_date_sec:
|
||||
|
|
|
|||
|
|
@ -110,20 +110,96 @@ def _normaliser_type_document(type_doc: int) -> int:
|
|||
|
||||
|
||||
def normaliser_date(valeur):
|
||||
if isinstance(valeur, str):
|
||||
try:
|
||||
return datetime.fromisoformat(valeur)
|
||||
except ValueError:
|
||||
return datetime.now()
|
||||
"""Parse flexible des dates - supporte ISO, datetime, YYYY-MM-DD HH:MM:SS"""
|
||||
if valeur is None:
|
||||
return datetime.now()
|
||||
|
||||
elif isinstance(valeur, date):
|
||||
return datetime.combine(valeur, datetime.min.time())
|
||||
|
||||
elif isinstance(valeur, datetime):
|
||||
if isinstance(valeur, datetime):
|
||||
return valeur
|
||||
|
||||
else:
|
||||
return datetime.now()
|
||||
if isinstance(valeur, date):
|
||||
return datetime.combine(valeur, datetime.min.time())
|
||||
|
||||
if isinstance(valeur, str):
|
||||
valeur = valeur.strip()
|
||||
|
||||
if not valeur:
|
||||
return datetime.now()
|
||||
|
||||
if valeur.endswith("Z"):
|
||||
valeur = valeur[:-1] + "+00:00"
|
||||
|
||||
formats = [
|
||||
"%Y-%m-%dT%H:%M:%S.%f%z",
|
||||
"%Y-%m-%dT%H:%M:%S%z",
|
||||
"%Y-%m-%dT%H:%M:%S.%f",
|
||||
"%Y-%m-%dT%H:%M:%S",
|
||||
"%Y-%m-%d %H:%M:%S.%f",
|
||||
"%Y-%m-%d %H:%M:%S",
|
||||
"%Y-%m-%d %H:%M",
|
||||
"%Y-%m-%d",
|
||||
"%d/%m/%Y %H:%M:%S",
|
||||
"%d/%m/%Y %H:%M",
|
||||
"%d/%m/%Y",
|
||||
]
|
||||
|
||||
for fmt in formats:
|
||||
try:
|
||||
dt = datetime.strptime(valeur, fmt)
|
||||
return dt.replace(tzinfo=None) if dt.tzinfo else dt
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
try:
|
||||
if "+" in valeur:
|
||||
valeur = valeur.split("+")[0]
|
||||
dt = datetime.fromisoformat(valeur)
|
||||
return dt.replace(tzinfo=None) if dt.tzinfo else dt
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return datetime.now()
|
||||
|
||||
|
||||
def _parser_heure_sage(do_heure) -> str:
|
||||
"""Parse DO_Heure format Sage (HHMMSS stocké en entier)"""
|
||||
if not do_heure:
|
||||
return "00:00:00"
|
||||
|
||||
try:
|
||||
# Convertir en entier pour éliminer les zéros de padding SQL
|
||||
heure_int = int(str(do_heure).strip())
|
||||
|
||||
# Formatter en string 6 caractères (HHMMSS)
|
||||
heure_str = str(heure_int).zfill(6)
|
||||
|
||||
hh = int(heure_str[0:2])
|
||||
mm = int(heure_str[2:4])
|
||||
ss = int(heure_str[4:6])
|
||||
|
||||
if 0 <= hh <= 23 and 0 <= mm <= 59 and 0 <= ss <= 59:
|
||||
return f"{hh:02d}:{mm:02d}:{ss:02d}"
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
return "00:00:00"
|
||||
|
||||
|
||||
def _combiner_date_heure(do_date, do_heure) -> str:
|
||||
"""Combine DO_Date et DO_Heure en datetime string"""
|
||||
if not do_date:
|
||||
return ""
|
||||
|
||||
try:
|
||||
date_str = (
|
||||
do_date.strftime("%Y-%m-%d")
|
||||
if hasattr(do_date, "strftime")
|
||||
else str(do_date)[:10]
|
||||
)
|
||||
heure_str = _parser_heure_sage(do_heure)
|
||||
return f"{date_str} {heure_str}"
|
||||
except Exception:
|
||||
return str(do_date) if do_date else ""
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
|
@ -136,4 +212,5 @@ __all__ = [
|
|||
"_convertir_type_depuis_sql",
|
||||
"_convertir_type_pour_sql",
|
||||
"normaliser_date",
|
||||
"_combiner_date_heure",
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in a new issue