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; } }