feat(web-admin): wire fq last-period and dj deadline autofill in SamplePaymentPanel
Auto-recalculate the final installment due amount when earlier periods change (with manual override), and sync lump-sum deadline to due date. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
6ec4ec6730
commit
618d8fe21c
1 file changed
+65
-1
@@ -59,7 +59,7 @@
|
|||||||
placeholder="选择截止时间"
|
placeholder="选择截止时间"
|
||||||
clearable
|
clearable
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@update:model-value="(v: string) => patchPay(pIdx, { lumpSumDeadline: v || '' })"
|
@update:model-value="(v: string) => onLumpSumDeadlineChange(pIdx, v || '')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
@@ -364,12 +364,15 @@
|
|||||||
import {
|
import {
|
||||||
applyConsolidateRemainingToPayment,
|
applyConsolidateRemainingToPayment,
|
||||||
applyExpandRemainingToInstallment,
|
applyExpandRemainingToInstallment,
|
||||||
|
applyLumpSumDeadlineToLastDueDate,
|
||||||
availableSamplePayModes,
|
availableSamplePayModes,
|
||||||
|
calcLastPeriodDueAmount,
|
||||||
parseInstallmentRatios,
|
parseInstallmentRatios,
|
||||||
parsePreferentialPrice,
|
parsePreferentialPrice,
|
||||||
resolvePerSamplePaymentDefaults,
|
resolvePerSamplePaymentDefaults,
|
||||||
samplePaymentHasConfirmedTransfer,
|
samplePaymentHasConfirmedTransfer,
|
||||||
schedulePaidArrears,
|
schedulePaidArrears,
|
||||||
|
shouldAutoFillLastPeriodDue,
|
||||||
shouldReplaceContractWithPreferentialPrice
|
shouldReplaceContractWithPreferentialPrice
|
||||||
} from '@/utils/protocol-sample-payment'
|
} from '@/utils/protocol-sample-payment'
|
||||||
import { isMultiSchedulePayMode } from '@/utils/protocol-payment-presets'
|
import { isMultiSchedulePayMode } from '@/utils/protocol-payment-presets'
|
||||||
@@ -430,6 +433,8 @@
|
|||||||
const transferTypeOptions = ref<Api.Dict.DictDataOption[]>([])
|
const transferTypeOptions = ref<Api.Dict.DictDataOption[]>([])
|
||||||
const submittingId = ref('')
|
const submittingId = ref('')
|
||||||
const savingKey = ref('')
|
const savingKey = ref('')
|
||||||
|
/** 按样本 key:用户手改过最后一期应缴金额则 true,前几期再变时清除 */
|
||||||
|
const lastPeriodDueOverrideByKey = ref<Record<string, boolean>>({})
|
||||||
|
|
||||||
async function ensureTransferTypes() {
|
async function ensureTransferTypes() {
|
||||||
await loadTransferTypeDict()
|
await loadTransferTypeDict()
|
||||||
@@ -442,6 +447,18 @@
|
|||||||
return '¥' + formatMoneyDisplay(v)
|
return '¥' + formatMoneyDisplay(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function samplePayKey(pay: Record<string, any>, pIdx: number): string {
|
||||||
|
return String(pay.sampleCode || pay.protocolSampleId || pIdx)
|
||||||
|
}
|
||||||
|
|
||||||
|
function activeScheduleIndices(schedules: Record<string, any>[]): number[] {
|
||||||
|
const idx: number[] = []
|
||||||
|
schedules.forEach((s, i) => {
|
||||||
|
if (String(s.scheduleStatus || 'open') !== 'void' && !s._deleted) idx.push(i)
|
||||||
|
})
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|
||||||
/** 仅财务已确认(yjf)锁定;付款确认中仍可改,直至财务确认 */
|
/** 仅财务已确认(yjf)锁定;付款确认中仍可改,直至财务确认 */
|
||||||
function isTransferLocked(tr: Record<string, any>) {
|
function isTransferLocked(tr: Record<string, any>) {
|
||||||
return tr.payStatus === 'yjf'
|
return tr.payStatus === 'yjf'
|
||||||
@@ -458,6 +475,37 @@
|
|||||||
const pay = { ...list[pIdx] }
|
const pay = { ...list[pIdx] }
|
||||||
const schedules = [...(pay.schedules || [])]
|
const schedules = [...(pay.schedules || [])]
|
||||||
schedules[sIdx] = { ...schedules[sIdx], ...patch }
|
schedules[sIdx] = { ...schedules[sIdx], ...patch }
|
||||||
|
const mode = String(pay.payMode || '')
|
||||||
|
const key = samplePayKey(pay, pIdx)
|
||||||
|
const activeIdx = activeScheduleIndices(schedules)
|
||||||
|
|
||||||
|
if ('dueAmount' in patch && mode === 'fq' && activeIdx.length >= 2) {
|
||||||
|
const lastIdx = activeIdx[activeIdx.length - 1]
|
||||||
|
if (sIdx === lastIdx) {
|
||||||
|
lastPeriodDueOverrideByKey.value = {
|
||||||
|
...lastPeriodDueOverrideByKey.value,
|
||||||
|
[key]: true
|
||||||
|
}
|
||||||
|
} else if (activeIdx.slice(0, -1).includes(sIdx)) {
|
||||||
|
lastPeriodDueOverrideByKey.value = {
|
||||||
|
...lastPeriodDueOverrideByKey.value,
|
||||||
|
[key]: false
|
||||||
|
}
|
||||||
|
const lastSch = schedules[lastIdx]
|
||||||
|
const canFill = shouldAutoFillLastPeriodDue({
|
||||||
|
lastManualOverride: false,
|
||||||
|
lastLocked: isScheduleDueLocked(lastSch)
|
||||||
|
})
|
||||||
|
if (canFill) {
|
||||||
|
const priors = activeIdx.slice(0, -1).map((i) => schedules[i]?.dueAmount)
|
||||||
|
const lastAmt = calcLastPeriodDueAmount(pay.contractAmount, priors)
|
||||||
|
if (lastAmt != null) {
|
||||||
|
schedules[lastIdx] = { ...schedules[lastIdx], dueAmount: lastAmt }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pay.schedules = schedules
|
pay.schedules = schedules
|
||||||
if ('dueAmount' in patch) {
|
if ('dueAmount' in patch) {
|
||||||
pay.installmentRatios = schedules.map((s: Record<string, any>) => {
|
pay.installmentRatios = schedules.map((s: Record<string, any>) => {
|
||||||
@@ -469,6 +517,22 @@
|
|||||||
emit('update:modelValue', list)
|
emit('update:modelValue', list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onLumpSumDeadlineChange(pIdx: number, raw: string) {
|
||||||
|
const list = [...(props.modelValue || [])]
|
||||||
|
const pay = { ...list[pIdx] }
|
||||||
|
const deadline = raw || ''
|
||||||
|
pay.lumpSumDeadline = deadline
|
||||||
|
if (String(pay.payMode || '') === 'dj') {
|
||||||
|
pay.schedules = applyLumpSumDeadlineToLastDueDate(
|
||||||
|
[...(pay.schedules || [])],
|
||||||
|
deadline,
|
||||||
|
isScheduleDueLocked
|
||||||
|
)
|
||||||
|
}
|
||||||
|
list[pIdx] = pay
|
||||||
|
emit('update:modelValue', list)
|
||||||
|
}
|
||||||
|
|
||||||
function sampleTitle(pay: Record<string, any>) {
|
function sampleTitle(pay: Record<string, any>) {
|
||||||
const sample = (props.samples || []).find(
|
const sample = (props.samples || []).find(
|
||||||
(s) => String(s.sampleCode || '') === String(pay.sampleCode || '')
|
(s) => String(s.sampleCode || '') === String(pay.sampleCode || '')
|
||||||
|
|||||||
Reference in new issue
Block a user