273 lines
8.4 KiB
PHP
273 lines
8.4 KiB
PHP
<?php
|
|
|
|
namespace App\Models\Pay;
|
|
|
|
use App\Models\BaseModel;
|
|
use App\Models\BaseModelTrait;
|
|
use App\Models\YiiModels\User;
|
|
use Exception;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
|
|
|
/**
|
|
* App\Models\Pay\Bill
|
|
*
|
|
* @property int $id
|
|
* @property string|null $mchid 商户ID
|
|
* @property string|null $appid 应用ID
|
|
* @property string|null $billable_type 多态模型名称
|
|
* @property int|null $billable_id 多态模型ID
|
|
* @property int|null $user_id 用户ID
|
|
* @property string|null $openid Openid(微信支付涉及)
|
|
* @property string|null $title 订单名称
|
|
* @property int|null $pay_way 支付方式
|
|
* @property string $pay_amount 支付发起金额
|
|
* @property string $pay_no 商户订单号
|
|
* @property string|null $pay_service_no 支付商订单号
|
|
* @property string|null $pay_at 支付成功时间
|
|
* @property int $bill_status 账单状态
|
|
* @property int $pay_status 支付状态
|
|
* @property string|null $extra 额外数据
|
|
* @property string|null $remark 备注
|
|
* @property \Illuminate\Support\Carbon|null $created_at
|
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
|
* @property-read \Illuminate\Database\Eloquent\Model|\Eloquent $billable
|
|
* @property-read string $bill_status_string 账单状态名称
|
|
* @property-read float $can_refund_amount 可退款的金额
|
|
* @property-read string $created_at_format 创建时间的格式化
|
|
* @property-read string $pay_status_string 支付状态名称
|
|
* @property-read string $pay_way_alias 支付方式别名
|
|
* @property-read string $pay_way_string 支付方式名称
|
|
* @property-read float $refunded_amount 已退款的金额
|
|
* @property-read float $refunding_amount 退款中的金额
|
|
* @property-read string $status_string 状态名称
|
|
* @property-read string $updated_at_format 更新时间的格式化
|
|
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Pay\RefundBill[] $refunds 退款单
|
|
* @property-read int|null $refunds_count
|
|
* @property-read \App\Models\YiiModels\User|null $user 用户
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Pay\Bill newModelQuery()
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Pay\Bill newQuery()
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Pay\Bill query()
|
|
* @mixin \Eloquent
|
|
*/
|
|
class Bill extends BaseModel
|
|
{
|
|
use BaseModelTrait;
|
|
|
|
protected $attributes = [
|
|
'bill_status' => self::BILL_STATUS_UNSUCCESSFUL,
|
|
'pay_status' => self::PAY_STATUS_UN_PAY,
|
|
];
|
|
|
|
// 支付方式
|
|
const PAY_WAY_ALIAS = [
|
|
self::PAY_WAY_WECHAT => 'wechat',
|
|
self::PAY_WAY_ALIPAY => 'alipay',
|
|
self::PAY_WAY_UNIPAY => 'unipay',
|
|
];
|
|
const PAY_WAY = [
|
|
self::PAY_WAY_WECHAT => '微信',
|
|
self::PAY_WAY_ALIPAY => '支付宝',
|
|
self::PAY_WAY_UNIPAY => '银联',
|
|
];
|
|
const PAY_WAY_WECHAT = 1;
|
|
const PAY_WAY_ALIPAY = 2;
|
|
const PAY_WAY_UNIPAY = 3;
|
|
|
|
// 账单状态
|
|
const BILL_STATUS_LABEL = [
|
|
self::BILL_STATUS_UNSUCCESSFUL => 'warning',
|
|
self::BILL_STATUS_SUCCESSFUL => 'success',
|
|
];
|
|
const BILL_STATUS = [
|
|
self::BILL_STATUS_UNSUCCESSFUL => '未支付成功过',
|
|
self::BILL_STATUS_SUCCESSFUL => '支付成功过',
|
|
];
|
|
const BILL_STATUS_UNSUCCESSFUL = 0;
|
|
const BILL_STATUS_SUCCESSFUL = 1;
|
|
|
|
// 支付状态
|
|
const PAY_STATUS_LABEL = [
|
|
self::PAY_STATUS_UN_PAY => 'info',
|
|
self::PAY_STATUS_SUCCESS => 'success',
|
|
self::PAY_STATUS_FAIL => 'primary',
|
|
self::PAY_STATUS_CANCEL => 'default',
|
|
self::PAY_STATUS_REFUND_PART => 'warning',
|
|
self::PAY_STATUS_REFUND_FULL => 'danger',
|
|
];
|
|
const PAY_STATUS = [
|
|
self::PAY_STATUS_UN_PAY => '未支付',
|
|
self::PAY_STATUS_SUCCESS => '付款成功',
|
|
self::PAY_STATUS_FAIL => '付款失败',
|
|
self::PAY_STATUS_CANCEL => '付款取消',
|
|
self::PAY_STATUS_REFUND_PART => '部分退款',
|
|
self::PAY_STATUS_REFUND_FULL => '全额退款',
|
|
];
|
|
const PAY_STATUS_UN_PAY = 1;
|
|
const PAY_STATUS_SUCCESS = 2;
|
|
const PAY_STATUS_FAIL = 4;
|
|
const PAY_STATUS_CANCEL = 5;
|
|
const PAY_STATUS_REFUND_PART = 7;
|
|
const PAY_STATUS_REFUND_FULL = 8;
|
|
|
|
protected static function boot()
|
|
{
|
|
parent::boot();
|
|
static::creating(function (self $bill) {
|
|
if (!$bill->pay_no) {
|
|
$bill->pay_no = self::getNewNumber('pay_no');
|
|
}
|
|
});
|
|
}
|
|
|
|
public function billable(): MorphTo
|
|
{
|
|
return $this->morphTo();
|
|
}
|
|
|
|
/**
|
|
* @comment 用户
|
|
* @return BelongsTo
|
|
*/
|
|
public function user(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class, 'user_id');
|
|
}
|
|
|
|
/**
|
|
* @comment 退款单
|
|
* @return HasMany
|
|
*/
|
|
public function refunds(): HasMany
|
|
{
|
|
return $this->hasMany(RefundBill::class, 'bill_id');
|
|
}
|
|
|
|
/**
|
|
* pay_way_string
|
|
*
|
|
* @comment 支付方式名称
|
|
* @return string
|
|
*/
|
|
public function getPayWayStringAttribute(): string
|
|
{
|
|
return self::PAY_WAY[$this->pay_way] ?? '';
|
|
}
|
|
|
|
/**
|
|
* pay_way_alias
|
|
*
|
|
* @comment 支付方式别名
|
|
* @return string
|
|
*/
|
|
public function getPayWayAliasAttribute(): string
|
|
{
|
|
return self::PAY_WAY_ALIAS[$this->pay_way] ?? '';
|
|
}
|
|
|
|
/**
|
|
* bill_status_string
|
|
*
|
|
* @comment 账单状态名称
|
|
* @return string
|
|
*/
|
|
public function getBillStatusStringAttribute(): string
|
|
{
|
|
return self::BILL_STATUS[$this->bill_status] ?? '';
|
|
}
|
|
|
|
/**
|
|
* pay_status_string
|
|
*
|
|
* @comment 支付状态名称
|
|
* @return string
|
|
*/
|
|
public function getPayStatusStringAttribute(): string
|
|
{
|
|
return self::PAY_STATUS[$this->pay_status] ?? '';
|
|
}
|
|
|
|
/**
|
|
* refunded_amount
|
|
*
|
|
* @comment 已退款的金额
|
|
* @return float
|
|
*/
|
|
public function getRefundedAmountAttribute(): float
|
|
{
|
|
return $this->refunds->where('refund_status', 2)->sum('refund_amount');
|
|
}
|
|
|
|
/**
|
|
* refunding_amount
|
|
*
|
|
* @comment 退款中的金额
|
|
* @return float
|
|
*/
|
|
public function getRefundingAmountAttribute(): float
|
|
{
|
|
return $this->refunds->where('refund_status', 1)->sum('refund_amount');
|
|
}
|
|
|
|
/**
|
|
* can_refund_amount
|
|
*
|
|
* @comment 可退款的金额
|
|
* @return float
|
|
*/
|
|
public function getCanRefundAmountAttribute(): float
|
|
{
|
|
return $this->pay_amount - $this->refunded_amount - $this->refunding_amount;
|
|
}
|
|
|
|
/**
|
|
* 支付回调通知处理 - 异步.
|
|
*
|
|
* @param array $data
|
|
* @param int $payWay
|
|
* @return bool|string
|
|
*/
|
|
public static function handleNotify(array $data, int $payWay): bool|string
|
|
{
|
|
$bill = self::where('pay_no', $data['pay_no'])->where('pay_way', $payWay)->first();
|
|
if (!$bill) {
|
|
log_i("找不到支付订单信息:{$data['pay_no']}", 'pay-bill-error', $bill->pay_way_alias);
|
|
return '找不到支付订单信息';
|
|
}
|
|
if ($bill->pay_status != self::PAY_STATUS_UN_PAY) {
|
|
// [付款失败, 付款取消] 安排退款
|
|
if (in_array($bill->pay_status, [self::PAY_STATUS_FAIL, self::PAY_STATUS_CANCEL])) {
|
|
// todo
|
|
return true;
|
|
}
|
|
log_i("订单状态非未支付:{$data['pay_no']},订单状态:{$bill->pay_status_string}", 'pay-bill-error', $bill->pay_way_alias);
|
|
return '订单状态非未支付';
|
|
}
|
|
if ($bill->pay_amount != $data['pay_amount']) {
|
|
log_i("订单支付金额不一致:{$data['pay_no']},订单金额:{$bill->pay_amount},回调金额:{$data['pay_amount']}", 'pay-bill-error', $bill->pay_way_alias);
|
|
return '订单支付金额不一致';
|
|
}
|
|
|
|
$bill->fill([
|
|
'mchid' => $data['mchid'],
|
|
'appid' => $data['appid'],
|
|
'pay_service_no' => $data['pay_service_no'],
|
|
'pay_at' => $data['pay_at'],
|
|
'bill_status' => self::BILL_STATUS_SUCCESSFUL,
|
|
'pay_status' => self::PAY_STATUS_SUCCESS,
|
|
]);
|
|
$bill->save();
|
|
|
|
try {
|
|
$bill->loadMissing(['billable']);
|
|
if ($bill->billable) {
|
|
$bill->billable->handlePied($bill);
|
|
}
|
|
} catch (Exception $exception) {
|
|
|
|
}
|
|
return true;
|
|
}
|
|
}
|