This commit is contained in:
zlwu committed 2026-10-14 12:32:03 +08:00
1 parent a2125374a8
commit 3950b5c334
157 files changed
+57538 -22359

No files matched your search

@@ -70,8 +70,7 @@ export function normalizeInstallmentAmounts(
return defaultInstallmentAmounts(contractAmount, count)
}
if (isLegacyInstallmentRatios(values, contractAmount)) {
const sized =
values.length === count ? values : resizeInstallmentRatios(values, count)
const sized = values.length === count ? values : resizeInstallmentRatios(values, count)
return calcInstallmentDueAmountsByRatios(contractAmount, finalizeInstallmentRatios(sized))
}
const amounts = values.map((v) => Number(v || 0))
@@ -283,6 +282,36 @@ export function calcUnpaidAmountsByRatios(
type PaymentLike = Record<string, unknown> | null | undefined
type DetailLike = Record<string, any>
function integerOrUndefined(value: unknown): number | undefined {
if (value === null || value === undefined || value === '') return undefined
const parsed = Number(value)
return Number.isFinite(parsed) ? Math.trunc(parsed) : undefined
}
/**
* 普通协议保存只提交草稿字段。财务确认、退款状态及其附件必须走专用接口。
*/
export function buildProtocolPaymentDetailPayload(detail: DetailLike): DetailLike {
return {
id: detail.id,
transferType: detail.transferType,
dueAmount: detail.dueAmount,
transferAmount: detail.transferAmount,
transferTime: detail.transferTime,
installmentNo: integerOrUndefined(detail.installmentNo),
installmentDueDate: detail.installmentDueDate,
remark: detail.remark,
attachments: (detail.attachments || []).map((attachment: DetailLike) => ({
id: attachment.id,
fileName: attachment.fileName,
fileUrl: attachment.fileUrl,
fileSize: attachment.fileSize,
fileSizeDisplay: attachment.fileSizeDisplay,
fileType: attachment.fileType
}))
}
}
function resolveFqAmounts(payment: PaymentLike, count: number, details?: DetailLike[]): number[] {
const contract = payment?.contractAmount != null ? Number(payment.contractAmount) : null
const stored = Array.isArray(payment?.installmentRatios)
@@ -0,0 +1,64 @@
import { describe, it } from 'node:test'
import assert from 'node:assert/strict'
import * as installment from './protocol-payment-installment'
describe('buildProtocolPaymentDetailPayload', () => {
it('keeps normal draft fields and strips finance/refund state fields', () => {
const buildPayload = (installment as any).buildProtocolPaymentDetailPayload
assert.equal(typeof buildPayload, 'function')
const payload = buildPayload({
id: 'detail-1',
transferType: 'bank',
dueAmount: 1200,
transferAmount: 1000,
transferTime: '2026-10-14 10:00:00',
installmentNo: '2',
installmentDueDate: '20261114',
remark: '草稿备注',
attachments: [
{
id: 'attachment-1',
fileName: 'receipt.pdf',
fileUrl: '/receipt.pdf',
fileSize: 10,
fileSizeDisplay: '10 B',
fileType: 'application/pdf',
localOnly: true
}
],
payStatus: 'yjf',
financeRemark: '不应提交',
financeConfirmAttachments: 'finance.pdf',
financeConfirmAttachmentFiles: [{ fileUrl: '/finance.pdf' }],
refundAmount: 100,
refundRemark: '不应提交',
refundAttachments: 'refund.pdf',
refundAttachmentFiles: [{ fileUrl: '/refund.pdf' }],
refundFinanceRemark: '不应提交',
refundFinanceConfirmAttachments: 'refund-confirm.pdf',
refundFinanceConfirmAttachmentFiles: [{ fileUrl: '/refund-confirm.pdf' }]
})
assert.deepEqual(payload, {
id: 'detail-1',
transferType: 'bank',
dueAmount: 1200,
transferAmount: 1000,
transferTime: '2026-10-14 10:00:00',
installmentNo: 2,
installmentDueDate: '20261114',
remark: '草稿备注',
attachments: [
{
id: 'attachment-1',
fileName: 'receipt.pdf',
fileUrl: '/receipt.pdf',
fileSize: 10,
fileSizeDisplay: '10 B',
fileType: 'application/pdf'
}
]
})
})
})