支付流水记录
parent
95112ff7e4
commit
a0aa1c0eec
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Constants;
|
||||
|
||||
use App\Services\WeChatPayService;
|
||||
|
||||
class PayWay
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------
|
||||
| 微信支付
|
||||
|--------------------------------------------
|
||||
*/
|
||||
public const WXPAY_APP = 'wxpay_app'; // App 支付
|
||||
public const WXPAY_JSAPI = 'wxpay_jsapi'; // JSAPI 支付
|
||||
public const WXPAY_MINI = 'wxpay_mini'; // 小程序支付
|
||||
public const WXPAY_H5 = 'wxpay_h5'; // H5 支付
|
||||
public const WXPAY_NATIVE = 'wxpay_native'; // Native 支付
|
||||
|
||||
/**
|
||||
* 微信支付交易类型
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $wxpayTradeTypes = [
|
||||
self::WXPAY_APP => WeChatPayService::TRADE_TYPE_APP,
|
||||
self::WXPAY_JSAPI => WeChatPayService::TRADE_TYPE_JSAPI,
|
||||
self::WXPAY_MINI => WeChatPayService::TRADE_TYPE_JSAPI,
|
||||
self::WXPAY_H5 => WeChatPayService::TRADE_TYPE_H5,
|
||||
self::WXPAY_NATIVE => WeChatPayService::TRADE_TYPE_NATIVE,
|
||||
];
|
||||
}
|
||||
|
|
@ -44,24 +44,22 @@ class OrderController extends Controller
|
|||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$rules = [
|
||||
$isQuick = $request->filled('product');
|
||||
|
||||
$rules = $isQuick ? [
|
||||
'product.sku_id' => ['bail', 'required', 'int'],
|
||||
'product.quantity' => ['bail', 'required', 'int', 'min:1'],
|
||||
'shipping_address_id' => ['bail', 'required', 'int'],
|
||||
'coupon_id' => ['bail', 'nullable', 'int'],
|
||||
'note' => ['bail', 'nullable', 'string', 'max:255'],
|
||||
] : [
|
||||
'shopping_cart' => ['bail', 'required', 'array'],
|
||||
'shipping_address_id' => ['bail', 'required', 'int'],
|
||||
'coupon_id' => ['bail', 'nullable', 'int'],
|
||||
'note' => ['bail', 'nullable', 'string', 'max:255'],
|
||||
];
|
||||
|
||||
if ($isQuick = $request->filled('product')) {
|
||||
$rules = array_merge($rules, [
|
||||
'product.sku_id' => ['bail', 'required', 'int'],
|
||||
'product.quantity' => ['bail', 'required', 'int', 'min:1'],
|
||||
]);
|
||||
} else {
|
||||
$rules = array_merge($rules, [
|
||||
'shopping_cart' => ['bail', 'required', 'array'],
|
||||
]);
|
||||
}
|
||||
|
||||
$request->validate($rules, [], [
|
||||
$input = $request->validate($rules, [], [
|
||||
'product.sku_id' => '商品',
|
||||
'product.quantity' => '数量',
|
||||
'shopping_cart' => '购物车商品',
|
||||
|
|
@ -73,26 +71,26 @@ class OrderController extends Controller
|
|||
$user = $request->user();
|
||||
|
||||
try {
|
||||
$order = DB::transaction(function () use ($isQuick, $user, $request) {
|
||||
$order = DB::transaction(function () use ($isQuick, $user, $input) {
|
||||
$orderService = new OrderService();
|
||||
|
||||
if ($isQuick) {
|
||||
return $orderService->createQuickOrder(
|
||||
$user,
|
||||
$request->input('product.sku_id'),
|
||||
$request->input('product.quantity'),
|
||||
$request->input('shipping_address_id'),
|
||||
$request->input('coupon_id'),
|
||||
$request->input('note'),
|
||||
$input['product']['sku_id'],
|
||||
$input['product']['quantity'],
|
||||
$input['shipping_address_id'],
|
||||
$input['coupon_id'] ?? null,
|
||||
$input['note'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
return $orderService->createShoppingCartOrder(
|
||||
$user,
|
||||
$request->input('shopping_cart'),
|
||||
$request->input('shipping_address_id'),
|
||||
$request->input('coupon_id'),
|
||||
$request->input('note'),
|
||||
$input['shopping_cart'],
|
||||
$input['shipping_address_id'],
|
||||
$input['coupon_id'] ?? null,
|
||||
$input['note'] ?? null,
|
||||
);
|
||||
});
|
||||
} catch (QueryException $e) {
|
||||
|
|
|
|||
|
|
@ -34,13 +34,13 @@ class WeChatPayController extends Controller
|
|||
$payService = new PayService();
|
||||
|
||||
if (data_get($message, 'result_code') !== 'SUCCESS') {
|
||||
return $payService->payFailed($message['out_trade_no'], [
|
||||
return $payService->handleSuccessByPaySerialNumber($message['out_trade_no'], [
|
||||
'pay_sn' => $message['transaction_id'] ?? null,
|
||||
'failed_reason' => '['.$message['err_code'].']'.$message['err_code_des'],
|
||||
]);
|
||||
}
|
||||
|
||||
return $payService->paySuccess($message['out_trade_no'], [
|
||||
return $payService->handleFailedByPaySerialNumber($message['out_trade_no'], [
|
||||
'out_trade_no' => $message['transaction_id'],
|
||||
'pay_at' => Carbon::parse($message['time_end']),
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -13,11 +13,12 @@ class PayLog extends Model
|
|||
public const STATUS_SUCCESS = 1; // 成功
|
||||
public const STATUS_FAILED = 2; // 失败
|
||||
|
||||
/**
|
||||
* 支付方式
|
||||
*/
|
||||
public const PAY_WAY_WXPAY = 'wxpay'; // 微信支付
|
||||
public const PAY_WAY_ALIPAY = 'alipay'; // 支付宝
|
||||
public const PAY_WAY_WXPAY_APP = 'wxpay_app'; // 微信支付 - App 支付
|
||||
public const PAY_WAY_WXPAY_JSAPI = 'wxpay_jsapi'; // 微信支付 - JSAPI 支付
|
||||
public const PAY_WAY_WXPAY_MINI = 'wxpay_mini'; // 微信支付 - 小程序支付
|
||||
public const PAY_WAY_WXPAY_H5 = 'wxpay_h5'; // 微信支付 - H5 支付
|
||||
public const PAY_WAY_BALANCE = 'balance'; // 余额支付
|
||||
public const PAY_WAY_OFFLINE = 'offline'; // 线下支付
|
||||
|
||||
/**
|
||||
* @var array
|
||||
|
|
@ -60,4 +61,29 @@ class PayLog extends Model
|
|||
{
|
||||
return $this->status === static::STATUS_PENDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认支付方式是否是微信支付
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isWxpay(): bool
|
||||
{
|
||||
return in_array($this->pay_way, [
|
||||
static::PAY_WAY_WXPAY_APP,
|
||||
static::PAY_WAY_WXPAY_JSAPI,
|
||||
static::PAY_WAY_WXPAY_MINI,
|
||||
static::PAY_WAY_WXPAY_H5,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认支付方式是否是线下支付
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isOffline(): bool
|
||||
{
|
||||
return $this->pay_way === static::PAY_WAY_OFFLINE;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Constants\PayWay;
|
||||
use App\Endpoint\Api\Http\Resources\ProductSkuSimpleResource;
|
||||
use App\Endpoint\Api\Http\Resources\ShippingAddressResource;
|
||||
use App\Endpoint\Api\Http\Resources\UserCouponResource;
|
||||
use App\Exceptions\BizException;
|
||||
use App\Exceptions\ShippingNotSupportedException;
|
||||
use App\Helpers\Numeric;
|
||||
use App\Models\Coupon;
|
||||
use App\Models\DistributionPreIncomeJob;
|
||||
use App\Models\Order;
|
||||
use App\Models\OrderProduct;
|
||||
use App\Models\PayLog;
|
||||
use App\Models\ProductGift;
|
||||
use App\Models\ProductSku;
|
||||
use App\Models\ShippingAddress;
|
||||
|
|
@ -22,16 +23,6 @@ use Illuminate\Support\Facades\DB;
|
|||
|
||||
class OrderService
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $wxpayWays = [
|
||||
PayWay::WXPAY_APP,
|
||||
PayWay::WXPAY_JSAPI,
|
||||
PayWay::WXPAY_MINI,
|
||||
PayWay::WXPAY_H5,
|
||||
];
|
||||
|
||||
/**
|
||||
* 快速下单
|
||||
*
|
||||
|
|
@ -135,39 +126,104 @@ class OrderService
|
|||
$productsTotalAmount,
|
||||
$vipDiscountAmount,
|
||||
$couponDiscountAmount,
|
||||
$totalAmount,
|
||||
) = $this->calculateFees($mapProducts);
|
||||
|
||||
// 订单总费用
|
||||
$totalAmount += $shippingFee;
|
||||
$order = $this->storeOrder(
|
||||
$user,
|
||||
$shippingAddress,
|
||||
$productsTotalAmount,
|
||||
$couponDiscountAmount,
|
||||
$vipDiscountAmount,
|
||||
$shippingFee,
|
||||
$note,
|
||||
$coupon
|
||||
);
|
||||
|
||||
$orderAttrs = [
|
||||
'sn' => serial_number(),
|
||||
'user_coupon_id' => $coupon?->id,
|
||||
'coupon_discount_amount' => $couponDiscountAmount,
|
||||
'vip_discount_amount' => $vipDiscountAmount,
|
||||
'shipping_fee' => $shippingFee,
|
||||
'products_total_amount' => $productsTotalAmount,
|
||||
'total_amount' => $totalAmount,
|
||||
'note' => $note,
|
||||
// 收货地址
|
||||
'consignee_name' => $shippingAddress->consignee,
|
||||
'consignee_telephone' => $shippingAddress->telephone,
|
||||
'consignee_zone' => $shippingAddress->zone,
|
||||
'consignee_address' => $shippingAddress->address,
|
||||
];
|
||||
$this->storeOrderProducts($order, $mapProducts);
|
||||
|
||||
if ($totalAmount === 0) {
|
||||
$orderAttrs = array_merge([
|
||||
'status' => Order::STATUS_PAID,
|
||||
'pay_sn' => serial_number(),
|
||||
'pay_way' => Order::PAY_WAY_BALANCE,
|
||||
'pay_at' => now(),
|
||||
]);
|
||||
// 将优惠券标记为已使用
|
||||
$coupon?->markAsUse();
|
||||
|
||||
if ($order->total_amount === 0) {
|
||||
$this->pay($order, PayLog::PAY_WAY_BALANCE);
|
||||
|
||||
$order->refresh();
|
||||
}
|
||||
|
||||
$order = $user->orders()->create($orderAttrs);
|
||||
return $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存订单
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\ShippingAddress $shippingAddress
|
||||
* @param int $productsTotalAmount
|
||||
* @param int $couponDiscountAmount
|
||||
* @param int $vipDiscountAmount
|
||||
* @param int $shippingFee
|
||||
* @param string|null $note
|
||||
* @param \App\Models\Coupon|null $coupon
|
||||
* @return \App\Models\Order
|
||||
*/
|
||||
protected function storeOrder(
|
||||
User $user,
|
||||
ShippingAddress $shippingAddress,
|
||||
int $productsTotalAmount,
|
||||
int $couponDiscountAmount,
|
||||
int $vipDiscountAmount,
|
||||
int $shippingFee,
|
||||
?string $note = null,
|
||||
?Coupon $coupon = null,
|
||||
): Order {
|
||||
// 订单支付金额=商品总额-券折扣金额-会员折扣金额+邮费
|
||||
$totalAmount = $productsTotalAmount - $couponDiscountAmount - $vipDiscountAmount;
|
||||
|
||||
if ($totalAmount < 0) {
|
||||
$totalAmount = 0;
|
||||
}
|
||||
|
||||
$totalAmount += $shippingFee;
|
||||
|
||||
$totalAmount=0;
|
||||
|
||||
do {
|
||||
// 如果订单号重复,则直接重试
|
||||
try {
|
||||
$attrs = [
|
||||
'sn' => serial_number(),
|
||||
'user_coupon_id' => $coupon?->id,
|
||||
'coupon_discount_amount' => $couponDiscountAmount,
|
||||
'vip_discount_amount' => $vipDiscountAmount,
|
||||
'shipping_fee' => $shippingFee,
|
||||
'products_total_amount' => $productsTotalAmount,
|
||||
'total_amount' => $totalAmount, // 商品总额-券折扣金额-会员折扣金额+邮费
|
||||
'note' => $note,
|
||||
// 收货地址
|
||||
'consignee_name' => $shippingAddress->consignee,
|
||||
'consignee_telephone' => $shippingAddress->telephone,
|
||||
'consignee_zone' => $shippingAddress->zone,
|
||||
'consignee_address' => $shippingAddress->address,
|
||||
];
|
||||
|
||||
return $user->orders()->create($attrs);
|
||||
} catch (QueryException $e) {
|
||||
if (strpos($e->getMessage(), 'Duplicate entry') === false) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存订单商品
|
||||
*
|
||||
* @param \App\Models\Order $order
|
||||
* @param array $mapProducts
|
||||
* @return void
|
||||
*/
|
||||
public function storeOrderProducts(Order $order, array $mapProducts)
|
||||
{
|
||||
$orderProducts = [];
|
||||
|
||||
foreach ($mapProducts as $product) {
|
||||
|
|
@ -231,13 +287,7 @@ class OrderService
|
|||
}
|
||||
}
|
||||
|
||||
// 处理赠品
|
||||
OrderProduct::insert($orderProducts);
|
||||
|
||||
// 将优惠券标记为已使用
|
||||
$coupon?->markAsUse();
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -254,22 +304,16 @@ class OrderService
|
|||
'stock' => DB::raw("stock - {$qty}"), // 库存
|
||||
]);
|
||||
|
||||
try {
|
||||
return retry(5, function () use ($sku, $qty) {
|
||||
// 如果是因为赠品库存不足引起的异常,则需重试
|
||||
do {
|
||||
try {
|
||||
return $this->deductGifts($sku, $qty);
|
||||
}, 0, function ($e) {
|
||||
// 如果赠品库存不足时,需重试
|
||||
return $e instanceof QueryException
|
||||
&& strpos($e->getMessage(), 'Numeric value out of range') !== false;
|
||||
});
|
||||
} catch (QueryException $e) {
|
||||
// 赠品库存不足
|
||||
if (strpos($e->getMessage(), 'Numeric value out of range') !== false) {
|
||||
$e = new BizException('下单人数过多,请稍后再试!');
|
||||
} catch (QueryException $e) {
|
||||
if (strpos($e->getMessage(), 'Numeric value out of range') === false) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -405,10 +449,14 @@ class OrderService
|
|||
$productsTotalAmount,
|
||||
$vipDiscountAmount,
|
||||
$couponDiscountAmount,
|
||||
$totalAmount,
|
||||
) = $this->calculateFees($mapProducts);
|
||||
|
||||
// 订单总费用
|
||||
$totalAmount = $productsTotalAmount - $couponDiscountAmount - $vipDiscountAmount;
|
||||
|
||||
if ($totalAmount < 0) {
|
||||
$totalAmount = 0;
|
||||
}
|
||||
|
||||
$totalAmount += $shippingFee;
|
||||
|
||||
return [
|
||||
|
|
@ -441,21 +489,16 @@ class OrderService
|
|||
$vipDiscountAmount = 0;
|
||||
$couponDiscountAmount = 0;
|
||||
|
||||
|
||||
foreach ($products as $product) {
|
||||
$productsTotalAmount += $product['total_amount'];
|
||||
$vipDiscountAmount += $product['vip_discount_amount'];
|
||||
$couponDiscountAmount += $product['coupon_discount_amount'];
|
||||
}
|
||||
|
||||
// 订单总额
|
||||
$totalAmount = $productsTotalAmount - $vipDiscountAmount - $couponDiscountAmount;
|
||||
|
||||
return [
|
||||
$productsTotalAmount,
|
||||
$vipDiscountAmount,
|
||||
$couponDiscountAmount,
|
||||
$totalAmount,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -706,54 +749,40 @@ class OrderService
|
|||
throw new BizException('订单状态不是待付款');
|
||||
}
|
||||
|
||||
$payLog = $order->payLogs()->create([
|
||||
'pay_sn' => serial_number(),
|
||||
'pay_way' => $payWay,
|
||||
]);
|
||||
do {
|
||||
$payLog = null;
|
||||
|
||||
switch ($payWay) {
|
||||
case PayWay::WXPAY_APP:
|
||||
case PayWay::WXPAY_H5:
|
||||
case PayWay::WXPAY_JSAPI:
|
||||
case PayWay::WXPAY_MINI:
|
||||
return (new WeChatPayService())->pay([
|
||||
'body' => app_settings('app_name').'-商城订单',
|
||||
'out_trade_no' => $payLog->pay_sn,
|
||||
'total_fee' => $order->total_amount,
|
||||
'trade_type' => PayWay::$wxpayTradeTypes[$payWay],
|
||||
try {
|
||||
$payLog = $order->payLogs()->create([
|
||||
'pay_sn' => serial_number(),
|
||||
'pay_way' => $payWay,
|
||||
]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (QueryException $e) {
|
||||
if (strpos($e->getMessage(), 'Duplicate entry') === false) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
} while ($payLog === null);
|
||||
|
||||
/**
|
||||
* 支付成功
|
||||
*
|
||||
* @param string $sn
|
||||
* @param array $params
|
||||
* @return \App\Models\Order
|
||||
*/
|
||||
public function paySuccess(Order $order, array $params = []): Order
|
||||
{
|
||||
if (! $order->isPending()) {
|
||||
throw new BizException('订单状态不是待支付');
|
||||
// 如果支付方式为线下支付,或支付金额为 0,则按支付完成处理
|
||||
if ($payLog->isOffline() || $order->total_amount === 0) {
|
||||
return (new PayService())->handleSuccess($payLog, [
|
||||
'pay_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
$order->update([
|
||||
'pay_sn' => $params['pay_sn'],
|
||||
'pay_way' => $params['pay_way'],
|
||||
'pay_at' => $params['pay_at'],
|
||||
'out_trade_no' => $params['out_trade_no'],
|
||||
'status' => Order::STATUS_PAID,
|
||||
]);
|
||||
if ($payLog->isWxpay()) {
|
||||
if (! isset(WeChatPayService::$tradeTypes[$payLog->pay_way])) {
|
||||
throw new BizException('支付方式不支持');
|
||||
}
|
||||
|
||||
DistributionPreIncomeJob::create([
|
||||
'jobable_id' => $order->id,
|
||||
'jobable_type' => $order->getMorphClass(),
|
||||
'remarks' => '支付订单',
|
||||
]);
|
||||
|
||||
return $order;
|
||||
return (new WeChatPayService())->pay([
|
||||
'body' => app_settings('app_name').'-商城订单',
|
||||
'out_trade_no' => $payLog->pay_sn,
|
||||
'total_fee' => $order->total_amount,
|
||||
'trade_type' => WeChatPayService::$tradeTypes[$payLog->pay_way],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Constants\PayWay;
|
||||
use App\Exceptions\BizException;
|
||||
use App\Models\DistributionPreIncomeJob;
|
||||
use App\Models\Order;
|
||||
use App\Models\PayLog;
|
||||
|
||||
class PayService
|
||||
{
|
||||
/**
|
||||
* 支付成功
|
||||
* 根据支付流水号处理支付成功业务
|
||||
*
|
||||
* @param string $sn
|
||||
* @param array $params
|
||||
|
|
@ -18,10 +18,24 @@ class PayService
|
|||
*
|
||||
* @throws \App\Exceptions\BizException
|
||||
*/
|
||||
public function paySuccess(string $sn, array $params = []): PayLog
|
||||
public function handleSuccessByPaySerialNumber(string $paySerialNumber, array $params = []): PayLog
|
||||
{
|
||||
$payLog = PayLog::where('pay_sn', $sn)->firstOrFail();
|
||||
$payLog = PayLog::where('pay_sn', $paySerialNumber)->lockForUpdate()->first();
|
||||
|
||||
return $this->handleSuccess($payLog, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理支付成功业务
|
||||
*
|
||||
* @param \App\Models\PayLog $payLog
|
||||
* @param array $params
|
||||
* @return \App\Models\PayLog
|
||||
*
|
||||
* @throws \App\Exceptions\BizException
|
||||
*/
|
||||
public function handleSuccess(PayLog $payLog, array $params = []): PayLog
|
||||
{
|
||||
if (! $payLog->isPending()) {
|
||||
throw new BizException('支付记录状态异常');
|
||||
}
|
||||
|
|
@ -33,25 +47,30 @@ class PayService
|
|||
]);
|
||||
|
||||
if ($payLog->payable instanceof Order) {
|
||||
switch ($payLog->pay_way) {
|
||||
case PayWay::WXPAY_APP:
|
||||
case PayWay::WXPAY_H5:
|
||||
case PayWay::WXPAY_JSAPI:
|
||||
case PayWay::WXPAY_MINI:
|
||||
case PayWay::WXPAY_NATIVE:
|
||||
$payWay = Order::PAY_WAY_WXPAY;
|
||||
break;
|
||||
$order = $payLog->payable;
|
||||
|
||||
default:
|
||||
$payWay = $payLog->pay_way;
|
||||
break;
|
||||
// 支付方式
|
||||
$payWay = $payLog->pay_way;
|
||||
if ($payLog->isWxpay()) {
|
||||
$payWay = Order::PAY_WAY_WXPAY;
|
||||
}
|
||||
|
||||
(new OrderService())->paySuccess($payLog->payable, [
|
||||
if (! $order->isPending()) {
|
||||
throw new BizException('订单状态不是待支付');
|
||||
}
|
||||
|
||||
$order->update([
|
||||
'pay_sn' => $payLog->pay_sn,
|
||||
'pay_way' => $payWay,
|
||||
'pay_at' => $payLog->pay_at,
|
||||
'out_trade_no' => $payLog->out_trade_no,
|
||||
'status' => Order::STATUS_PAID,
|
||||
]);
|
||||
|
||||
DistributionPreIncomeJob::create([
|
||||
'jobable_id' => $order->id,
|
||||
'jobable_type' => $order->getMorphClass(),
|
||||
'remarks' => '支付订单',
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +78,7 @@ class PayService
|
|||
}
|
||||
|
||||
/**
|
||||
* 支付失败
|
||||
* 根据支付流水号处理支付失败业务
|
||||
*
|
||||
* @param string $sn
|
||||
* @param array $params
|
||||
|
|
@ -67,10 +86,24 @@ class PayService
|
|||
*
|
||||
* @throws \App\Exceptions\BizException
|
||||
*/
|
||||
public function payFailed(string $sn, array $params = []): PayLog
|
||||
public function handleFailedByPaySerialNumber(string $paySerialNumber, array $params = []): PayLog
|
||||
{
|
||||
$payLog = PayLog::where('pay_sn', $sn)->firstOrFail();
|
||||
$payLog = PayLog::where('pay_sn', $paySerialNumber)->lockForUpdate()->first();
|
||||
|
||||
return $this->handleFailed($payLog, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理支付失败业务
|
||||
*
|
||||
* @param \App\Models\PayLog $payLog
|
||||
* @param array $params
|
||||
* @return \App\Models\PayLog
|
||||
*
|
||||
* @throws \App\Exceptions\BizException
|
||||
*/
|
||||
public function handleFailed(PayLog $payLog, array $params = []): PayLog
|
||||
{
|
||||
if (! $payLog->isPending()) {
|
||||
throw new BizException('支付记录状态异常');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Services;
|
||||
|
||||
use App\Exceptions\WeChatPayException;
|
||||
use App\Models\PayLog;
|
||||
use Closure;
|
||||
use EasyWeChat\Factory;
|
||||
use EasyWeChat\Payment\Application;
|
||||
|
|
@ -22,10 +23,11 @@ class WeChatPayService
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
public static $allowTradeTypes = [
|
||||
self::TRADE_TYPE_JSAPI,
|
||||
self::TRADE_TYPE_APP,
|
||||
self::TRADE_TYPE_H5,
|
||||
public static $tradeTypes = [
|
||||
PayLog::PAY_WAY_WXPAY_APP => self::TRADE_TYPE_APP,
|
||||
PayLog::PAY_WAY_WXPAY_JSAPI => self::TRADE_TYPE_JSAPI,
|
||||
PayLog::PAY_WAY_WXPAY_MINI => self::TRADE_TYPE_JSAPI,
|
||||
PayLog::PAY_WAY_WXPAY_H5 => self::TRADE_TYPE_H5,
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -64,7 +66,7 @@ class WeChatPayService
|
|||
$params['trade_type'] = static::TRADE_TYPE_APP;
|
||||
}
|
||||
|
||||
if (! in_array($params['trade_type'], static::$allowTradeTypes)) {
|
||||
if (! in_array($params['trade_type'], static::$tradeTypes)) {
|
||||
throw new WeChatPayException(sprintf('交易类型 [%s] 暂不支持', $params['trade_type']), $params);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,3 +37,32 @@ if (! function_exists('serial_number')) {
|
|||
return date('YmdHis').sprintf('%06d', mt_rand(1, 999999));
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('serial_number')) {
|
||||
/**
|
||||
* 生成流水号
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function serial_number(): string
|
||||
{
|
||||
return date('YmdHis').sprintf('%06d', mt_rand(1, 999999));
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('trim_trailing_zeros')) {
|
||||
/**
|
||||
* 去除数字字符串小数点后多余的 0
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
function trim_trailing_zeros($value)
|
||||
{
|
||||
if (is_numeric($value) && strpos($value, '.') !== false) {
|
||||
$value = rtrim(rtrim($value, '0'), '.') ?: '0';
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class CreateOrdersTable extends Migration
|
|||
$table->string('note')->nullable()->comment('客户备注');
|
||||
$table->string('remark')->nullable()->comment('订单备注');
|
||||
// 支付信息
|
||||
$table->string('pay_sn')->nullable()->comment('支付单号');
|
||||
$table->string('pay_sn')->nullable()->comment('支付流水号');
|
||||
$table->string('pay_way')->nullable()->comment('支付方式');
|
||||
$table->timestamp('pay_at')->nullable()->comment('支付时间');
|
||||
// 收货信息
|
||||
|
|
|
|||
Loading…
Reference in New Issue