Files
xin-procurement/app/Http/Controllers/Recon/PaymentController.php
T
2026-08-29 13:54:06 +08:00

151 lines
6.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Http\Controllers\Recon;
use App\Exceptions\RepositoryException;
use App\Models\BillModel;
use App\Models\PaymentModel;
use App\Models\StoreModel;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Throwable;
/**
* 支付记录(小程序合并付款提交汇款凭证;后台审核:通过后关联账单批量置已支付,拒绝释放账单)
*/
#[RequestAttribute('/recon/payment', 'recon.payment')]
class PaymentController extends BaseController
{
protected array $searchField = [
'store_id' => '=',
'status' => '=',
'pay_type' => '=',
'pay_method' => '=',
'payment_no' => 'like',
];
/** 支付记录列表(待审核优先) */
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$data = $this->buildSearch($params, PaymentModel::query()
->with(['store:id,name', 'auditor:id,nickname'])
->withCount('bills'))
->orderBy('status')
->orderBy('id', 'desc')
->paginate($pageSize)
->toArray();
return $this->success($data);
}
/** 支付记录详情:支付信息 + 凭证图片 + 合并付款的账单 */
#[GetRoute(route: '/{id}', authorize: 'query', where: ['id' => '[0-9]+'])]
public function detail(int $id): JsonResponse
{
$payment = PaymentModel::with(['store:id,name,contact,phone', 'auditor:id,nickname'])->find($id);
if (empty($payment)) {
throw new RepositoryException('支付记录不存在');
}
$bills = $payment->bills()
->orderBy('id')
->get(['id', 'bill_no', 'bill_date', 'product_amount', 'delivery_fee', 'added_amount', 'after_sale', 'total_amount', 'status'])
->toArray();
$data = $payment->toArray();
$data['voucher_urls'] = $payment->voucherUrls();
return $this->success([
'payment' => $data,
'bills' => $bills,
]);
}
/**
* 审核支付记录:通过 → 关联账单全部置已支付;拒绝 → 释放账单(可重新发起付款)
* @throws Throwable
*/
#[PutRoute(route: '/{id}/audit', authorize: 'audit', where: ['id' => '[0-9]+'])]
public function audit(int $id, Request $request): JsonResponse
{
$data = $request->validate([
'result' => 'required|string|in:pass,reject',
'audit_remark' => 'nullable|string|max:255|required_if:result,reject',
], [
'result.required' => '请选择审核结果',
'result.in' => '审核结果不正确',
'audit_remark.required_if' => '拒绝时请填写原因',
'audit_remark.max' => '审核备注超过最大长度',
]);
return DB::transaction(function () use ($id, $data, $request) {
$payment = PaymentModel::query()->lockForUpdate()->find($id);
if (empty($payment)) {
throw new RepositoryException('支付记录不存在');
}
if ($payment->status !== PaymentModel::STATUS_PENDING) {
throw new RepositoryException('该支付记录已审核,请勿重复操作');
}
$bills = $payment->bills()->lockForUpdate()->get();
$auditorId = (int) $request->user()->id;
$now = now();
if ($data['result'] === 'pass') {
// 任一账单已通过其他方式收款(如线下登记)则整批中止,避免重复收款
$paid = $bills->where('status', BillModel::STATUS_PAID);
if ($paid->isNotEmpty()) {
throw new RepositoryException(
'账单 ' . $paid->pluck('bill_no')->implode('、') . ' 已收款,请核实后再审核'
);
}
$methodName = PaymentModel::METHOD_NAMES[$payment->pay_method] ?? '线上支付';
BillModel::query()->whereIn('id', $bills->pluck('id'))->update([
'status' => BillModel::STATUS_PAID,
'paid_at' => $now,
'paid_operator_id' => $auditorId,
'pay_remark' => $methodName . '(支付单号 ' . $payment->payment_no . '',
]);
// 按门店累加总采购金额(只统计商品金额,不含配送费/附加金额)
foreach ($bills->groupBy('store_id')->sortKeys() as $storeId => $storeBills) {
$amount = '0';
foreach ($storeBills as $storeBill) {
$amount = bcadd($amount, (string) $storeBill->product_amount, 2);
}
$store = StoreModel::query()->lockForUpdate()->find((int) $storeId);
if ($store !== null) {
$store->total_purchase_amount = bcadd((string) $store->total_purchase_amount, $amount, 2);
$store->save();
}
}
$payment->status = PaymentModel::STATUS_APPROVED;
} else {
// 拒绝:释放账单,门店可重新发起付款
BillModel::query()->whereIn('id', $bills->pluck('id'))->update(['payment_id' => 0]);
$payment->status = PaymentModel::STATUS_REJECTED;
}
$payment->audited_at = $now;
$payment->auditor_id = $auditorId;
$payment->audit_remark = (string) ($data['audit_remark'] ?? '');
$payment->save();
return $this->success(
[],
$payment->status === PaymentModel::STATUS_APPROVED
? '审核通过,' . $bills->count() . ' 张账单已置为已支付'
: '已拒绝,账单已释放可重新付款'
);
});
}
}