From 45c31e555ff2c8a39c30be57331bb4dbc457d725 Mon Sep 17 00:00:00 2001 From: louispaulb Date: Wed, 3 Jun 2026 18:05:56 -0400 Subject: [PATCH] =?UTF-8?q?Contrat=20r=C3=A9sidentiel:=20conformit=C3=A9?= =?UTF-8?q?=20CRTC=202026-43=20(fin=20du=20clawback)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Installation = vraie créance financée (champ install_fee : 240$ std → 10$/mois, 120$ simple → 5$/mois). Résiliation résidentielle ne facture que le solde restant de l'install (service rendu) ; promotions/carte-cadeau jamais récupérées (termination_fee_benefits=0). Récap reformulé (financement install, plus de "promotion non étalée"). Conforme avant l'échéance du 12 juin. Co-Authored-By: Claude Opus 4.8 (1M context) --- services/targo-hub/lib/contracts.js | 44 +++++++++++++++++------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/services/targo-hub/lib/contracts.js b/services/targo-hub/lib/contracts.js index c19cec7..5affb5f 100644 --- a/services/targo-hub/lib/contracts.js +++ b/services/targo-hub/lib/contracts.js @@ -62,15 +62,21 @@ function calculateTerminationFee (contract) { termination_fee_total: fee, } } else { - // Résidentiel: only benefit residual value (+ current month max) - fee = totalBenefitRemaining + // Résidentiel (CRTC 2026-43) : AUCUN clawback de promotion. On ne facture + // que le SOLDE de l'installation financée — un service déjà rendu, donc + // facturable. Les promotions/carte-cadeau ne sont JAMAIS récupérées. + const installFee = contract.install_fee || 0 + const installRemaining = round2(installFee * monthsRemaining / (contract.duration_months || 24)) + fee = installRemaining feeBreakdown = { type: 'residential', months_remaining: monthsRemaining, monthly_rate: monthlyRate, - termination_fee_benefits: totalBenefitRemaining, - termination_fee_remaining: 0, - termination_fee_total: totalBenefitRemaining, + install_fee: installFee, + install_remaining: installRemaining, + termination_fee_benefits: 0, + termination_fee_remaining: installRemaining, + termination_fee_total: installRemaining, } } @@ -180,6 +186,7 @@ async function handle (req, res, method, path) { end_date: endDate, duration_months: duration, monthly_rate: body.monthly_rate || 0, + install_fee: body.install_fee || 0, service_location: body.service_location || '', quotation: body.quotation || '', subscription: body.subscription || '', @@ -878,15 +885,15 @@ async function createTerminationInvoice (contract, calc, reason) { income_account: '', // will use default }) } else { - // Residential: charge benefit residual - for (const b of calc.benefits) { - if (b.remaining_value <= 0) continue + // Résidentiel : solde de l'installation financée (service rendu) — PAS une pénalité. + if (calc.install_remaining > 0) { items.push({ - item_name: `Résiliation — ${b.description}`, - description: `Valeur résiduelle: ${b.benefit_value}$ - ${b.months_recognized} mois reconnus ` + - `(${b.monthly_recognition}$/mois). Restant: ${b.remaining_value}$`, + item_name: "Solde de l'installation (financement restant)", + description: `Installation ${calc.install_fee}$ financée sur ${contract.duration_months || 24} mois. ` + + `Solde restant après ${calc.months_elapsed} mois : ${calc.install_remaining}$. ` + + `Service déjà réalisé — aucune pénalité de résiliation, aucune promotion récupérée.`, qty: 1, - rate: b.remaining_value, + rate: calc.install_remaining, }) } } @@ -931,9 +938,8 @@ function renderAcceptancePage (contract, token) { const TARGO_LOGO_SVG = `` const isCommercial = contract.contract_type === 'Commercial' - const penaltyText = isCommercial - ? `la totalité des mensualités restantes au terme (${contract.monthly_rate || 0} $/mois × mois restants)` - : `la portion non étalée de la promotion, au prorata des mois restants sur ${duration} mois` + const installFee = contract.install_fee || 0 + const installMonthly = installFee ? round2(installFee / duration) : 0 return ` @@ -992,6 +998,7 @@ tfoot td{font-weight:700;color:#00733a;background:#f4fff6;border-top:1px solid #
Client${escapeHtml(contract.customer_name || contract.customer || '')}
Mensualité${contract.monthly_rate || 0} $/mois (+taxes)
+ ${installFee ? `
Installation (financée sur ${duration} mois)${installMonthly} $/mois (${installFee} $ — service)
` : ''}
Durée${duration} mois
Début prévu${contract.start_date || 'À déterminer'}
@@ -1000,14 +1007,15 @@ tfoot td{font-weight:700;color:#00733a;background:#f4fff6;border-top:1px solid # ${benefitRows} - - +
Valeur totale de la promotion${round2(totalBenefit)} $
Étalée sur ${duration} mois
Valeur des promotions (non récupérables)${round2(totalBenefit)} $
` : ''}
Changement avant ${duration} mois ?
- Pas de pénalité. On récupère simplement ${penaltyText}. Rien de plus. + ${isCommercial + ? `Les mensualités restantes du terme demeurent dues (${contract.monthly_rate || 0} $/mois × mois restants).` + : `Aucune pénalité de résiliation. ${installFee ? `L'installation (${installFee} $) est financée sur ${duration} mois : seul le solde restant de l'installation — un service déjà réalisé — demeure dû. ` : ''}Vos promotions et la carte-cadeau ne sont jamais récupérées ; le rabais nouveau client cesse simplement.`}