新增
This commit is contained in:
@@ -487,8 +487,8 @@ export function prescriptionOrderComplete(params: { id: number; fulfillment_stat
|
|||||||
return request.post({ url: '/tcm.prescriptionOrder/complete', params })
|
return request.post({ url: '/tcm.prescriptionOrder/complete', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 业务订单退款(须填写原因;关联收款单标记已退款、已付总额清零) */
|
/** 业务订单退款(须填写原因;refund_amount 可选,不传则退满可退上限) */
|
||||||
export function prescriptionOrderRefund(params: { id: number; reason: string }) {
|
export function prescriptionOrderRefund(params: { id: number; reason: string; refund_amount?: number }) {
|
||||||
return request.post({ url: '/tcm.prescriptionOrder/refund', params })
|
return request.post({ url: '/tcm.prescriptionOrder/refund', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2163,6 +2163,20 @@
|
|||||||
label-width="88px"
|
label-width="88px"
|
||||||
class="mt-3"
|
class="mt-3"
|
||||||
>
|
>
|
||||||
|
<el-form-item label="退款金额" prop="refund_amount">
|
||||||
|
<el-input-number
|
||||||
|
v-model="completeRefundForm.refund_amount"
|
||||||
|
:min="0.01"
|
||||||
|
:max="completeOrderRefundMax > 0 ? completeOrderRefundMax : undefined"
|
||||||
|
:step="0.01"
|
||||||
|
:precision="2"
|
||||||
|
class="w-full"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
<div class="text-xs text-gray-500 mt-1">
|
||||||
|
可退上限 ¥{{ formatMoney(completeOrderRefundMax) }}
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="退款原因" prop="reason">
|
<el-form-item label="退款原因" prop="reason">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="completeRefundForm.reason"
|
v-model="completeRefundForm.reason"
|
||||||
@@ -2201,9 +2215,23 @@
|
|||||||
:closable="false"
|
:closable="false"
|
||||||
show-icon
|
show-icon
|
||||||
class="mb-4 !items-start"
|
class="mb-4 !items-start"
|
||||||
title="确认退款后,关联收款记录将全部标记为「已退款」,已付总额清零,且不可撤销。"
|
:title="refundOrderAlertTitle"
|
||||||
/>
|
/>
|
||||||
<el-form ref="refundOrderFormRef" :model="refundOrderForm" :rules="refundOrderRules" label-width="88px">
|
<el-form ref="refundOrderFormRef" :model="refundOrderForm" :rules="refundOrderRules" label-width="88px">
|
||||||
|
<el-form-item label="退款金额" prop="refund_amount">
|
||||||
|
<el-input-number
|
||||||
|
v-model="refundOrderForm.refund_amount"
|
||||||
|
:min="0.01"
|
||||||
|
:max="refundOrderMaxAmount > 0 ? refundOrderMaxAmount : undefined"
|
||||||
|
:step="0.01"
|
||||||
|
:precision="2"
|
||||||
|
class="w-full"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
<div class="text-xs text-gray-500 mt-1">
|
||||||
|
可退上限 ¥{{ formatMoney(refundOrderMaxAmount) }}(默认全额);部分退款时按金额从关联收款单依次标记已退款,并扣减本单已付。
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="退款原因" prop="reason">
|
<el-form-item label="退款原因" prop="reason">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="refundOrderForm.reason"
|
v-model="refundOrderForm.reason"
|
||||||
@@ -5332,20 +5360,31 @@ const completeOrderSubmitting = ref(false)
|
|||||||
const completeOrderPayLoading = ref(false)
|
const completeOrderPayLoading = ref(false)
|
||||||
const completeOrderLinkedPays = ref<any[]>([])
|
const completeOrderLinkedPays = ref<any[]>([])
|
||||||
const completeRefundFormRef = ref<FormInstance>()
|
const completeRefundFormRef = ref<FormInstance>()
|
||||||
const completeRefundForm = reactive({ reason: '' })
|
const completeRefundForm = reactive({ reason: '', refund_amount: undefined as number | undefined })
|
||||||
const completeRefundRules: FormRules = {
|
const completeOrderRefundMax = ref(0)
|
||||||
reason: [{ required: true, message: '请填写退款原因', trigger: 'blur' }]
|
const completeOrderRefundTotal = computed(() => calcRefundableFromLinkedPays(completeOrderLinkedPays.value))
|
||||||
}
|
const completeRefundRules = computed<FormRules>(() => ({
|
||||||
const completeOrderRefundTotal = computed(() => {
|
refund_amount: [
|
||||||
let sum = 0
|
{ required: true, message: '请输入退款金额', trigger: 'change' },
|
||||||
for (const o of completeOrderLinkedPays.value) {
|
{
|
||||||
const st = Number(o?.status)
|
validator: (_rule, v, cb) => {
|
||||||
if (st === 2 || st === 5) {
|
const n = Number(v)
|
||||||
sum += Number(o?.amount) || 0
|
const cap = completeOrderRefundMax.value
|
||||||
|
if (!Number.isFinite(n) || n <= 0) {
|
||||||
|
cb(new Error('退款金额须大于 0'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (cap > 0 && n > cap + 0.009) {
|
||||||
|
cb(new Error(`不能超过可退上限 ¥${formatMoney(cap)}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cb()
|
||||||
|
},
|
||||||
|
trigger: 'change'
|
||||||
}
|
}
|
||||||
}
|
],
|
||||||
return Math.round(sum * 100) / 100
|
reason: [{ required: true, message: '请填写退款原因', trigger: 'blur' }]
|
||||||
})
|
}))
|
||||||
let completeOrderLogisticsRequestSeq = 0
|
let completeOrderLogisticsRequestSeq = 0
|
||||||
|
|
||||||
function onCompleteOrderDialogClosed() {
|
function onCompleteOrderDialogClosed() {
|
||||||
@@ -5353,6 +5392,8 @@ function onCompleteOrderDialogClosed() {
|
|||||||
completeOrderLinkedPays.value = []
|
completeOrderLinkedPays.value = []
|
||||||
completeOrderPayLoading.value = false
|
completeOrderPayLoading.value = false
|
||||||
completeRefundForm.reason = ''
|
completeRefundForm.reason = ''
|
||||||
|
completeRefundForm.refund_amount = undefined
|
||||||
|
completeOrderRefundMax.value = 0
|
||||||
completeRefundFormRef.value?.clearValidate()
|
completeRefundFormRef.value?.clearValidate()
|
||||||
completeOrderLogisticsRequestSeq += 1
|
completeOrderLogisticsRequestSeq += 1
|
||||||
completeOrderLogisticsPayload.value = null
|
completeOrderLogisticsPayload.value = null
|
||||||
@@ -5370,8 +5411,13 @@ async function loadCompleteOrderPayContext(orderId: number) {
|
|||||||
const d = r?.data ?? r ?? null
|
const d = r?.data ?? r ?? null
|
||||||
const arr = d?.linked_pay_orders
|
const arr = d?.linked_pay_orders
|
||||||
completeOrderLinkedPays.value = Array.isArray(arr) ? arr : []
|
completeOrderLinkedPays.value = Array.isArray(arr) ? arr : []
|
||||||
|
const linkedMax = calcRefundableFromLinkedPays(completeOrderLinkedPays.value)
|
||||||
|
const paid = Number(d?.paid) || 0
|
||||||
|
completeOrderRefundMax.value = linkedMax > 0 ? linkedMax : paid
|
||||||
|
completeRefundForm.refund_amount = completeOrderRefundMax.value
|
||||||
} catch {
|
} catch {
|
||||||
completeOrderLinkedPays.value = []
|
completeOrderLinkedPays.value = []
|
||||||
|
completeOrderRefundMax.value = 0
|
||||||
} finally {
|
} finally {
|
||||||
completeOrderPayLoading.value = false
|
completeOrderPayLoading.value = false
|
||||||
}
|
}
|
||||||
@@ -5421,7 +5467,11 @@ async function submitCompleteOrder() {
|
|||||||
if (!valid) return
|
if (!valid) return
|
||||||
completeOrderSubmitting.value = true
|
completeOrderSubmitting.value = true
|
||||||
try {
|
try {
|
||||||
await prescriptionOrderRefund({ id, reason: completeRefundForm.reason.trim() })
|
await prescriptionOrderRefund({
|
||||||
|
id,
|
||||||
|
reason: completeRefundForm.reason.trim(),
|
||||||
|
refund_amount: Number(completeRefundForm.refund_amount)
|
||||||
|
})
|
||||||
feedback.msgSuccess('退款成功')
|
feedback.msgSuccess('退款成功')
|
||||||
completeOrderDialogVisible.value = false
|
completeOrderDialogVisible.value = false
|
||||||
getLists()
|
getLists()
|
||||||
@@ -5462,25 +5512,79 @@ async function submitCompleteOrder() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ─── 订单退款(已发货/已签收 + 支付审核通过)────────────────────────────────────────────
|
// ─── 订单退款(已发货/已签收 + 支付审核通过)────────────────────────────────────────────
|
||||||
|
function calcRefundableFromLinkedPays(list: any[]) {
|
||||||
|
let sum = 0
|
||||||
|
for (const o of list || []) {
|
||||||
|
const st = Number(o?.status)
|
||||||
|
if (st === 2 || st === 5) {
|
||||||
|
sum += Number(o?.amount) || 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Math.round(sum * 100) / 100
|
||||||
|
}
|
||||||
|
|
||||||
const refundOrderDialogVisible = ref(false)
|
const refundOrderDialogVisible = ref(false)
|
||||||
const refundOrderId = ref(0)
|
const refundOrderId = ref(0)
|
||||||
const refundOrderSubmitting = ref(false)
|
const refundOrderSubmitting = ref(false)
|
||||||
const refundOrderFormRef = ref<FormInstance>()
|
const refundOrderFormRef = ref<FormInstance>()
|
||||||
const refundOrderForm = reactive({ reason: '' })
|
const refundOrderMaxAmount = ref(0)
|
||||||
const refundOrderRules: FormRules = {
|
const refundOrderForm = reactive({ reason: '', refund_amount: undefined as number | undefined })
|
||||||
|
const refundOrderAlertTitle = computed(() => {
|
||||||
|
const cap = formatMoney(refundOrderMaxAmount.value)
|
||||||
|
const amt = formatMoney(refundOrderForm.refund_amount)
|
||||||
|
if (Number(refundOrderForm.refund_amount) >= refundOrderMaxAmount.value - 0.009) {
|
||||||
|
return `确认全额退款 ¥${cap}:关联收款将标记已退款,本单已付清零,且不可撤销。`
|
||||||
|
}
|
||||||
|
return `确认部分退款 ¥${amt}(可退上限 ¥${cap}):将扣减本单已付,并按金额依次标记关联收款已退款。`
|
||||||
|
})
|
||||||
|
const refundOrderRules = computed<FormRules>(() => ({
|
||||||
|
refund_amount: [
|
||||||
|
{ required: true, message: '请输入退款金额', trigger: 'change' },
|
||||||
|
{
|
||||||
|
validator: (_rule, v, cb) => {
|
||||||
|
const n = Number(v)
|
||||||
|
const cap = refundOrderMaxAmount.value
|
||||||
|
if (!Number.isFinite(n) || n <= 0) {
|
||||||
|
cb(new Error('退款金额须大于 0'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (cap > 0 && n > cap + 0.009) {
|
||||||
|
cb(new Error(`不能超过可退上限 ¥${formatMoney(cap)}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cb()
|
||||||
|
},
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
],
|
||||||
reason: [{ required: true, message: '请填写退款原因', trigger: 'blur' }]
|
reason: [{ required: true, message: '请填写退款原因', trigger: 'blur' }]
|
||||||
}
|
}))
|
||||||
|
|
||||||
function onRefundOrderDialogClosed() {
|
function onRefundOrderDialogClosed() {
|
||||||
refundOrderId.value = 0
|
refundOrderId.value = 0
|
||||||
refundOrderForm.reason = ''
|
refundOrderForm.reason = ''
|
||||||
|
refundOrderForm.refund_amount = undefined
|
||||||
|
refundOrderMaxAmount.value = 0
|
||||||
refundOrderFormRef.value?.clearValidate()
|
refundOrderFormRef.value?.clearValidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
function openRefundOrder(row: { id: number }) {
|
async function openRefundOrder(row: { id: number }) {
|
||||||
refundOrderId.value = row.id
|
refundOrderId.value = row.id
|
||||||
refundOrderForm.reason = ''
|
refundOrderForm.reason = ''
|
||||||
|
refundOrderForm.refund_amount = undefined
|
||||||
|
refundOrderMaxAmount.value = 0
|
||||||
refundOrderDialogVisible.value = true
|
refundOrderDialogVisible.value = true
|
||||||
|
try {
|
||||||
|
const r: any = await prescriptionOrderDetail({ id: row.id })
|
||||||
|
const d = r?.data ?? r ?? null
|
||||||
|
const linked = Array.isArray(d?.linked_pay_orders) ? d.linked_pay_orders : []
|
||||||
|
const linkedMax = calcRefundableFromLinkedPays(linked)
|
||||||
|
const paid = Number(d?.paid) || 0
|
||||||
|
refundOrderMaxAmount.value = linkedMax > 0 ? linkedMax : paid
|
||||||
|
refundOrderForm.refund_amount = refundOrderMaxAmount.value
|
||||||
|
} catch {
|
||||||
|
refundOrderMaxAmount.value = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitRefundOrder() {
|
async function submitRefundOrder() {
|
||||||
@@ -5490,7 +5594,11 @@ async function submitRefundOrder() {
|
|||||||
if (!valid) return
|
if (!valid) return
|
||||||
refundOrderSubmitting.value = true
|
refundOrderSubmitting.value = true
|
||||||
try {
|
try {
|
||||||
await prescriptionOrderRefund({ id, reason: refundOrderForm.reason.trim() })
|
await prescriptionOrderRefund({
|
||||||
|
id,
|
||||||
|
reason: refundOrderForm.reason.trim(),
|
||||||
|
refund_amount: Number(refundOrderForm.refund_amount)
|
||||||
|
})
|
||||||
feedback.msgSuccess('退款成功')
|
feedback.msgSuccess('退款成功')
|
||||||
refundOrderDialogVisible.value = false
|
refundOrderDialogVisible.value = false
|
||||||
getLists()
|
getLists()
|
||||||
@@ -5676,6 +5784,7 @@ function confirmComplete(row: {
|
|||||||
completeOrderId.value = row.id
|
completeOrderId.value = row.id
|
||||||
completeFulfillmentStatus.value = 3
|
completeFulfillmentStatus.value = 3
|
||||||
completeRefundForm.reason = ''
|
completeRefundForm.reason = ''
|
||||||
|
completeRefundForm.refund_amount = undefined
|
||||||
completeOrderLinkedPays.value = []
|
completeOrderLinkedPays.value = []
|
||||||
completeOrderLogisticsPayload.value = null
|
completeOrderLogisticsPayload.value = null
|
||||||
completeOrderDialogVisible.value = true
|
completeOrderDialogVisible.value = true
|
||||||
|
|||||||
@@ -1880,6 +1880,17 @@
|
|||||||
label-width="80px"
|
label-width="80px"
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
>
|
>
|
||||||
|
<el-form-item label="退款金额" prop="refund_amount">
|
||||||
|
<el-input-number
|
||||||
|
v-model="completeRefundForm.refund_amount"
|
||||||
|
:min="0.01"
|
||||||
|
:max="completeOrderRefundMax > 0 ? completeOrderRefundMax : undefined"
|
||||||
|
:step="0.01"
|
||||||
|
:precision="2"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
<div class="text-xs text-gray-500 mt-1">可退上限 ¥{{ formatMoney(completeOrderRefundMax) }}</div>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="退款原因" prop="reason">
|
<el-form-item label="退款原因" prop="reason">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="completeRefundForm.reason"
|
v-model="completeRefundForm.reason"
|
||||||
@@ -1917,9 +1928,20 @@
|
|||||||
:closable="false"
|
:closable="false"
|
||||||
show-icon
|
show-icon
|
||||||
class="mb-4 !items-start"
|
class="mb-4 !items-start"
|
||||||
title="确认退款后,关联收款记录将全部标记为「已退款」,已付总额清零,且不可撤销。"
|
:title="refundOrderAlertTitle"
|
||||||
/>
|
/>
|
||||||
<el-form ref="refundOrderFormRef" :model="refundOrderForm" :rules="refundOrderRules" label-width="88px">
|
<el-form ref="refundOrderFormRef" :model="refundOrderForm" :rules="refundOrderRules" label-width="88px">
|
||||||
|
<el-form-item label="退款金额" prop="refund_amount">
|
||||||
|
<el-input-number
|
||||||
|
v-model="refundOrderForm.refund_amount"
|
||||||
|
:min="0.01"
|
||||||
|
:max="refundOrderMaxAmount > 0 ? refundOrderMaxAmount : undefined"
|
||||||
|
:step="0.01"
|
||||||
|
:precision="2"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
<div class="text-xs text-gray-500 mt-1">可退上限 ¥{{ formatMoney(refundOrderMaxAmount) }}</div>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="退款原因" prop="reason">
|
<el-form-item label="退款原因" prop="reason">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="refundOrderForm.reason"
|
v-model="refundOrderForm.reason"
|
||||||
@@ -4656,23 +4678,41 @@ const completeFulfillmentStatus = ref<number>(3)
|
|||||||
const completeOrderSubmitting = ref(false)
|
const completeOrderSubmitting = ref(false)
|
||||||
const completeOrderLinkedPays = ref<any[]>([])
|
const completeOrderLinkedPays = ref<any[]>([])
|
||||||
const completeRefundFormRef = ref<FormInstance>()
|
const completeRefundFormRef = ref<FormInstance>()
|
||||||
const completeRefundForm = reactive({ reason: '' })
|
function calcRefundableFromLinkedPays(list: any[]) {
|
||||||
const completeRefundRules: FormRules = {
|
|
||||||
reason: [{ required: true, message: '请填写退款原因', trigger: 'blur' }]
|
|
||||||
}
|
|
||||||
const completeOrderRefundTotal = computed(() => {
|
|
||||||
let sum = 0
|
let sum = 0
|
||||||
for (const o of completeOrderLinkedPays.value) {
|
for (const o of list || []) {
|
||||||
const st = Number(o?.status)
|
const st = Number(o?.status)
|
||||||
if (st === 2 || st === 5) sum += Number(o?.amount) || 0
|
if (st === 2 || st === 5) sum += Number(o?.amount) || 0
|
||||||
}
|
}
|
||||||
return Math.round(sum * 100) / 100
|
return Math.round(sum * 100) / 100
|
||||||
})
|
}
|
||||||
|
|
||||||
|
const completeRefundForm = reactive({ reason: '', refund_amount: undefined as number | undefined })
|
||||||
|
const completeOrderRefundMax = ref(0)
|
||||||
|
const completeOrderRefundTotal = computed(() => calcRefundableFromLinkedPays(completeOrderLinkedPays.value))
|
||||||
|
const completeRefundRules = computed<FormRules>(() => ({
|
||||||
|
refund_amount: [
|
||||||
|
{ required: true, message: '请输入退款金额', trigger: 'change' },
|
||||||
|
{
|
||||||
|
validator: (_r, v, cb) => {
|
||||||
|
const n = Number(v)
|
||||||
|
const cap = completeOrderRefundMax.value
|
||||||
|
if (!Number.isFinite(n) || n <= 0) return cb(new Error('退款金额须大于 0'))
|
||||||
|
if (cap > 0 && n > cap + 0.009) return cb(new Error(`不能超过 ¥${formatMoney(cap)}`))
|
||||||
|
cb()
|
||||||
|
},
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
reason: [{ required: true, message: '请填写退款原因', trigger: 'blur' }]
|
||||||
|
}))
|
||||||
|
|
||||||
function onCompleteOrderDialogClosed() {
|
function onCompleteOrderDialogClosed() {
|
||||||
completeOrderId.value = 0
|
completeOrderId.value = 0
|
||||||
completeOrderLinkedPays.value = []
|
completeOrderLinkedPays.value = []
|
||||||
completeRefundForm.reason = ''
|
completeRefundForm.reason = ''
|
||||||
|
completeRefundForm.refund_amount = undefined
|
||||||
|
completeOrderRefundMax.value = 0
|
||||||
completeRefundFormRef.value?.clearValidate()
|
completeRefundFormRef.value?.clearValidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4685,8 +4725,13 @@ async function loadCompleteOrderPayContext(orderId: number) {
|
|||||||
const r: any = await prescriptionOrderDetail({ id: orderId })
|
const r: any = await prescriptionOrderDetail({ id: orderId })
|
||||||
const d = r?.data ?? r ?? null
|
const d = r?.data ?? r ?? null
|
||||||
completeOrderLinkedPays.value = Array.isArray(d?.linked_pay_orders) ? d.linked_pay_orders : []
|
completeOrderLinkedPays.value = Array.isArray(d?.linked_pay_orders) ? d.linked_pay_orders : []
|
||||||
|
const linkedMax = calcRefundableFromLinkedPays(completeOrderLinkedPays.value)
|
||||||
|
const paid = Number(d?.paid) || 0
|
||||||
|
completeOrderRefundMax.value = linkedMax > 0 ? linkedMax : paid
|
||||||
|
completeRefundForm.refund_amount = completeOrderRefundMax.value
|
||||||
} catch {
|
} catch {
|
||||||
completeOrderLinkedPays.value = []
|
completeOrderLinkedPays.value = []
|
||||||
|
completeOrderRefundMax.value = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4699,7 +4744,11 @@ async function submitCompleteOrder() {
|
|||||||
if (!valid) return
|
if (!valid) return
|
||||||
completeOrderSubmitting.value = true
|
completeOrderSubmitting.value = true
|
||||||
try {
|
try {
|
||||||
await prescriptionOrderRefund({ id, reason: completeRefundForm.reason.trim() })
|
await prescriptionOrderRefund({
|
||||||
|
id,
|
||||||
|
reason: completeRefundForm.reason.trim(),
|
||||||
|
refund_amount: Number(completeRefundForm.refund_amount)
|
||||||
|
})
|
||||||
feedback.msgSuccess('退款成功')
|
feedback.msgSuccess('退款成功')
|
||||||
completeOrderDialogVisible.value = false
|
completeOrderDialogVisible.value = false
|
||||||
getLists()
|
getLists()
|
||||||
@@ -4743,21 +4792,57 @@ const refundOrderDialogVisible = ref(false)
|
|||||||
const refundOrderId = ref(0)
|
const refundOrderId = ref(0)
|
||||||
const refundOrderSubmitting = ref(false)
|
const refundOrderSubmitting = ref(false)
|
||||||
const refundOrderFormRef = ref<FormInstance>()
|
const refundOrderFormRef = ref<FormInstance>()
|
||||||
const refundOrderForm = reactive({ reason: '' })
|
const refundOrderMaxAmount = ref(0)
|
||||||
const refundOrderRules: FormRules = {
|
const refundOrderForm = reactive({ reason: '', refund_amount: undefined as number | undefined })
|
||||||
|
const refundOrderAlertTitle = computed(() => {
|
||||||
|
const cap = formatMoney(refundOrderMaxAmount.value)
|
||||||
|
const amt = formatMoney(refundOrderForm.refund_amount)
|
||||||
|
if (Number(refundOrderForm.refund_amount) >= refundOrderMaxAmount.value - 0.009) {
|
||||||
|
return `全额退款 ¥${cap}:关联收款标记已退款,已付清零。`
|
||||||
|
}
|
||||||
|
return `部分退款 ¥${amt}(上限 ¥${cap})`
|
||||||
|
})
|
||||||
|
const refundOrderRules = computed<FormRules>(() => ({
|
||||||
|
refund_amount: [
|
||||||
|
{ required: true, message: '请输入退款金额', trigger: 'change' },
|
||||||
|
{
|
||||||
|
validator: (_r, v, cb) => {
|
||||||
|
const n = Number(v)
|
||||||
|
const cap = refundOrderMaxAmount.value
|
||||||
|
if (!Number.isFinite(n) || n <= 0) return cb(new Error('退款金额须大于 0'))
|
||||||
|
if (cap > 0 && n > cap + 0.009) return cb(new Error(`不能超过 ¥${formatMoney(cap)}`))
|
||||||
|
cb()
|
||||||
|
},
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
],
|
||||||
reason: [{ required: true, message: '请填写退款原因', trigger: 'blur' }]
|
reason: [{ required: true, message: '请填写退款原因', trigger: 'blur' }]
|
||||||
}
|
}))
|
||||||
|
|
||||||
function onRefundOrderDialogClosed() {
|
function onRefundOrderDialogClosed() {
|
||||||
refundOrderId.value = 0
|
refundOrderId.value = 0
|
||||||
refundOrderForm.reason = ''
|
refundOrderForm.reason = ''
|
||||||
|
refundOrderForm.refund_amount = undefined
|
||||||
|
refundOrderMaxAmount.value = 0
|
||||||
refundOrderFormRef.value?.clearValidate()
|
refundOrderFormRef.value?.clearValidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
function openRefundOrder(row: { id: number }) {
|
async function openRefundOrder(row: { id: number }) {
|
||||||
refundOrderId.value = row.id
|
refundOrderId.value = row.id
|
||||||
refundOrderForm.reason = ''
|
refundOrderForm.reason = ''
|
||||||
|
refundOrderMaxAmount.value = 0
|
||||||
refundOrderDialogVisible.value = true
|
refundOrderDialogVisible.value = true
|
||||||
|
try {
|
||||||
|
const r: any = await prescriptionOrderDetail({ id: row.id })
|
||||||
|
const d = r?.data ?? r ?? null
|
||||||
|
const linked = Array.isArray(d?.linked_pay_orders) ? d.linked_pay_orders : []
|
||||||
|
const linkedMax = calcRefundableFromLinkedPays(linked)
|
||||||
|
const paid = Number(d?.paid) || 0
|
||||||
|
refundOrderMaxAmount.value = linkedMax > 0 ? linkedMax : paid
|
||||||
|
refundOrderForm.refund_amount = refundOrderMaxAmount.value
|
||||||
|
} catch {
|
||||||
|
refundOrderMaxAmount.value = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitRefundOrder() {
|
async function submitRefundOrder() {
|
||||||
@@ -4767,7 +4852,11 @@ async function submitRefundOrder() {
|
|||||||
if (!valid) return
|
if (!valid) return
|
||||||
refundOrderSubmitting.value = true
|
refundOrderSubmitting.value = true
|
||||||
try {
|
try {
|
||||||
await prescriptionOrderRefund({ id, reason: refundOrderForm.reason.trim() })
|
await prescriptionOrderRefund({
|
||||||
|
id,
|
||||||
|
reason: refundOrderForm.reason.trim(),
|
||||||
|
refund_amount: Number(refundOrderForm.refund_amount)
|
||||||
|
})
|
||||||
feedback.msgSuccess('退款成功')
|
feedback.msgSuccess('退款成功')
|
||||||
refundOrderDialogVisible.value = false
|
refundOrderDialogVisible.value = false
|
||||||
getLists()
|
getLists()
|
||||||
|
|||||||
@@ -351,11 +351,17 @@ class PrescriptionOrderController extends BaseAdminController
|
|||||||
public function refund()
|
public function refund()
|
||||||
{
|
{
|
||||||
$params = (new PrescriptionOrderValidate())->post()->goCheck('refund');
|
$params = (new PrescriptionOrderValidate())->post()->goCheck('refund');
|
||||||
|
$rawRefundAmount = $params['refund_amount'] ?? null;
|
||||||
|
$refundAmount = ($rawRefundAmount === null || $rawRefundAmount === '')
|
||||||
|
? null
|
||||||
|
: round((float) $rawRefundAmount, 2);
|
||||||
|
|
||||||
$result = PrescriptionOrderLogic::refund(
|
$result = PrescriptionOrderLogic::refund(
|
||||||
(int) $params['id'],
|
(int) $params['id'],
|
||||||
(string) ($params['reason'] ?? ''),
|
(string) ($params['reason'] ?? ''),
|
||||||
$this->adminId,
|
$this->adminId,
|
||||||
$this->adminInfo
|
$this->adminInfo,
|
||||||
|
$refundAmount
|
||||||
);
|
);
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
return $this->fail(PrescriptionOrderLogic::getError());
|
return $this->fail(PrescriptionOrderLogic::getError());
|
||||||
|
|||||||
@@ -782,6 +782,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
|
|||||||
'export_medication_days' => '天数',
|
'export_medication_days' => '天数',
|
||||||
'export_amount' => '总金额',
|
'export_amount' => '总金额',
|
||||||
'export_paid_amount' => '已付金额',
|
'export_paid_amount' => '已付金额',
|
||||||
|
'export_refund_amount' => '退款金额',
|
||||||
'export_agency_collect' => '代收金额',
|
'export_agency_collect' => '代收金额',
|
||||||
'export_tracking_number' => '快递单号',
|
'export_tracking_number' => '快递单号',
|
||||||
'export_sign_time' => '签收日期',
|
'export_sign_time' => '签收日期',
|
||||||
|
|||||||
@@ -2626,11 +2626,43 @@ class PrescriptionOrderLogic
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 业务订单退款:须填写原因;关联收款单标记为已退款,实付清零。
|
* 关联收款单中可退款的记录(已支付/待审核)
|
||||||
*
|
*
|
||||||
|
* @return array<int, array<string, mixed>>
|
||||||
|
*/
|
||||||
|
private static function linkedPayRefundableRows(int $prescriptionOrderId): array
|
||||||
|
{
|
||||||
|
$ids = self::linkedPayOrderIdList($prescriptionOrderId);
|
||||||
|
if ($ids === []) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Order::whereIn('id', $ids)
|
||||||
|
->whereNull('delete_time')
|
||||||
|
->whereIn('status', [2, 5])
|
||||||
|
->field(['id', 'amount'])
|
||||||
|
->order('id', 'asc')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function linkedPayRefundableTotal(int $prescriptionOrderId): float
|
||||||
|
{
|
||||||
|
$sum = 0.0;
|
||||||
|
foreach (self::linkedPayRefundableRows($prescriptionOrderId) as $row) {
|
||||||
|
$sum += (float) ($row['amount'] ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return round($sum, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务订单退款:须填写原因;可指定退款金额(部分退)或退满可退上限(全额)。
|
||||||
|
*
|
||||||
|
* @param float|null $refundAmount 为空或 0 表示退满可退上限
|
||||||
* @return array<string,mixed>|false
|
* @return array<string,mixed>|false
|
||||||
*/
|
*/
|
||||||
public static function refund(int $id, string $reason, int $adminId, array $adminInfo)
|
public static function refund(int $id, string $reason, int $adminId, array $adminInfo, ?float $refundAmount = null)
|
||||||
{
|
{
|
||||||
self::$error = '';
|
self::$error = '';
|
||||||
$reason = trim($reason);
|
$reason = trim($reason);
|
||||||
@@ -2663,30 +2695,72 @@ class PrescriptionOrderLogic
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$linkedPayOrderIds = self::linkedPayOrderIdList($id);
|
$maxRefundable = self::linkedPayRefundableTotal($id);
|
||||||
$refundedPayCount = 0;
|
$currentPaid = round((float) $order->paid, 2);
|
||||||
$refundedAmount = 0.0;
|
$cap = $maxRefundable > 0 ? $maxRefundable : $currentPaid;
|
||||||
|
if ($cap <= 0) {
|
||||||
|
self::$error = '当前无可退金额';
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($refundAmount === null || $refundAmount <= 0) {
|
||||||
|
$refundAmount = $cap;
|
||||||
|
} else {
|
||||||
|
$refundAmount = round($refundAmount, 2);
|
||||||
|
if ($refundAmount > $cap + 0.009) {
|
||||||
|
self::$error = '退款金额不能超过可退上限 ¥' . $cap;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$isFullRefund = $refundAmount >= $cap - 0.009;
|
||||||
|
$toRefundRows = self::linkedPayRefundableRows($id);
|
||||||
|
$refundedPayCount = 0;
|
||||||
|
$markedPayTotal = 0.0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($linkedPayOrderIds !== []) {
|
if ($isFullRefund && $toRefundRows !== []) {
|
||||||
$toRefundRows = Order::whereIn('id', $linkedPayOrderIds)
|
$ids = array_map('intval', array_column($toRefundRows, 'id'));
|
||||||
|
$refundedPayCount = Order::whereIn('id', $ids)
|
||||||
->whereNull('delete_time')
|
->whereNull('delete_time')
|
||||||
->whereIn('status', [2, 5])
|
->update(['status' => 4]);
|
||||||
->field(['id', 'amount'])
|
|
||||||
->select()
|
|
||||||
->toArray();
|
|
||||||
foreach ($toRefundRows as $pr) {
|
foreach ($toRefundRows as $pr) {
|
||||||
$refundedAmount += (float) ($pr['amount'] ?? 0);
|
$markedPayTotal += (float) ($pr['amount'] ?? 0);
|
||||||
}
|
}
|
||||||
$refundedAmount = round($refundedAmount, 2);
|
$markedPayTotal = round($markedPayTotal, 2);
|
||||||
if ($toRefundRows !== []) {
|
} elseif (!$isFullRefund && $toRefundRows !== []) {
|
||||||
$refundedPayCount = Order::whereIn('id', array_column($toRefundRows, 'id'))
|
$remaining = $refundAmount;
|
||||||
->whereNull('delete_time')
|
foreach ($toRefundRows as $pr) {
|
||||||
->update(['status' => 4]);
|
if ($remaining < 0.01) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$amt = round((float) ($pr['amount'] ?? 0), 2);
|
||||||
|
if ($amt <= $remaining + 0.001) {
|
||||||
|
Order::where('id', (int) $pr['id'])
|
||||||
|
->whereNull('delete_time')
|
||||||
|
->update(['status' => 4]);
|
||||||
|
$remaining -= $amt;
|
||||||
|
$markedPayTotal += $amt;
|
||||||
|
$refundedPayCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$markedPayTotal = round($markedPayTotal, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($isFullRefund) {
|
||||||
|
$order->fulfillment_status = 10;
|
||||||
|
$order->paid = 0;
|
||||||
|
} else {
|
||||||
|
$order->paid = round(max(0, $currentPaid - $refundAmount), 2);
|
||||||
|
if ($order->paid <= 0.009) {
|
||||||
|
$order->paid = 0;
|
||||||
|
$order->fulfillment_status = 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$order->fulfillment_status = 10;
|
$prevStoredRefund = round((float) ($order->refund_amount ?? 0), 2);
|
||||||
$order->paid = 0;
|
$order->refund_amount = round($prevStoredRefund + $refundAmount, 2);
|
||||||
$order->save();
|
$order->save();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
self::$error = $e->getMessage();
|
self::$error = $e->getMessage();
|
||||||
@@ -2694,21 +2768,34 @@ class PrescriptionOrderLogic
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$unassignSummary = self::clearDiagnosisAssistantOnComplete((int) $order->diagnosis_id);
|
$unassignSummary = '';
|
||||||
$logLine = '订单退款,状态变更为「退款」;原因:' . $reason;
|
if ($isFullRefund || (float) $order->paid <= 0.009) {
|
||||||
|
$unassignSummary = self::clearDiagnosisAssistantOnComplete((int) $order->diagnosis_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($isFullRefund) {
|
||||||
|
$logLine = '订单全额退款,状态变更为「退款」;原因:' . $reason . ';退款金额 ¥' . $refundAmount;
|
||||||
|
} else {
|
||||||
|
$logLine = '订单部分退款;原因:' . $reason . ';本次退款 ¥' . $refundAmount . ';已付余额 ¥' . $order->paid;
|
||||||
|
}
|
||||||
if ($refundedPayCount > 0) {
|
if ($refundedPayCount > 0) {
|
||||||
$logLine .= ';关联收款单 ' . $refundedPayCount . ' 笔已标记为已退款';
|
$logLine .= ';关联收款单 ' . $refundedPayCount . ' 笔已标记为已退款';
|
||||||
if ($refundedAmount > 0) {
|
if ($markedPayTotal > 0) {
|
||||||
$logLine .= ',合计 ¥' . $refundedAmount;
|
$logLine .= '(收款侧合计 ¥' . $markedPayTotal . ')';
|
||||||
}
|
}
|
||||||
} elseif ($linkedPayOrderIds !== []) {
|
} elseif ($toRefundRows !== []) {
|
||||||
$logLine .= ';关联收款单无待退款的已支付/待审核记录';
|
$logLine .= ';关联收款单无匹配的已支付/待审核记录可标记';
|
||||||
|
}
|
||||||
|
if ($isFullRefund) {
|
||||||
|
$logLine .= ';已付总额清零' . $unassignSummary;
|
||||||
}
|
}
|
||||||
$logLine .= ';已付总额清零' . $unassignSummary;
|
|
||||||
|
|
||||||
self::writeLog($id, $adminId, $adminInfo, 'refund', $logLine);
|
self::writeLog($id, $adminId, $adminInfo, 'refund', $logLine);
|
||||||
|
|
||||||
$out = $order->toArray();
|
$out = $order->toArray();
|
||||||
|
$out['this_refund_amount'] = $refundAmount;
|
||||||
|
$out['refund_full'] = $isFullRefund;
|
||||||
|
$out['refundable_cap'] = $cap;
|
||||||
self::maskInternalCostIfNeeded($out, $adminInfo);
|
self::maskInternalCostIfNeeded($out, $adminInfo);
|
||||||
self::maskRemarkExtraIfNeeded($out, $adminInfo);
|
self::maskRemarkExtraIfNeeded($out, $adminInfo);
|
||||||
self::attachLinkedPayOrders($out);
|
self::attachLinkedPayOrders($out);
|
||||||
@@ -3251,6 +3338,10 @@ class PrescriptionOrderLogic
|
|||||||
$paid = round((float) ($item['linked_pay_paid_total'] ?? 0), 2);
|
$paid = round((float) ($item['linked_pay_paid_total'] ?? 0), 2);
|
||||||
$item['export_amount'] = number_format($amt, 2, '.', '');
|
$item['export_amount'] = number_format($amt, 2, '.', '');
|
||||||
$item['export_paid_amount'] = number_format($paid, 2, '.', '');
|
$item['export_paid_amount'] = number_format($paid, 2, '.', '');
|
||||||
|
$refundStored = round((float) ($item['refund_amount'] ?? 0), 2);
|
||||||
|
$item['export_refund_amount'] = $refundStored > 0
|
||||||
|
? number_format($refundStored, 2, '.', '')
|
||||||
|
: '';
|
||||||
$item['export_agency_collect'] = number_format(round($amt - $paid, 2), 2, '.', '');
|
$item['export_agency_collect'] = number_format(round($amt - $paid, 2), 2, '.', '');
|
||||||
|
|
||||||
$item['export_tracking_number'] = (string) ($item['tracking_number'] ?? '');
|
$item['export_tracking_number'] = (string) ($item['tracking_number'] ?? '');
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ class PrescriptionOrderValidate extends BaseValidate
|
|||||||
'remark' => 'max:500',
|
'remark' => 'max:500',
|
||||||
'fulfillment_status' => 'require|integer|in:3,7,8,9,11,12',
|
'fulfillment_status' => 'require|integer|in:3,7,8,9,11,12',
|
||||||
'reason' => 'require|max:500',
|
'reason' => 'require|max:500',
|
||||||
|
'refund_amount' => 'float|egt:0',
|
||||||
'patient_name' => 'require|max:50',
|
'patient_name' => 'require|max:50',
|
||||||
'phone' => 'require|max:20',
|
'phone' => 'require|max:20',
|
||||||
'phone_tail' => 'max:20|regex:/^\\d*$/',
|
'phone_tail' => 'max:20|regex:/^\\d*$/',
|
||||||
@@ -77,7 +78,7 @@ class PrescriptionOrderValidate extends BaseValidate
|
|||||||
'linkPayOrder' => ['id', 'pay_order_id'],
|
'linkPayOrder' => ['id', 'pay_order_id'],
|
||||||
'requestCompletion' => ['id'],
|
'requestCompletion' => ['id'],
|
||||||
'complete' => ['id', 'fulfillment_status'],
|
'complete' => ['id', 'fulfillment_status'],
|
||||||
'refund' => ['id', 'reason'],
|
'refund' => ['id', 'reason', 'refund_amount'],
|
||||||
'submitGancaoRecipel' => ['id'],
|
'submitGancaoRecipel' => ['id'],
|
||||||
'previewGancaoRecipel' => ['id'],
|
'previewGancaoRecipel' => ['id'],
|
||||||
'patchPrescriptionPatient' => ['id', 'patient_name', 'phone'],
|
'patchPrescriptionPatient' => ['id', 'patient_name', 'phone'],
|
||||||
|
|||||||
Reference in New Issue
Block a user