@@ -46,6 +46,13 @@ export function getEntityKey(log: QBSyncLogSelectSchemaType): string {
4646 )
4747}
4848
49+ type MixedPayoutInvoices = {
50+ // Display-joined affected invoice numbers (from the log `remark`).
51+ affectedInvoiceNumbers ?: string
52+ // Subset whose absorbed fee is already recorded in QBO.
53+ invoiceNumbersWithFee ?: string
54+ }
55+
4956export class SyncErrorNotifier extends BaseService {
5057 /**
5158 * Dispatches an IU notification for a freshly written FAILED sync log row
@@ -72,34 +79,14 @@ export class SyncErrorNotifier extends BaseService {
7279 return
7380 }
7481
75- // Mixed-payout rows stash the affected invoices in `remark`; surface them,
76- // then flag which already have a recorded fee to warn against double-booking.
77- const affectedInvoiceNumbers =
78- action === NotificationActions . QB_PAYOUT_MIXED_INTENT ? log . remark : null
79- let invoiceNumbersWithFee : string | undefined
80- if ( affectedInvoiceNumbers ) {
81- try {
82- const affected = affectedInvoiceNumbers
83- . split ( MIXED_INTENT_INVOICE_DELIMITER )
84- . filter ( Boolean )
85- const withFee = await getInvoiceNumbersWithRecordedFee (
86- this . user . workspaceId ,
87- affected ,
88- )
89- const recorded = affected . filter ( ( invoiceNumber ) =>
90- withFee . has ( invoiceNumber ) ,
91- )
92- if ( recorded . length )
93- invoiceNumbersWithFee = recorded . join ( MIXED_INTENT_INVOICE_DELIMITER )
94- } catch ( error ) {
95- // A lookup blip must still let the terminal payout notification through.
96- CustomLogger . error ( {
97- message :
98- 'SyncErrorNotifier | recorded-fee lookup failed; notifying without it' ,
99- obj : error ,
100- } )
101- }
102- }
82+ // Only mixed-payout rows carry an affected-invoice list to resolve.
83+ const {
84+ affectedInvoiceNumbers,
85+ invoiceNumbersWithFee,
86+ } : MixedPayoutInvoices =
87+ action !== NotificationActions . QB_PAYOUT_MIXED_INTENT
88+ ? { }
89+ : await this . resolveMixedPayoutInvoices ( log . remark )
10390
10491 const context : NotificationContext = {
10592 entityType : log . entityType ,
@@ -110,7 +97,7 @@ export class SyncErrorNotifier extends BaseService {
11097 productName : log . productName ,
11198 qbItemName : log . qbItemName ,
11299 errorMessage : log . errorMessage ,
113- invoiceNumbers : affectedInvoiceNumbers ?? undefined ,
100+ invoiceNumbers : affectedInvoiceNumbers ,
114101 invoiceNumbersWithFee,
115102 }
116103 const portal = await getPortalConnection ( this . user . workspaceId )
@@ -125,4 +112,34 @@ export class SyncErrorNotifier extends BaseService {
125112 context ,
126113 )
127114 }
115+
116+ // Resolve a mixed-payout `remark` into its affected invoices and the subset
117+ // with a recorded fee; a lookup blip drops that detail, not the notification.
118+ private async resolveMixedPayoutInvoices (
119+ remark : string | null ,
120+ ) : Promise < MixedPayoutInvoices > {
121+ if ( ! remark ) return { }
122+ const affected = remark
123+ . split ( MIXED_INTENT_INVOICE_DELIMITER )
124+ . filter ( Boolean )
125+ let invoiceNumbersWithFee : string | undefined
126+ try {
127+ const withFee = await getInvoiceNumbersWithRecordedFee (
128+ this . user . workspaceId ,
129+ affected ,
130+ )
131+ const recorded = affected . filter ( ( invoiceNumber ) =>
132+ withFee . has ( invoiceNumber ) ,
133+ )
134+ if ( recorded . length )
135+ invoiceNumbersWithFee = recorded . join ( MIXED_INTENT_INVOICE_DELIMITER )
136+ } catch ( error ) {
137+ CustomLogger . error ( {
138+ message :
139+ 'SyncErrorNotifier | recorded-fee lookup failed; notifying without it' ,
140+ obj : error ,
141+ } )
142+ }
143+ return { affectedInvoiceNumbers : remark , invoiceNumbersWithFee }
144+ }
128145}
0 commit comments