fix(audit): H4 (reservation signing berth rule) + H13 (manual EOI-sign stage parity)
H4: reservation_agreement completion fired the contract_signed berth rule, flipping the berth to 'sold' one-to-two stages early. Add a dedicated reservation_signed berth trigger (defaults to under_offer) and fire it. H13: the manual signed-EOI upload path advanced only to 'eoi' via the ungated helper while the Documenso-webhook path advanced to 'reservation'; both now use advanceStageIfBehindGated(..., 'reservation', 'eoi_signed') so manually- and webhook-signed deals reach the same stage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import { logger } from '@/lib/logger';
|
||||
export type BerthRuleTrigger =
|
||||
| 'eoi_sent'
|
||||
| 'eoi_signed'
|
||||
| 'reservation_signed'
|
||||
| 'deposit_received'
|
||||
| 'contract_signed'
|
||||
| 'interest_archived'
|
||||
@@ -39,6 +40,10 @@ interface RuleConfig {
|
||||
const DEFAULT_RULES: Record<BerthRuleTrigger, RuleConfig> = {
|
||||
eoi_sent: { mode: 'suggest', targetStatus: 'under_offer' },
|
||||
eoi_signed: { mode: 'auto', targetStatus: 'under_offer' },
|
||||
// Reservation agreement signed — a commitment short of sale, so the berth
|
||||
// stays Under offer (audit H4); previously reused the contract_signed rule
|
||||
// and flipped it to Sold prematurely.
|
||||
reservation_signed: { mode: 'auto', targetStatus: 'under_offer' },
|
||||
deposit_received: { mode: 'auto', targetStatus: 'sold' },
|
||||
contract_signed: { mode: 'auto', targetStatus: 'sold' },
|
||||
interest_archived: { mode: 'suggest', targetStatus: 'available' },
|
||||
|
||||
@@ -988,13 +988,18 @@ export async function uploadSignedManually(
|
||||
if (interest) {
|
||||
void evaluateRule('eoi_signed', doc.interestId, portId, meta);
|
||||
|
||||
// Stage stays at 'eoi' - sub-status badge flips to "signed".
|
||||
void advanceStageIfBehind(
|
||||
// EOI signed = formal commitment → advance to 'reservation' via the
|
||||
// GATED helper, matching the Documenso-webhook path (audit H13).
|
||||
// Previously this manual-upload path used the ungated helper and only
|
||||
// reached 'eoi', so manually-signed deals lagged a stage behind
|
||||
// webhook-signed ones and skewed funnel/stage-duration reports.
|
||||
void advanceStageIfBehindGated(
|
||||
doc.interestId,
|
||||
portId,
|
||||
'eoi',
|
||||
'reservation',
|
||||
meta,
|
||||
'Signed EOI uploaded manually',
|
||||
'eoi_signed',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1680,7 +1685,11 @@ export async function handleDocumentCompleted(eventData: { documentId: string; p
|
||||
'reservation_signed',
|
||||
);
|
||||
void import('@/lib/services/berth-rules-engine').then(({ evaluateRule }) =>
|
||||
evaluateRule('contract_signed', doc.interestId!, doc.portId, systemMeta),
|
||||
// Reservation signing is NOT contract signing — firing 'contract_signed'
|
||||
// here flipped the berth to 'sold' one-to-two stages early (audit H4).
|
||||
// Use the dedicated 'reservation_signed' trigger (defaults to
|
||||
// 'under_offer').
|
||||
evaluateRule('reservation_signed', doc.interestId!, doc.portId, systemMeta),
|
||||
);
|
||||
|
||||
// Tenancies P3 — auto-create pending tenancies (one per in-bundle berth).
|
||||
|
||||
Reference in New Issue
Block a user