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

167 lines
6.3 KiB
PHP

<?php
namespace App\Http\Controllers\Mini;
use App\Exceptions\RepositoryException;
use App\Models\BillModel;
use App\Models\PaymentModel;
use App\Services\BillNumberService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\SystemTool\Models\SysFileModel;
use Throwable;
/**
* 小程序门店支付(选择本店账单合并付款,提交汇款凭证,后台审核通过后账单置已支付)
*/
#[RequestAttribute('/mini', 'mini', authGuard: 'users')]
class PaymentController extends BaseMiniController
{
/** 支付配置:收款码图片与对公汇款信息(付款页展示) */
#[GetRoute('/payment/config', authorize: true)]
public function config(): JsonResponse
{
// 配置值支持图片URL或文件ID(文件ID解析为预览地址)
$resolve = static function (mixed $value): string {
$value = trim((string) $value);
if ($value === '') {
return '';
}
if (is_numeric($value)) {
return (string) (SysFileModel::query()->find((int) $value)?->preview_url ?? '');
}
return $value;
};
return $this->success([
'wechat_qrcode' => $resolve(site_config('pay.wechat_qrcode', '')),
'alipay_qrcode' => $resolve(site_config('pay.alipay_qrcode', '')),
'bank_info' => (string) site_config('pay.bank_info', ''),
]);
}
/** 支付记录列表:当前门店强制过滤,?status=&page=&pageSize= */
#[GetRoute('/payment', authorize: true)]
public function index(Request $request): JsonResponse
{
$store = $this->currentStore($request);
$query = PaymentModel::query()
->where('store_id', $store->id)
->withCount('bills');
if ($request->filled('status')) {
$query->where('status', (int) $request->input('status'));
}
$data = $query->orderBy('id', 'desc')
->paginate((int) $request->input('pageSize', 10))
->toArray();
return $this->success($data);
}
/**
* 发起付款:合并选择本店未支付账单,提交支付方式与汇款凭证(后台审核)
* @throws Throwable
*/
#[PostRoute('/payment', authorize: true)]
public function create(Request $request): JsonResponse
{
$data = $request->validate([
'bill_ids' => 'required|array|min:1',
'bill_ids.*' => 'integer|distinct',
'pay_method' => 'required|integer|in:1,2,3',
'voucher_ids' => 'required|array|min:1',
'voucher_ids.*' => 'integer|distinct',
'remark' => 'nullable|string|max:255',
], [
'bill_ids.required' => '请选择要付款的账单',
'bill_ids.min' => '请选择要付款的账单',
'pay_method.required' => '请选择支付方式',
'pay_method.in' => '支付方式不正确',
'voucher_ids.required' => '请上传汇款凭证',
'voucher_ids.min' => '请上传汇款凭证',
'remark.max' => '备注超过最大长度',
]);
$store = $this->currentStore($request);
$billIds = array_map('intval', $data['bill_ids']);
$payment = DB::transaction(function () use ($store, $data, $billIds) {
$bills = BillModel::query()
->where('store_id', $store->id)
->whereIn('id', $billIds)
->lockForUpdate()
->get();
if ($bills->count() !== count($billIds)) {
throw new RepositoryException('包含不属于本店的账单,请刷新后重试');
}
foreach ($bills as $bill) {
if ($bill->status === BillModel::STATUS_PAID) {
throw new RepositoryException('账单 ' . $bill->bill_no . ' 已支付,请刷新后重试');
}
if ((int) $bill->payment_id !== 0) {
throw new RepositoryException('账单 ' . $bill->bill_no . ' 已在支付审核中,请勿重复提交');
}
}
$amount = $bills->reduce(
static fn (string $carry, BillModel $bill): string => bcadd($carry, (string) $bill->total_amount, 2),
'0'
);
$payment = PaymentModel::create([
'payment_no' => app(BillNumberService::class)->make('ZF'),
'store_id' => $store->id,
'amount' => $amount,
'pay_method' => (int) $data['pay_method'],
'voucher_ids' => array_map('intval', $data['voucher_ids']),
'status' => PaymentModel::STATUS_PENDING,
'remark' => (string) ($data['remark'] ?? ''),
]);
// 锁定账单到本支付记录(审核拒绝后释放,可重新付款)
BillModel::query()->whereIn('id', $bills->pluck('id'))->update(['payment_id' => $payment->id]);
return $payment;
});
return $this->success([
'id' => $payment->id,
'payment_no' => $payment->payment_no,
'amount' => $payment->amount,
], '付款申请已提交,请等待商家审核');
}
/** 支付记录详情(校验归属;含合并账单与凭证图片) */
#[GetRoute('/payment/{id}', authorize: true, where: ['id' => '[0-9]+'])]
public function detail(int $id, Request $request): JsonResponse
{
$store = $this->currentStore($request);
$payment = PaymentModel::query()
->where('store_id', $store->id)
->find($id);
if ($payment === null) {
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,
]);
}
}