retrodoc-abap-ia/documentation/documentation_zpayments.prog.md

189 lines
9.2 KiB
Markdown

The user wants me to document the ABAP report ZPAYMENTS in markdown format with specific sections. Let me analyze the code carefully.
# Documentation technique : `ZPAYMENTS`
> **Rapport** : ZPAYMENTS | **Créé le** : 01.01.2016 | **Auteur** : Hifzulla.A (I065658)
> **Objectif** : Automatiser le paiement des fournisseurs (Vendor Payments) en appliquant des règles métier sur les postes ouverts comptables.
---
# Algorithmie
Le programme implémente un moteur de paiement automatique des fournisseurs en plusieurs phases :
1. **Chargement des règles de paiement** : lecture de la table custom `ZPAYMENTRULES` qui définit la liste des fournisseurs éligibles et leurs paramètres (notamment `dayslate`).
2. **Extraction des postes ouverts** : sélection dans `BSIK` (postes fournisseurs ouverts) des documents de type `RE` (facture) et `KR` (avoir crédit) pour tous les fournisseurs présents dans les règles.
3. **Calcul de la date et du montant de paiement** : pour chaque poste ouvert, le programme détermine la date de paiement et le montant à payer selon deux logiques :
- **Sans escompte** (`zbd1p` vide ou nul) : date = date de base + délai net + jours de retard autorisés.
- **Avec escompte** : selon le nombre de niveaux d'escompte (`zbd2t`, `zbd3t`), le programme compare la date du jour à la date d'escompte :
- Si on est exactement à la date d'escompte : paiement avec déduction du taux d'escompte.
- Sinon : paiement au net.
- Si `dayslate` est renseigné : paiement forcé au net avec ajout des jours de retard sur la date nette.
4. **Filtrage des documents annulés** : élimination des paires de documents `H` (original) / `S` (contrepassation) pour ne pas payer des factures déjà annulées.
5. **Posting des paiements** : appel de la fonction `ZFI_OUT_PAYMENT_POST_CLEAR` pour chaque paiement à effectuer, avec détermination dynamique de la banque (`HBKID`/`HKTID`) selon la société (`BUKRS`).
6. **Journalisation** : chaque tentative de paiement (succès ou échec) est tracée dans la table `ZPAYMENTSLOG`.
7. **Envoi d'un email de synthèse** : un mail HTML récapitulatif est envoyé en fin d'exécution via `SO_NEW_DOCUMENT_SEND_API1`.
---
# Objets
## Tables de base de données
| Objet | Type | Rôle |
|---|---|---|
| `ZPAYMENTRULES` | Table custom Z | Référentiel des fournisseurs éligibles au paiement automatique, avec paramètres (`dayslate`, etc.) |
| `BSIK` | Table SAP standard | Postes comptables fournisseurs **ouverts** (source des factures à payer) |
| `ZPAYMENTSLOG` | Table custom Z | Journal des paiements exécutés (succès / erreurs) |
| `T052` | Table SAP standard | Table des conditions de paiement (déclarée mais non exploitée directement dans le code visible) |
## Structures et types locaux
| Objet | Rôle |
|---|---|
| `ty_lifnr` | Type simple pour stocker un numéro de fournisseur |
| `ty_paymentdata` | Type local de données de paiement (remplacé dans la pratique par `zpayments_data_s`) |
| `zpayments_data_s` | Structure custom principale transportant les données de paiement enrichies (`new_dateofpayment`, `new_wrbtr`, etc.) |
## Tables internes principales
| Variable | Rôle |
|---|---|
| `lt_zpaymentrules` / `ls_zpaymentrules` | Règles de paiement chargées depuis `ZPAYMENTRULES` |
| `iv_lt_bsik` / `iv_ls_bsik` | Postes ouverts bruts issus de `BSIK` |
| `lt_payment_data` / `ls_payment_data` | Postes filtrés et enrichis avec les dates/montants de paiement calculés |
| `lt_payment_reversals` / `ls_payment_reversals` | Postes de contrepassation isolés pour nettoyage |
| `lt_payment_data_temp` / `ls_payment_data_temp` | Copie de travail pour la boucle de posting |
| `lt_paymentslog` / `ls_paymentslog` | Journal des résultats de paiement |
## Variables de pilotage
| Variable | Rôle |
|---|---|
| `for_date` | Paramètre de sélection : date de traitement (défaut = date du jour) |
| `bukrs` | Paramètre de sélection : société (défaut = `1710`) |
| `no_data` | Flag indiquant l'absence de données à traiter |
| `lv_hbkid` / `lv_hktid` | Identifiants de la banque utilisée pour le paiement, déterminés par société |
## Fonction externe
| Fonction | Rôle |
|---|---|
| `ZFI_OUT_PAYMENT_POST_CLEAR` | Fonction custom Z qui comptabilise et solde le paiement fournisseur |
| `SO_NEW_DOCUMENT_SEND_API1` | Fonction SAP standard d'envoi d'email via SAPoffice/SMTP |
---
# Dépendances
## Dépendances fonctionnelles critiques
```
ZPAYMENTS
├── ZPAYMENTRULES (table de configuration : fournisseurs éligibles)
├── BSIK (postes ouverts fournisseurs, source de données)
├── ZPAYMENTSLOG (table de log, mise à jour via MODIFY)
├── ZPAYMENTS_DATA_S (structure de données intermédiaire)
├── ZFI_OUT_PAYMENT_POST_CLEAR (module fonction de posting/clearing)
│ └── Dépend de la config bancaire (HBKID/HKTID par société)
└── SO_NEW_DOCUMENT_SEND_API1 (envoi email SAPoffice)
```
## Dépendances par société (mapping banque)
| `BUKRS` | `HBKID` | `HKTID` |
|---|---|---|
| `1710` | `USBK1` | `USAC1` |
| `AUC1` | `AUCBK` | `AUCAC` |
| `DEC1` | `DECBK` | `DECAC` |
| `USC1` | `USCBK` | `USCAC` |
> Toute nouvelle société nécessite un ajout dans le code source.
## Dépendances de configuration
- La table `ZPAYMENTRULES` doit être alimentée pour que le programme fonctionne.
- Le fournisseur `USSU_V8000` est **exclu en dur** du traitement.
- La fonction `ZFI_OUT_PAYMENT_POST_CLEAR` doit exister et être fonctionnelle.
- Le groupe de fonctions `ZFGPAYMENTRULES` gère la vue de maintenance de `ZPAYMENTRULES`.
---
# Flux de traitement
````
[DÉBUT]
├─► Affichage heure de démarrage (sy-uzeit)
├─► SELECT * FROM ZPAYMENTRULES → lt_zpaymentrules
│ └─► Exclusion forcée du fournisseur USSU_V8000
├─► [SI lt_zpaymentrules vide] → Message + RETURN
├─► SELECT FROM BSIK (blart = RE ou KR)
│ └─► Pour tous les fournisseurs de lt_zpaymentrules
│ └─► Filtre : zfbdt <= sy-datum (postes dont la date de base est passée)
├─► [SI BSIK vide] → Message "No records"
├─► LOOP sur iv_lt_bsik
│ ├─► Cas SANS escompte (zbd1p = 0)
│ │ └─► new_dateofpayment = zfbdt + zbd1t + dayslate
│ │ └─► new_wrbtr = wrbtr (montant plein)
│ │
│ └─► Cas AVEC escompte
│ ├─► dayslate = 0 : respect strict des termes de paiement
│ │ ├─► 1 niveau d'escompte : si date = lv_discount_date1 → paiement escompté
│ │ │ sinon → paiement net
│ │ └─► 2 niveaux d'escompte : comparaison date1 puis date2
│ │ sinon → paiement net
│ └─► dayslate > 0 : paiement net + décalage dayslate
├─► DELETE lt_payment_data WHERE new_dateofpayment > for_date
├─► Nettoyage des contrepassations (shkzg H/S)
│ └─► Suppression des paires original/contrepassation de lt_payment_data
├─► [SI lt_payment_data vide] → no_data = 'X'
├─► LOOP sur lt_payment_data_temp (= postes à payer)
│ ├─► Détermination HBKID/HKTID selon BUKRS
│ ├─► CALL FUNCTION ZFI_OUT_PAYMENT_POST_CLEAR
│ ├─► [SI ex_belnr renseigné] → log Succès
│ └─► [SINON] → log Erreur
├─► MODIFY ZPAYMENTSLOG FROM TABLE lt_paymentslog
├─► PERFORM send_mail
│ ├─► Construction du corps HTML (résumé statistiques + détails)
│ ├─► Listing des erreurs puis des succès
│ └─► CALL FUNCTION SO_NEW_DOCUMENT_SEND_API1
└─► Affichage heure de fin
[FIN]
````
---
# Points d'attention
## Risques techniques
| # | Risque | Description |
|---|---|---|
| 1 | **Exclusion fournisseur en dur** | `DELETE lt_zpaymentrules WHERE lifnr EQ 'USSU_V8000'` est codé en dur. Toute évolution de cette liste nécessite une modification du programme. |
| 2 | **Mapping banque en dur** | L'association `BUKRS` -> `HBKID`/`HKTID` est dans un `IF/ELSEIF` statique. L'ajout d'une nouvelle société impose une modification de code. |
| 3 | **Compte GL en dur** | `im_hkont = '0011001000'` est passé en dur à la fonction de clearing. Aucune paramétrage externe n'est prévu. |
| 4 | **Variable `bukrs` shadowing** | Le filtre `DELETE iv_lt_bsik WHERE bukrs NE bukrs` compare le champ `bukrs` de la table interne avec lui-même (même nom que le paramètre de sélection). Cette condition ne filtre **jamais** rien et est probablement un bug. |
| 5 | **Données locales déclarées dans une boucle** | `DATA: lv_discount_date1, lv_discount_date2, lv_net_date, lv_discount_levels` sont déclarés à l'intérieur d'un `LOOP`. En ABAP classique, cela est toléré syntaxiquement mais contraire aux bonnes pratiques et peut induire des comportements inattendus si la variable n'est pas correctement réinitialisée. |
| 6 | **Absence de gestion d'erreur sur Z