This commit is contained in:
Your Name
2026-06-04 09:25:00 +08:00
parent 6b528c34c8
commit 5ab3be1fdd
7 changed files with 361 additions and 64 deletions
@@ -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
*/
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 = '';
$reason = trim($reason);
@@ -2663,30 +2695,72 @@ class PrescriptionOrderLogic
return false;
}
$linkedPayOrderIds = self::linkedPayOrderIdList($id);
$refundedPayCount = 0;
$refundedAmount = 0.0;
$maxRefundable = self::linkedPayRefundableTotal($id);
$currentPaid = round((float) $order->paid, 2);
$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 {
if ($linkedPayOrderIds !== []) {
$toRefundRows = Order::whereIn('id', $linkedPayOrderIds)
if ($isFullRefund && $toRefundRows !== []) {
$ids = array_map('intval', array_column($toRefundRows, 'id'));
$refundedPayCount = Order::whereIn('id', $ids)
->whereNull('delete_time')
->whereIn('status', [2, 5])
->field(['id', 'amount'])
->select()
->toArray();
->update(['status' => 4]);
foreach ($toRefundRows as $pr) {
$refundedAmount += (float) ($pr['amount'] ?? 0);
$markedPayTotal += (float) ($pr['amount'] ?? 0);
}
$refundedAmount = round($refundedAmount, 2);
if ($toRefundRows !== []) {
$refundedPayCount = Order::whereIn('id', array_column($toRefundRows, 'id'))
->whereNull('delete_time')
->update(['status' => 4]);
$markedPayTotal = round($markedPayTotal, 2);
} elseif (!$isFullRefund && $toRefundRows !== []) {
$remaining = $refundAmount;
foreach ($toRefundRows as $pr) {
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;
$order->paid = 0;
$prevStoredRefund = round((float) ($order->refund_amount ?? 0), 2);
$order->refund_amount = round($prevStoredRefund + $refundAmount, 2);
$order->save();
} catch (\Throwable $e) {
self::$error = $e->getMessage();
@@ -2694,21 +2768,34 @@ class PrescriptionOrderLogic
return false;
}
$unassignSummary = self::clearDiagnosisAssistantOnComplete((int) $order->diagnosis_id);
$logLine = '订单退款,状态变更为「退款」;原因:' . $reason;
$unassignSummary = '';
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) {
$logLine .= ';关联收款单 ' . $refundedPayCount . ' 笔已标记为已退款';
if ($refundedAmount > 0) {
$logLine .= '合计 ¥' . $refundedAmount;
if ($markedPayTotal > 0) {
$logLine .= '(收款侧合计 ¥' . $markedPayTotal . '';
}
} elseif ($linkedPayOrderIds !== []) {
$logLine .= ';关联收款单无待退款的已支付/待审核记录';
} elseif ($toRefundRows !== []) {
$logLine .= ';关联收款单无匹配的已支付/待审核记录可标记';
}
if ($isFullRefund) {
$logLine .= ';已付总额清零' . $unassignSummary;
}
$logLine .= ';已付总额清零' . $unassignSummary;
self::writeLog($id, $adminId, $adminInfo, 'refund', $logLine);
$out = $order->toArray();
$out['this_refund_amount'] = $refundAmount;
$out['refund_full'] = $isFullRefund;
$out['refundable_cap'] = $cap;
self::maskInternalCostIfNeeded($out, $adminInfo);
self::maskRemarkExtraIfNeeded($out, $adminInfo);
self::attachLinkedPayOrders($out);
@@ -3251,6 +3338,10 @@ class PrescriptionOrderLogic
$paid = round((float) ($item['linked_pay_paid_total'] ?? 0), 2);
$item['export_amount'] = number_format($amt, 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_tracking_number'] = (string) ($item['tracking_number'] ?? '');