Finance
Screen specifications RA-29 to RA-31 of the reseller app — balance and credit, invoices and credit notes with PDFs, payments and the declaration of a transfer, CCP or BaridiMob payment with proof.
Cahier §4.7: invoices, receipts, credit notes and payment history; payment on delivery, transfer, CCP, BaridiMob or credit; credit ceiling, available credit, due dates and blocking. The reseller app shows the reseller's own figures (FIN-10) and lets them declare a payment with proof for HOCO's finance team to verify (FIN-03). Designed on day 9, built in MRA-07; server side in SRV-18. Financial data is strictly limited to its owner (ACL-04).
| ID | Screen | UI title | Section | Release | Design | Build |
|---|---|---|---|---|---|---|
RA-29 | Balance & credit | Solde et crédit | Finance | V1 | Day 9 | MRA-07 |
RA-30 | Invoices | Factures | Finance | V1 | Day 9 | MRA-07 |
RA-31 | Payments & payment declaration | Paiements | Finance | V1 | Day 9 | MRA-07 |
Who sees what. Guests: nothing (the Compte tab shows the sign-up prompt). PENDING_VALIDATION: the screens open read-only (they are usually empty) and payment declaration is refused (403 ACCOUNT_PENDING_VALIDATION). Active resellers: everything — including a reseller whose lifecycle status is Suspendu, who must still be able to pay.
How money moves (for the copy). HOCO issues the invoice when the order ships (default). Cash on delivery is collected by the driver and recorded by HOCO. Transfer, CCP and BaridiMob payments are made by the reseller after HOCO confirms the order, then declared in the app with a proof; finance verifies each declaration in BO-45 and allocates it to invoices. A declaration changes nothing to the balance until it is Confirmé. Credit notes (avoirs) from returns and after-sales reduce what is due (FIN-08).
RA-29 — Balance & credit
| Field | Value |
|---|---|
| Screen | Balance & credit · Finance |
| French title | Solde et crédit |
| Release | V1 |
| Design day | Day 9 — DES-09 |
| Build task | MRA-07 |
| Requirements | FIN-05 · FIN-10 |
| Reference screen | None — follow the design system |
Purpose — Answer « how much do I owe, by when, and how much can I still order on credit? » in one screen (FIN-05, FIN-10).
Entry points & exits — Account tiles of RA-09, the finance section of RA-27, /finance. Exits to RA-30, RA-31 (list and « Déclarer un paiement »).
Layout
AppBar« Solde et crédit ».- Balance card: « Solde à payer » with the amount, large; under it, in danger tone, « dont en retard : 12 000,00 DA » when overdue invoices exist; « Prochaine échéance : 30 nov. 2026 — 25 000,00 DA ».
- Credit card (only with a credit account): « Plafond de crédit 300 000,00 DA », « Utilisé 50 000,00 DA », « Disponible 250 000,00 DA », and a progress bar (used / ceiling). Blocked: danger state « Crédit bloqué — contactez le service finance. »
- Declarations line: « 2 paiements en cours de vérification — 35 000,00 DA » → RA-31 filtered À vérifier.
- Credit notes line, when available: « Avoirs disponibles : 4 500,00 DA » → RA-30 tab Avoirs.
- Actions: primary « Déclarer un paiement »;
ListRow« Mes factures », « Mes paiements ». - Help text: « Le crédit disponible diminue avec chaque commande payée à crédit et se libère quand vos paiements sont confirmés par HOCO. »
Data
| Shown | Source |
|---|---|
| Balance, overdue, next due date | finance.summary → balanceDue, overdueAmount, nextDue.date, nextDue.amount |
| Credit | finance.summary → creditLimit, creditUsed, creditAvailable, blocked (a limit of 0 means no credit line) |
| Declarations under verification | finance.summary → pendingDeclarations.count, pendingDeclarations.amount |
| Credit notes | finance.summary → creditNotesAvailable (Assumption — field to add with V1 credit notes) |
Actions — Pull-to-refresh; « Déclarer un paiement » → RA-31 form (pending accounts: hidden).
Rules — Available credit = ceiling − used (FIN-05); used credit counts unpaid credit orders and invoices; it is checked at checkout (RA-18). Overdue is set by the daily job when a due date passes with a balance (En retard (OVERDUE)). Detailed credit terms and automatic blocking are V2 (FIN-06).
States — Loading: card skeletons. No credit account: the credit card becomes « Paiement à crédit non activé. Contactez HOCO pour en bénéficier. » (muted). Nothing due: success state « Vous êtes à jour ». Offline: cached figures with « données du … ». Error: ErrorState.
Copy — « Solde et crédit » · « Solde à payer » · « dont en retard : {amount} » · « Prochaine échéance : {date} — {amount} » · « Plafond de crédit » · « Utilisé » · « Disponible » · « Crédit bloqué — contactez le service finance. » · « {count} paiements en cours de vérification — {amount} » · « Avoirs disponibles : {amount} » · « Déclarer un paiement » · « Mes factures » · « Mes paiements » · « Vous êtes à jour ».
Analytics — finance_viewed with hasCredit, hasOverdue.
Acceptance criteria
- Balance, ceiling, used and available credit equal the back-office credit account (BO-46) at the same moment.
- A confirmed payment lowers the balance (and frees credit) at the next refresh; a declaration under verification does not.
- Without a credit account, no credit figure is shown.
RA-30 — Invoices
| Field | Value |
|---|---|
| Screen | Invoices · Finance |
| French title | Factures |
| Release | V1 |
| Design day | Day 9 — DES-09 |
| Build task | MRA-07 |
| Requirements | FIN-01 · FIN-10 |
| Reference screen | None — follow the design system |
Purpose — List the reseller's invoices and credit notes, show what is paid and what remains, and give the PDFs (FIN-01, FIN-08, FIN-10).
Entry points & exits — « Mes factures » on RA-29 and RA-27, the invoice row of RA-22, notification invoice.issued, /finance/invoices/{invoiceId}. Exits to the invoice detail (same screen, pushed view), RA-22 (linked order), RA-31 (declare for this invoice), the PDF viewer.
Layout — list
AppBar« Factures ».Tabs« Factures » · « Avoirs ».- Status chips (invoices): « Toutes », Impayée, Partiellement payée, En retard, Payée, Annulée.
- Invoice rows: number « FAC-2026-000123 », issue date, order « CMD-2026-000158 », total TTC, « Reste 10 350,00 DA »,
StatusBadge, due date « Échéance 30 nov. » (danger when overdue). - Credit-note rows: number, date, origin (« Retour RET-2026-000012 », « SAV TKT-2026-000045 »), amount, PDF icon.
Layout — invoice detail
- Header: number,
StatusBadge, « Émise le 14 nov. 2026 », « Échéance le 30 nov. 2026 ». - Amounts: « Total HT », « TVA », « Total TTC », « Déjà payé », « Reste à payer » (large).
- « Paiements affectés »: rows « PAY-2026-000077 — 15 nov. — Virement bancaire — 5 000,00 DA » with the payment status.
- « Commande »: link to RA-22.
- Buttons: « Télécharger la facture (PDF) »; « Déclarer un paiement » (when something remains and the account is active) → RA-31 prefilled with this invoice and the remaining amount.
Data
| Shown | Source |
|---|---|
| Invoices | invoices.list ?status=&cursor= → items[].id, number, issuedAt, dueDate, order.id, order.number, totalTtc, amountPaid, amountDue, status |
| Invoice detail | invoices.get → totals (ht, vat, ttc), payments[] (paymentId, number, paidAt, method, amountAllocated, status), pdf.url, pdf.expiresAt |
| Credit notes | Assumption — a reseller list of credit notes (creditNotes.list, or invoices.list?kind=CREDIT_NOTE) is needed for the Avoirs tab; until it exists, credit notes are reached from their return (RA-40) or claim (RA-34) |
Actions — Row → detail. PDF → signed URL valid 5 minutes (requested at every tap, never cached), downloaded and opened in the PDF viewer with « Partager ». Pull-to-refresh.
Rules — Invoices carry the legal mentions (NIF, NIS, RC, AI, VAT) in the PDF (FIN-01, template DQA-09). An issued invoice is never edited; a correction is a cancellation or a credit note. Cancelled invoices stay visible.
States — Loading: row skeletons. Empty: « Aucune facture pour le moment. Les factures sont émises à l'expédition de vos commandes. » Error: ErrorState. PDF failure: snackbar « Téléchargement impossible. Réessayez. » Offline: cached list; PDFs unavailable.
Copy — « Factures » · « Avoirs » · « Toutes » · « Échéance {date} » · « Reste {amount} » · « Émise le {date} » · « Total HT » · « TVA » · « Total TTC » · « Déjà payé » · « Reste à payer » · « Paiements affectés » · « Télécharger la facture (PDF) » · « Déclarer un paiement » · « Aucune facture pour le moment. Les factures sont émises à l'expédition de vos commandes. »
Analytics — invoices_viewed with filter; invoice_viewed with status; invoice_pdf_downloaded; credit_note_pdf_downloaded.
Acceptance criteria
- Each invoice's remaining amount equals total TTC minus confirmed allocated payments.
- The PDF opens with the same number and amounts as the screen.
- Overdue invoices are marked in danger tone with their due date.
RA-31 — Payments & payment declaration
| Field | Value |
|---|---|
| Screen | Payments & payment declaration · Finance |
| French title | Paiements |
| Release | V1 |
| Design day | Day 9 — DES-09 |
| Build task | MRA-07 |
| Requirements | FIN-02 · FIN-03 |
| Reference screen | None — follow the design system |
Purpose — Show every payment of the shop — declared by the reseller or recorded by HOCO — with its verification status, and let the reseller declare a transfer, CCP or BaridiMob payment with its proof so that HOCO can confirm and allocate it (FIN-02, FIN-03).
Entry points & exits — « Mes paiements » and « Déclarer un paiement » on RA-29; « Déclarer un paiement » on RA-22 and the invoice detail of RA-30; pushes payment.confirmed (also when HOCO records a payment) and payment.rejected; /finance/payments, /finance/payments/declare?invoiceId=&orderId=. Exits to the payment detail, the declaration form, RA-30, back.
Layout — list
AppBar« Paiements » and the primary button « Déclarer un paiement » (top of the list, full width).- Status chips: « Tous », À vérifier, Confirmé, Rejeté.
- Payment rows: number « PAY-2026-000077 », date paid, method label, amount,
StatusBadge, source (« Déclaré par vous » or « Enregistré par HOCO » — cash collected at delivery), allocation (« FAC-2026-000123 » or « Non affecté »). Rejected rows show the reason in one line.
Layout — payment detail (BottomSheet, full height): every field above, the reference, the comment, the proof thumbnail (tap to open), a small timeline (« Déclaré le … », « Confirmé par HOCO le … » or « Rejeté le … — Motif : … »), and for a rejected declaration « Déclarer à nouveau » (form prefilled from it, without the proof).
Layout — declaration form (full screen, bottom navigation hidden):
AppBar« Déclarer un paiement ».- « Mode de paiement » — three
RadioCard: Virement bancaire, CCP, BaridiMob (cash on delivery and credit are never declared). - « Coordonnées HOCO » card for the chosen method, each value with a copy icon: account holder and bank RIB (transfer); CCP account number and key (CCP); RIP (BaridiMob).
TextField« Montant (DA) » — numeric keyboard, formatted as typed (« 25 000,00 »).- Date picker « Date du paiement » — default today.
TextField« Référence de l'opération (facultatif) » — helper « Numéro de virement, de reçu CCP ou de transaction BaridiMob ».- « Factures concernées (facultatif) » — multi-select list of unpaid invoices with their remaining amounts (prefilled when coming from an invoice); the sum of the selected remainders is shown; when coming from an order without invoice yet, the order number is shown instead.
- « Justificatif » —
Uploaderwith two buttons « Prendre une photo » and « Choisir un fichier » (image or PDF); preview with « Remplacer » and « Supprimer »; upload progress bar. TextField« Commentaire (facultatif) », 300 characters.StickyFooter: primary « Envoyer la déclaration ».
Data
| Shown or used | Source |
|---|---|
| Payments | payments.list ?status=&cursor= → items[].id, number, method, amount, paidAt, declaredAt, status (PaymentStatus), source (RESELLER, BACK_OFFICE), reference, comment, invoices[] (id, number, amountAllocated), rejectionReason, proof (FileRef) |
| HOCO's payment details | finance.summary → paymentInstructions[] (method, beneficiary, bankName, rib, ccpNumber, ccpKey, rip) — Assumption, field to add; values set in the back-office settings |
| Unpaid invoices | invoices.list ?status=UNPAID&status=PARTIALLY_PAID&status=OVERDUE → items[].id, number, amountDue, dueDate |
| Upload | files.createUpload → fileId, uploadUrl, headers, expiresAt; files.completeUpload → FileRef |
| Result | payments.declare → id, number, status |
Actions — declaring
- As soon as a proof is picked, the app compresses an image (longest side 2 000 px, JPEG quality 80, EXIF removed) and starts the upload in the background:
files.createUpload{ purpose: "PAYMENT_PROOF", mimeType, size, fileName }with anIdempotency-Key→PUTto the pre-signed URL (valid 10 minutes) with progress →files.completeUploadwith anIdempotency-Key. - « Envoyer la déclaration » (enabled when method, amount, date and a completed proof are present) →
payments.declare{ method, amount, paidAt, reference?, invoiceIds?, orderId?, proofFileId, comment? }with anIdempotency-Keykept until success (a retry never creates a second declaration). - Success: confirmation screen « Déclaration envoyée — PAY-2026-000078. Le service finance va vérifier votre paiement. Statut : À vérifier. » with « Voir mes paiements »; the new row appears first in the list.
- The form is kept as a draft on the device (fields and the local file path) until it is sent, so a phone call or an app switch loses nothing.
Rules
- Declarable methods: transfer, CCP, BaridiMob (FIN-02). The proof is required; files are private (
PAYMENT_PROOF, 10 MB at most, JPEG, PNG or PDF) and read only through signed URLs (SEC-04). - Amount above 0; date not in the future and not older than 90 days (Assumption).
- A declared amount above the balance due is allowed with the warning « Le montant dépasse votre solde à payer (12 000,00 DA). » (advance payment); finance decides the allocation (FIN-04).
- A declaration cannot be edited or deleted after sending in V1; a mistake goes through support or a new declaration after rejection.
- Verification is done by finance in BO-45: Confirmé (balance and credit updated) or Rejeté with a reason from
PAYMENT_REJECT_REASON(« Justificatif illisible », « Montant différent », « Paiement introuvable »…); the reseller is notified either way. - Payments recorded by HOCO (cash at delivery, payment at the office) appear with the source « Enregistré par HOCO ».
- PENDING_VALIDATION accounts cannot declare (
403 ACCOUNT_PENDING_VALIDATION).
States
| Situation | Message or behaviour |
|---|---|
| List loading | Row skeletons |
| No payment yet | « Aucun paiement enregistré. » with « Déclarer un paiement » |
| Upload in progress | Progress bar on the preview; the submit button waits (« Envoi du justificatif… ») |
| Upload failed or URL expired | « L'envoi du justificatif a échoué. » with « Réessayer » (a new upload is requested) |
422 FILE_TOO_LARGE · 422 FILE_TYPE_NOT_ALLOWED (on files.completeUpload) | « Fichier trop lourd (10 Mo maximum). » · « Format non accepté : photo (JPEG, PNG) ou PDF. » |
400 VALIDATION_FAILED | Messages under the fields (« Montant invalide », « La date ne peut pas être dans le futur ») |
409 PAYMENT_REFERENCE_ALREADY_DECLARED (Assumption) | « Cette référence a déjà été déclarée (PAY-2026-000077). » |
403 ACCOUNT_PENDING_VALIDATION | « Votre compte doit être validé avant de déclarer un paiement. » |
| Offline | List cached; the form stays fillable as a draft, « Envoyer » disabled with « Connexion requise pour envoyer la déclaration » |
Copy
| Key | French |
|---|---|
| List | « Paiements » · « Déclarer un paiement » · « Tous » · « À vérifier » · « Confirmé » · « Rejeté » · « Déclaré par vous » · « Enregistré par HOCO » · « Non affecté » |
| Form | « Mode de paiement » · « Coordonnées HOCO » · « Montant (DA) » · « Date du paiement » · « Référence de l'opération (facultatif) » · « Numéro de virement, de reçu CCP ou de transaction BaridiMob » · « Factures concernées (facultatif) » · « Justificatif » · « Prendre une photo » · « Choisir un fichier » · « Commentaire (facultatif) » · « Envoyer la déclaration » |
| Success | « Déclaration envoyée — {number}. Le service finance va vérifier votre paiement. Statut : À vérifier. » |
| Rejected | « Rejeté le {date} — Motif : {reason} » · « Déclarer à nouveau » |
Analytics — payment_declaration_started with source; payment_proof_uploaded with sizeKb, mimeType, ms; payment_declared with method, amount, invoiceCount; payment_declaration_failed with code.
Acceptance criteria
- A declaration with a photo proof reaches BO-45 with status À vérifier, the proof viewable, the amount, date, method and selected invoices.
- Retrying after a network failure never creates two declarations.
- When finance rejects it, the reseller receives a notification and sees the reason; « Déclarer à nouveau » prefills the form.
- A confirmed payment shows its allocation to invoices and lowers the balance on RA-29.
Promotions
Screen specifications RA-24 and RA-25 of the reseller app — daily offers with countdown, the list of promotions targeting the reseller, and a promotion's conditions and eligible products.
Account & support
Screen specifications RA-26 to RA-28 and RA-32 to RA-35 of the reseller app — notifications and announcements, account hub, store profile and documents, support with regional WhatsApp, tickets and after-sales claims, conversation, and settings.