FSD-12, Placement (DAT term-deposit savings)¶
1. Purpose¶
Placement lets a customer open a term deposit (a DAT, dépôt à terme) from the wallet, hold it for a fixed term, and receive at maturity the principal back plus the return earned. The customer opens a deposit in one short flow: a single screen takes the amount and the term and validates both, a recap then shows the rate and the projected return, the customer accepts the terms and conditions, and the wallet is debited once into the savings pool. The customer is debited only at opening. At maturity the customer is paid back the principal plus the earned return, with the tax on the return withheld at source, so the principal comes back in full and the return arrives net of tax. The return is paid as a wallet credit, never a second debit.
2. Open a placement¶
The customer opens Savings, picks the product, then opens the deposit in one short flow. The amount and the term are taken on the first screen and both are validated there. A recap shows the rate and the projected return. The customer accepts the terms and conditions. The wallet is debited once and the deposit opens.
Screen by screen.
- Amount and term. One screen takes the amount to place and the term, and validates both. The amount field carries the currency (929) and the description Le montant minimum est de {min} MRU. The amount is checked against the product minimum and the per-customer and per-product caps. The term is picked from the published list, each shown as {n} Mois (for example 6 Mois, 12 Mois, 24 Mois, 36 Mois). What comes back: the amount accepted and the term accepted, or a validation message (amount below the minimum, amount over a cap, no term picked). Real labels: Saisir le montant, Choisir la durée.
- Recap. A read-only recap comes back: Montant (the amount), Date debut and Date fin (the start and the maturity date), Taux d'intérêts (the rate for that product and term, percent), Montant des intérêts (the projected return, net of the tax at source), and Type de placement. The return shown is the net the customer will receive. Real label: Récapitulatif.
- Terms and conditions. The deposit terms and conditions, accepted with a yes or no field. The customer accepts. Real label: CONDITIONS SPECIFIQUES DU COMPTE D'INVESTISSEMENT PARTICIPATIF NON RESTREINT (CIPNR).
- Create. The amount to debit is presented, the customer confirms and enters the PIN, the wallet is debited once for the placed amount, and the deposit is created with its contract reference (the DAT reference). On the debit settling, the placed amount is moved into the savings pool and the deposit is opened. The receipt comes back: Votre placement a été effectué, with the DAT reference, the placed amount, the product, the term, and the maturity date.
Open request (the single wallet debit, carrying the amount and the term, the savings collection as the credited party).
{
"msisdn": "+222 45 67 89 01",
"amount": 50000,
"currency": "929",
"product": "ISLAMIQUE",
"term": "12",
"rate": "4",
"externalReferenceId": "DAT-1000042"
}
Open response.
{
"transactionId": "TXN-778102",
"status": "completed",
"reference": "DAT-1000042",
"product": "ISLAMIQUE",
"amount": 50000,
"term": "12",
"rate": "4",
"maturityDate": "2027-06-30"
}
Funding posting (on create, after the debit settles, the savings collection account to the savings pool account, an account-to-account adjustment, value in centimes, currency 929). The deposit then moves to open.
{
"srcAccount": "SAVINGS-COLLECTION",
"dstAccount": "SAVINGS-POOL",
"amount": { "value": 5000000, "currency": "929", "display": "50000 MRU" },
"reconciliationReference": "FUNDING",
"externalReference": "DAT-1000042",
"entryType": "TRANSFER"
}
sequenceDiagram
participant Cust as Customer
participant BMCI as BMCI integration
participant Mob as Wallet (Mobiquity)
Cust->>BMCI: amount and term (one screen)
BMCI->>BMCI: validate amount (minimum, caps) and term
BMCI-->>Cust: recap (rate, maturity date, net return)
Cust->>BMCI: accept terms and conditions
Cust->>Mob: confirm, enter PIN
Mob-->>Cust: single wallet debit into savings collection
Mob-->>BMCI: debit confirmed (payment ref, DAT ref)
BMCI->>Mob: adjustment create, collection to pool
Mob-->>BMCI: pending (id)
BMCI->>Mob: adjustment validate (action VALIDATE)
Mob-->>BMCI: committed, deposit open
BMCI-->>Cust: confirmation (DAT ref, amount, term, maturity date)
3. Maturity (échéance)¶
At the end of the term the deposit matures and the customer is paid back, with no screen open. This is not customer-driven, it is a scheduled run on the BMCI side and exposes no Comviva API. The engine computes the gross return (the placed amount times the term rate, prorated over the days held), the tax withheld at source (a percentage of the gross), and the net return (gross minus tax). It then posts three account-to-account adjustments: the principal back to the customer wallet, the tax to the tax-at-source account, and the net return to the customer wallet. The deposit closes only when all three are committed. A leg already committed is not re-posted on a retry, so a re-run completes only the outstanding legs. The customer receives the principal in full and the return net of tax in the same maturity event.
Maturity posting (the three adjustment shapes, by account role, value in centimes, currency 929). The principal and the net return both name the customer by MSISDN as the destination, which the platform resolves to the wallet account.
{ "srcAccount": "SAVINGS-POOL", "dstAccount": "+222 45 67 89 01", "amount": { "value": 5000000, "currency": "929", "display": "50000 MRU" }, "reconciliationReference": "MATURITY_PRINCIPAL", "externalReference": "DAT-1000042", "entryType": "TRANSFER" }
{ "srcAccount": "CHARGE-ACCOUNT", "dstAccount": "TAX-AT-SOURCE", "amount": { "value": 20000, "currency": "929", "display": "200 MRU" }, "reconciliationReference": "MATURITY_TAX", "externalReference": "DAT-1000042", "entryType": "TRANSFER" }
{ "srcAccount": "CHARGE-ACCOUNT", "dstAccount": "+222 45 67 89 01", "amount": { "value": 180000, "currency": "929", "display": "1800 MRU" }, "reconciliationReference": "MATURITY_RETURN", "externalReference": "DAT-1000042", "entryType": "TRANSFER" }
Each adjustment validate returns the committed status and the resolved destination account.
{ "success": true, "data": { "id": 880145, "status": "VALIDATED", "destinationAccountNumber": "WALLET-ACCT", "reconciliationReference": "MATURITY_PRINCIPAL", "externalReference": "DAT-1000042" } }
sequenceDiagram
participant Sched as Scheduler (BMCI)
participant BMCI as BMCI integration
participant Mob as Wallet (Mobiquity)
participant Cust as Customer
Note over Sched,BMCI: end of term (scheduled run)
Sched->>BMCI: maturing deposits due
BMCI->>BMCI: compute gross, tax at source, net return
BMCI->>Mob: 1, adjustment pool to customer (principal), create then validate
Mob-->>BMCI: committed
BMCI->>Mob: 2, adjustment charge to tax account (tax at source), create then validate
Mob-->>BMCI: committed
BMCI->>Mob: 3, adjustment charge to customer (net return), create then validate
Mob-->>BMCI: committed, deposit closed
BMCI-->>Cust: notification, deposit matured, wallet credited (push else SMS)
4. Early cancellation¶
A customer can request to close a deposit before maturity. This is handled on the BMCI side by a back-office two-person approval (one operator raises the request, a different operator decides), and on approval the placed principal is returned to the wallet as a single credit. It exposes no Comviva customer API and is not part of the open or maturity journey above.
5. Error handling¶
- Funding debit fails or is rejected. No collection happens, no funding posting is made, the deposit is not opened. A business rejection arrives as a code in the body, not a transport failure.
- The funding result is in doubt (ambiguous debit). Do not re-debit. Re-check the funding payment by the DAT reference and open the deposit and post the funding leg only once the re-check confirms the debit succeeded. The DAT reference is the dedup key, so a replayed callback resolves to the same deposit, never a second collection.
- An adjustment create succeeds but the validate is lost. The adjustment sits pending (created, not committed). It is resolved by re-checking and validating that specific adjustment, never by posting a fresh duplicate. Each leg is keyed on the DAT reference plus the leg label, so a pending leg is distinguishable from a missing one.
- Partial maturity. The three maturity legs (principal, tax, net return) are posted and validated independently. The deposit closes only when all three are validated. A leg already validated is not re-posted on a retry, so a re-run completes only the outstanding legs.
- Customer MSISDN does not resolve for a payout leg. The leg cannot name a destination account. Reject the leg and surface it for operations, do not post to a default account.
- Currency and units. Every posting is currency 929, with the amount in centimes. The funding amount is in the wallet currency. No conversion is involved.
6. Notifications and receipt¶
The customer is debited exactly once, at opening. The maturity payout arrives long after the customer left the placement screen, so it is notified rather than shown on screen.
- On opening, the on-screen confirmation is primary (the customer just confirmed and is watching). A push if enabled is a courtesy.
- On maturity, the customer is credited with the principal plus the net return by the scheduled run, with no screen open. Send a push if push is enabled, otherwise fall back to an SMS, telling the customer the deposit matured and the wallet was credited.
The internal ledger leg for the tax is institution-to-institution and never notifies the customer. The receipt carries the DAT contract reference prominently. That one reference is the same value used across the funding debit and every later ledger leg, and the same value the customer quotes for support, so the customer-visible reference and the reconciliation key are one and the same. At opening the receipt shows the product, the amount placed, the term, the rate, and the maturity date. At maturity it shows the principal returned and the return net of the tax at source.