Skip to content

Commit 95069fe

Browse files
refactor(OUT-4030): extract mixed-payout invoice resolution into a helper
Move the remark parse + recorded-fee lookup out of notify() into a private resolveMixedPayoutInvoices helper returning { affectedInvoiceNumbers, invoiceNumbersWithFee }. Behavior-preserving; keeps the fault-isolation so a lookup failure still dispatches the notification. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent dafd922 commit 95069fe

1 file changed

Lines changed: 46 additions & 29 deletions

File tree

src/app/api/quickbooks/syncLog/syncErrorNotifier.ts

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
4956
export 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

Comments
 (0)