Skip to content

Commit 98c76f4

Browse files
fix(OUT-3617): AB-gate settings write path and backend validations
- Strip bankDepositFeeFlag/bankAccountRef from payload for non-AB portals (prevents garbage state if portal is later added to AB list) - Reject bankDepositFeeFlag:true without bankAccountRef on the backend - Fix res.Deposit.Id optional chaining inconsistency in payment.service.ts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 36bcfa4 commit 98c76f4

2 files changed

Lines changed: 18 additions & 3 deletions

File tree

src/app/api/quickbooks/payment/payment.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ export class PaymentService extends BaseService {
262262
await this.logSync(
263263
opts.paymentId,
264264
{
265-
qbInvoiceId: res.Deposit.Id,
265+
qbInvoiceId: res.Deposit?.Id,
266266
invoiceNumber: opts.invoiceNumber,
267267
},
268268
EventType.SUCCEEDED,

src/app/api/quickbooks/setting/setting.controller.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import APIError from '@/app/api/core/exceptions/api'
12
import authenticate from '@/app/api/core/utils/authenticate'
23
import { SettingService } from '@/app/api/quickbooks/setting/setting.service'
34
import { TokenService } from '@/app/api/quickbooks/token/token.service'
@@ -58,17 +59,31 @@ export async function updateSettings(req: NextRequest) {
5859
const parsedType = z.nativeEnum(SettingType).parse(type)
5960

6061
const parsed = SettingRequestSchema.parse(body)
61-
const { bankAccountRef, ...settingFields } = parsed
62+
const { bankAccountRef, bankDepositFeeFlag, ...settingFields } = parsed
6263

64+
const isBankDepositAB =
65+
parsedType === SettingType.INVOICE &&
66+
isPortalInBankDepositABTest(user.workspaceId)
67+
68+
// Strip bank deposit fields for portals not in the AB test
6369
const payload = {
6470
...settingFields,
71+
...(isBankDepositAB && { bankDepositFeeFlag }),
6572
...(parsedType === SettingType.INVOICE
6673
? { initialInvoiceSettingMap: true }
6774
: { initialProductSettingMap: true }),
6875
}
6976

77+
// Reject bankDepositFeeFlag:true without a bankAccountRef
78+
if (isBankDepositAB && bankDepositFeeFlag && !bankAccountRef) {
79+
throw new APIError(
80+
httpStatus.BAD_REQUEST,
81+
'bankAccountRef is required when bankDepositFeeFlag is enabled',
82+
)
83+
}
84+
7085
const writeBankAccountRef =
71-
parsedType === SettingType.INVOICE && typeof bankAccountRef !== 'undefined'
86+
isBankDepositAB && typeof bankAccountRef !== 'undefined'
7287

7388
// Wrap both writes in a transaction to prevent partial state
7489
// (e.g. bankDepositFeeFlag=true but bankAccountRef=null)

0 commit comments

Comments
 (0)