Aller au contenu

Property Payment Schedule

Contrôleur HTTP de l'échéancier d'une property (création, simulation, prorogation, gestion des virements à assigner, séquestre d'intérêts). Source : property-payment-schedule.controller.ts.

Tous les endpoints requièrent une session admin BetterAuth valide (AdminAuthGuard). Les endpoints muteurs sont tracés via CreateAdminActionInterceptor.

Préfixe de routes : /administration/property.

POST /payment-schedule/simulation

Simule un échéancier sans le persister. Retourne les échéances calculées par PaymentScheduleComputing.generateSimulation.

Request body

{
  "totalFundedAmount": 100000,
  "initialCapitalLoaned": { "date": "2025-01-15", "amount": 100000 },
  "durationInMonths": 12,
  "annualInterestPercentage": 10,
  "managementFeesPercentage": 1.5,
  "spvCountry": "France",
  "interestSequestre": 0,
  "events": []
}

Validation via un sous-ensemble de EcheancierConfigModel.validator.props (totalFundedAmount, initialCapitalLoaned, durationInMonths, annualInterestPercentage, managementFeesPercentage, interestSequestre, events) (source), plus spvCountry (SpecialPurposeVehicule.countryValidator). paymentMode n'est pas validé ici.

Response

Echeance[] — tableau d'échéances simulées.

POST /payment-schedule/v2

Crée et persiste l'échéancier v2 d'une property.

Request body

{
  "propertyId": "uuid",
  "echeancierConfig": { "...": "EcheancierConfigModel.validator" },
  "totalConstructionBudget": 100000
}

Validé via PropertyEcheancierModel.createEcheancierV2_Payload (source).

Response

{ "propertyId": "uuid" }

Erreurs

Code Statut Cause
payment-schedule.already-exist 400 Un échéancier existe déjà pour cette property
spv-not-found 400 SPV introuvable pour cette property
initial-capital-loaned-is-greater-than-total-funded-amount 400 Validation config
interest-sequestre-is-greater-than-total-funded-amount 400 Validation config
sum-repayment-is-greater-than-sum-loaned 400 Validation config

PATCH /:propertyId/payment-schedule/simulation/capital-event

Simule l'application d'un événement de capital (capitalLoaned ou capitalRepaymentUnplanned) sur l'échéancier existant. Ne mute pas la base.

Path param

  • propertyId — UUIDv4

Request body

{
  "event": {
    "type": "capitalLoaned",
    "amount": 50000,
    "date": "2025-06-01"
  }
}

Le type peut être capitalLoaned ou capitalRepaymentUnplanned (source).

Response

L'échéancier simulé avec l'événement appliqué.

Erreurs

Code Statut Cause
echeancier-not-found 400 Pas d'échéancier pour cette property
echeance-not-found 400 Échéance correspondant à la date introuvable
echeancePeriod-does-not-match-event-date 400 Date de l'événement hors période
interest-sequestre-remaining-is-not-enough 400 Séquestre insuffisant pour le repayment
event-date-is-out-of-bound 400 Date de l'événement hors bornes de l'échéancier
echeancier-config-is-invalid 400 Config résultante incohérente

PUT /:propertyId/payment-schedule/mandate

Associe (ou met à jour) le mandat de prélèvement bancaire (SDD Lemonway) à l'échéancier d'une property.

Path param

  • propertyId — UUIDv4

Request body

{ "lemonwayMandateId": 12345 }

Response

200 OK avec un corps vide (le handler n'a pas de @HttpCode, NestJS retourne donc 200 par défaut).

GET /:propertyId/payment-schedule

Récupère l'échéancier persisté d'une property.

Path param

  • propertyId — UUIDv4

Response

Échéancier complet via PropertyPaymentScheduleRepository.getPaymentScheduleForProperty.

PUT /:propertyId/payment-schedule/unprogram-scheduled-mensualite-payment

Annule la programmation d'un prélèvement bancaire SDD (mensualité) prévu pour une échéance. Trace une PROPERTY_PAYMENT_SCHEDULE_UNPROGRAM_ONE_PAYMENT.

Path param

  • propertyId — UUIDv4

Request body

{ "echeanceId": "uuid-v4" }

Erreurs

Code Statut Cause
echeance-not-found 400 Échéance introuvable
echeance-mensualite-must-be-unpaid 400 La mensualité a déjà été payée
echeance-mensualite-scheduled-payment-must-be-scheduled 400 Aucun prélèvement programmé à annuler
failed-at-provider 500 Échec côté Lemonway

PUT /:propertyId/payment-schedule/program-unscheduled-mensualite-payment

Programme un prélèvement bancaire pour une échéance pas encore planifiée. Trace une PROPERTY_PAYMENT_SCHEDULE_PROGRAM_ONE_PAYMENT.

Path param

  • propertyId — UUIDv4

Request body

{
  "echeanceId": "uuid-v4",
  "customBankDebitDate": "2025-06-15"
}

Erreurs

Code Statut Cause
echeance-not-found 400 Échéance introuvable
echeance-mensualite-must-be-unpaid 400 Mensualité déjà payée
echeance-mensualite-must-be-not-scheduled 400 Mensualité déjà programmée
echeance-nothing-to-pay 400 Rien à payer pour cette échéance
echeancier-config-payment-mode-not-direct-debit 400 Mode de paiement n'est pas SDD
failed-at-provider 500 Échec côté Lemonway

GET /payment-schedule/payment/:period

Liste les paiements (avec statut financier projet) pour un mois donné.

Path param

  • period — au format YYYY-MM (validé via yearMonthDate)

Response

Tableau de paiements avec leur statut financier projet.

GET /payment-schedule/wire-to-be-assigned

Liste les virements en attente d'assignation à une échéance.

Response

Vue des virements EcheancierWireToBeAssigned au statut waiting.

GET /payment-schedule/payment-to-be-assigned/history

Liste en lecture seule les paiements déjà assignés (assigned) ou archivés (archivedNotAssigned).

Response

Même forme enrichie que la liste waiting (projet, SPV, lien Lemonway) avec en plus, pour les assignés, le numéro et la période de l'échéance cible. Le champ JSON porte le nom paymentToBeAssigned.

POST /payment-schedule/wire-to-be-assigned/switch-project

Réassigne un virement reçu à un autre projet (changement de SPV destinataire). Trace une PROPERTY_PAYMENT_SCHEDULE_SWITCH_PROJECT_OF_WIRE_WAITING_TO_BE_ASSIGNED.

Request body

{
  "wireToBeAssignedId": "uuid-v4",
  "newProjectId": "uuid"
}

Erreurs

Code Statut Cause
wire-not-found 400 Virement introuvable
wire-not-waiting 400 Virement n'est pas en statut waiting
only-parent-wires-can-be-project-switched 400 Le virement est un enfant (split)
only-wire-payments-can-be-project-switched 400 Le paiement n'est pas un virement entrant (p2p, other)
spv-current-project-not-found 400 SPV courant introuvable
new-project-not-found 400 Projet cible introuvable
new-project-spv-not-found 400 SPV du projet cible introuvable
p2p-failed-at-provider 400 Échec P2P Lemonway

POST /payment-schedule/wire-to-be-assigned/assign

Assigne un virement à une échéance (mensualité ou capital repayment). Trace une PROPERTY_PAYMENT_SCHEDULE_ASSIGN_WIRE_TO_ECHEANCE.

Request body

{
  "wireToBeAssignedId": "uuid-v4",
  "paymentFor": "mensualite",
  "echeanceId": "uuid-v4",
  "comment": "optionnel",
  "isSimulation": false
}

paymentFor'capitalRepayment' | 'mensualite'.

Response

L'échéancier mis à jour.

Erreurs

Code Statut Cause
wire-not-found 400 Virement introuvable
wire-not-waiting 400 Virement déjà assigné/archivé
echeance-not-found 400 Échéance introuvable
capital-repayment-no-payment-due 400 Pas de capital à rembourser sur l'échéance

POST /payment-schedule/wire-to-be-assigned/split

Découpe un virement reçu en deux pour pouvoir l'assigner partiellement. Trace une PROPERTY_PAYMENT_SCHEDULE_SPLIT_WIRE_TO_ECHEANCE.

Request body

{
  "wireToSplitId": "uuid-v4",
  "newAmount": 5000
}

newAmount en cents (positif, doit être inférieur au montant initial).

Erreurs

Code Statut Cause
wire-not-found 400 Virement introuvable
wire-not-waiting 400 Virement déjà traité
new-amount-must-be-less-than-original-amount 400 Montant nouveau ≥ montant initial

POST /payment-schedule/wire-to-be-assigned/archive

Archive un virement reçu sans l'assigner (cas erreur de saisie, virement non lié à un projet, etc.). Trace une PROPERTY_PAYMENT_SCHEDULE_ARCHIVE_WIRE.

Request body

{
  "wireToArchiveId": "uuid-v4",
  "comment": "raison de l'archivage"
}

comment requis (notEmptyString).

Erreurs

Code Statut Cause
wire-not-found 400 Virement introuvable
wire-not-waiting 400 Virement déjà traité

GET /payment-schedule/payment-to-be-assigned/eligible-projects

Liste les projets éligibles à la création manuelle d'un paiement à assigner (back-office). Source : property-payment-schedule.controller.ts L475.

Response

Liste de projets avec identifiants et métadonnées utiles au formulaire de création.

POST /payment-schedule/payment-to-be-assigned

Crée un paiement à assigner (virement entrant en attente d'affectation à une échéance). Trace une PROJECT_PAYMENT_SCHEDULE_CREATE_PAYMENT_TO_BE_ASSIGNED. Validator partagé : createPaymentToBeAssignedPayload (@bricks-common/api-communication-bricksoffice).

Request body

{
  "projectId": "uuid-v4",
  "amount": 100000,
  "date": "2025-06-15",
  "payment": {
    "kind": "p2p",
    "execution": "auto",
    "debitAccountId": "compte-lemonway-debiteur",
    "comment": "Paiement porteur juin"
  }
}

amount en cents (positif). payment est une union discriminée sur kind :

Variante Champs
p2p + auto debitAccountId, comment — déclenche un P2P Lemonway synchrone vers le wallet SPV du projet
p2p + manual paymentId (entier Lemonway), comment — rattache un P2P Lemonway existant
other comment — enregistrement sans mouvement Lemonway

Comportement P2P auto en échec

Si le P2P Lemonway échoue après création de l'enregistrement : le virement reste en status: waiting sans wireId, une alerte Slack est envoyée (InternalAlertSlackService + PaymentScheduleSlackService), et la réponse HTTP reste un succès avec l'enregistrement créé. Le retry se fait via POST .../payment-to-be-assigned/retry-p2p (idempotent via attemptP2PAtLemonway).

Response

L'enregistrement waitingWire créé.

Erreurs

Code Statut Cause
project-not-eligible 400 Projet non éligible
spv-not-found 400 SPV introuvable
spv-lemonway-wallet-not-found 400 Wallet Lemonway SPV introuvable
debit-account-not-found 400 Compte débiteur introuvable (P2P auto)
debit-account-insufficient-balance 400 Solde débiteur insuffisant (P2P auto)
lemonway-p2p-not-found 400 P2P Lemonway introuvable (P2P manual)
lemonway-p2p-not-success 400 P2P Lemonway pas en succès (P2P manual)
lemonway-p2p-amount-mismatch 400 Montant P2P ≠ montant demandé (P2P manual)
lemonway-p2p-receiver-account-mismatch 400 Compte receveur P2P ≠ wallet SPV (P2P manual)
lemonway-p2p-validation-failed 500 Échec technique de validation Lemonway

POST /payment-schedule/payment-to-be-assigned/retry-p2p

Relance le P2P Lemonway pour un paiement à assigner créé en mode p2p + auto dont le P2P initial a échoué. Trace une PROJECT_PAYMENT_SCHEDULE_RETRY_PAYMENT_TO_BE_ASSIGNED_P2P.

Request body

{ "wireToBeAssignedId": "uuid-v4" }

Response

L'enregistrement waitingWire mis à jour.

Erreurs

Code Statut Cause
payment-to-be-assigned-not-found 400 Enregistrement introuvable
payment-to-be-assigned-not-waiting 400 Déjà traité
payment-to-be-assigned-not-p2p-auto-execution 400 Pas un paiement P2P auto
payment-to-be-assigned-already-has-lemonway-wire-id 400 P2P déjà lié
spv-not-found 400 SPV introuvable
spv-lemonway-wallet-not-found 400 Wallet Lemonway SPV introuvable
p2p-failed 500 Échec technique du P2P Lemonway

POST /:propertyId/payment-schedule/prorogation

Proroge l'échéancier (prolonge la durée), avec optionnellement un nouveau taux d'intérêt sur la période de prorogation. Trace une PROPERTY_PAYMENT_SCHEDULE_PROROGATE_ECHEANCIER.

Path param

  • propertyId — UUIDv4

Request body

{
  "durationWithProrogation": 18,
  "interestRateDuringProrogation": 12
}

interestRateDuringProrogation est optionnel.

Response

L'échéancier prorogé.

Erreurs

Code Statut Cause
prorogation-duration-should-be-greater-than-nominal-duration 400 Durée demandée ≤ durée nominale
prorogation-duration-should-be-greater-than-current-duration 400 Durée demandée ≤ durée courante

POST /:propertyId/payment-schedule/recompute-from-echeance

Recalcule l'échéancier à partir d'une période donnée. Réservé à denis@bricks.co (beta dev — check email-only dans le contrôleur). Trace une PROPERTY_PAYMENT_SCHEDULE_RECOMPUTE_FROM_ECHEANCE.

Path param

  • propertyId — UUIDv4

Request body

{ "startRecomputeAtEcheancePeriod": "2025-06" }

Pré-conditions

  • Email admin ∈ denis@bricks.co (sinon 403 Forbidden)

Response

L'échéancier recalculé.

Erreurs

Code Statut Cause
(forbidden) 403 Email admin non autorisé
(internal) 500 Échec du recalcul

POST /echeancier/interest-sequestre/transfer-to-echeance-payment-to-be-assigned

Transfère du séquestre d'intérêts vers une échéance comme paiement à assigner. Trace une PROPERTY_ECHEANCIER_TRANSFER_SEQUESTRE_TO_ECHEANCE_PAYMENT_TO_BE_ASSIGNED.

Request body

{
  "propertyId": "uuid",
  "echeanceId": "uuid-v4",
  "interestSequestreAmountToTransfer": 1500,
  "paymentDate": "2025-06-15"
}

Erreurs

Code Statut Cause
(internal) 500 Échec du transfert (séquestre insuffisant, échéance introuvable, etc.)

GET /payment-schedule/capital-repayment/unpaid

Liste les remboursements de capital non payés à travers tous les échéanciers.

Response

Vue retournée par EcheancierViewService.getUnpaidCapitalRepayments.

Liens