495 lines
16 KiB
PHP
495 lines
16 KiB
PHP
<?php
|
|
|
|
namespace App\Models\YiiModels;
|
|
|
|
use App\Models\ExpressNo;
|
|
use App\Models\Pay\Bill;
|
|
use App\Models\Pay\MultiBill;
|
|
use App\Models\Pay\RefundBill;
|
|
use App\Models\ProductOrderItem;
|
|
use Exception;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
|
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
|
use Illuminate\Database\Eloquent\Relations\Relation;
|
|
use Illuminate\Support\Facades\Artisan;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Yansongda\LaravelPay\Facades\Pay;
|
|
|
|
/**
|
|
* App\Models\YiiModels\ProductOrder
|
|
*
|
|
* @property int $id
|
|
* @property int $store_id 门店id
|
|
* @property int|null $drugstore_id 仓库id
|
|
* @property int $su_id
|
|
* @property int $user_id 用户id
|
|
* @property int $up_id 就诊人id
|
|
* @property string $order_no 订单号
|
|
* @property int|null $is_online 是否互医订单 1是
|
|
* @property int|null $online_prescription_status 互医处方状态 1已通过 2已作废
|
|
* @property string|null $sync_order_no
|
|
* @property int $p_id 处方id
|
|
* @property int $order_type 订单类型 1处方订单 2商城订单 2商城处方订单
|
|
* @property int $type 支付类型 1微信2支付宝3银行卡4其他
|
|
* @property int $is_pay 是否支付0否1是
|
|
* @property string $total_pay_price 支付总价
|
|
* @property string $items_price 商品总价
|
|
* @property int $pay_time
|
|
* @property int $address_id
|
|
* @property string|null $address
|
|
* @property int $cancel_status
|
|
* @property int $cancel_time
|
|
* @property string|null $cancel_remark 取消备注(未支付超时取消,主动取消,拒绝取消)
|
|
* @property int $refund_status
|
|
* @property int $refund_time
|
|
* @property int $received_time
|
|
* @property int $auto_cancel_time
|
|
* @property int $status 产品订单状态0未支付1待发货2待收货3待评价4已退款5退款中6已收货7确认收货
|
|
* @property int $pay_method 支付方式1线上2线下
|
|
* @property string $trans_expenses 运费(默认包邮)
|
|
* @property int $free_ship 是否包邮
|
|
* @property string|null $remark 留言备注
|
|
* @property string|null $express_name 收货人
|
|
* @property string|null $express_mobile 收货电话
|
|
* @property string|null $express_region 收货省市区
|
|
* @property string|null $express_address 收货地址
|
|
* @property int|null $express_no_id 快递单信息id
|
|
* @property \Illuminate\Support\Carbon $created_at
|
|
* @property \Illuminate\Support\Carbon $updated_at
|
|
* @property-read \App\Models\Pay\Bill|null $billed 已支付的支付单
|
|
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Pay\Bill[] $bills 支付单
|
|
* @property-read int|null $bills_count
|
|
* @property-read \App\Models\ExpressNo|null $expressNo 物流信息
|
|
* @property-read string $cancel_status_string 取消状态
|
|
* @property-read string $created_at_format 创建时间的格式化
|
|
* @property-read string $refund_status_string 退款状态
|
|
* @property-read string $status_string 状态名称
|
|
* @property-read string $type_string 支付类型
|
|
* @property-read string $updated_at_format 更新时间的格式化
|
|
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProductOrderItem[] $items 订单商品明细
|
|
* @property-read int|null $items_count
|
|
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\YiiModels\ProductOrderLog[] $logs 订单日志
|
|
* @property-read int|null $logs_count
|
|
* @property-read \App\Models\YiiModels\Prescription|null $prescription 处方
|
|
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\YiiModels\ProductOrderRefund[] $refunds 退款单
|
|
* @property-read int|null $refunds_count
|
|
* @property-read \App\Models\YiiModels\Store|null $store 门店
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\YiiModels\ProductOrder newModelQuery()
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\YiiModels\ProductOrder newQuery()
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\YiiModels\ProductOrder query()
|
|
* @mixin \Eloquent
|
|
*/
|
|
class ProductOrder extends YiiBaseModel
|
|
{
|
|
// 订单类型
|
|
public const ORDER_TYPE_PRESCRIPTION = 1;
|
|
public const ORDER_TYPE_SHOP = 2;
|
|
public const ORDER_TYPE_SHOP_PRESCRIPTION = 3;
|
|
public const ORDER_TYPE = [
|
|
self::ORDER_TYPE_PRESCRIPTION => '处方订单',
|
|
self::ORDER_TYPE_SHOP => '商城订单',
|
|
self::ORDER_TYPE_SHOP_PRESCRIPTION => '商城处方订单',
|
|
];
|
|
|
|
// 订单类型
|
|
public const TYPE_WECHAT = 1;
|
|
public const TYPE_ALIPAY = 2;
|
|
public const TYPE_BANK = 3;
|
|
public const TYPE_OTHER = 4;
|
|
public const TYPE = [
|
|
self::TYPE_WECHAT => '微信',
|
|
self::TYPE_ALIPAY => '支付宝',
|
|
self::TYPE_BANK => '银行卡',
|
|
self::TYPE_OTHER => '其他',
|
|
];
|
|
|
|
// 是否支付
|
|
public const IS_PAY_FALSE = 0;
|
|
public const IS_PAY_TRUE = 1;
|
|
public const IS_PAY = [
|
|
self::IS_PAY_FALSE => '否',
|
|
self::IS_PAY_TRUE => '是',
|
|
];
|
|
|
|
// 是否互医订单
|
|
public const IS_ONLINE_FALSE = 0;
|
|
public const IS_ONLINE_TRUE = 1;
|
|
public const IS_ONLINE = [
|
|
self::IS_ONLINE_FALSE => '否',
|
|
self::IS_ONLINE_TRUE => '是',
|
|
];
|
|
|
|
// 订单状态
|
|
const STATUS_UNPAID = 0;
|
|
const STATUS_WAIT_SEND = 1;
|
|
const STATUS_WAIT_ACCEPT = 2;
|
|
const STATUS_WAIT_COMMENT = 3;
|
|
const STATUS_REFUND = 4;
|
|
const STATUS_REFUNDING = 5;
|
|
const STATUS_ACCEPTED = 6;
|
|
const STATUS_CONFIRM = 7;
|
|
const STATUS_CANCEL = 9;
|
|
const STATUS = [
|
|
self::STATUS_UNPAID => '未支付',
|
|
self::STATUS_WAIT_SEND => '待发货',
|
|
self::STATUS_WAIT_ACCEPT => '待收货',
|
|
self::STATUS_WAIT_COMMENT => '待评价',
|
|
self::STATUS_REFUND => '已退款',
|
|
self::STATUS_REFUNDING => '退款中',
|
|
self::STATUS_ACCEPTED => '已收货',
|
|
self::STATUS_CONFIRM => '确认收货',
|
|
self::STATUS_CANCEL => '已取消',
|
|
];
|
|
|
|
// 取消状态
|
|
const CANCEL_STATUS_FALSE = 0;
|
|
const CANCEL_STATUS_TRUE = 1;
|
|
const CANCEL_STATUS = [
|
|
self::CANCEL_STATUS_FALSE => '未取消',
|
|
self::CANCEL_STATUS_TRUE => '已取消',
|
|
];
|
|
|
|
// 退款状态
|
|
const REFUND_STATUS_NORMAL = 0;
|
|
const REFUND_STATUS_APPLYING = 1;
|
|
const REFUND_STATUS_AGREE = 2;
|
|
const REFUND_STATUS_END = 3;
|
|
const REFUND_STATUS_PART = 4;
|
|
const REFUND_STATUS_CANCEL = 9;
|
|
const REFUND_STATUS = [
|
|
self::REFUND_STATUS_NORMAL => '正常',
|
|
self::REFUND_STATUS_APPLYING => '申请中',
|
|
self::REFUND_STATUS_AGREE => '同意申请',
|
|
self::REFUND_STATUS_END => '退款完成',
|
|
self::REFUND_STATUS_PART => '部分退款完成',
|
|
self::REFUND_STATUS_CANCEL => '取消退款申请',
|
|
];
|
|
|
|
// 支付方式
|
|
public const PAY_METHOD_ONLINE = 1;
|
|
public const PAY_METHOD_OFFLINE = 2;
|
|
public const PAY_METHOD = [
|
|
self::PAY_METHOD_ONLINE => '线上',
|
|
self::PAY_METHOD_OFFLINE => '线下',
|
|
];
|
|
|
|
// 支付方式
|
|
public const FREE_SHIP_FALSE = 0;
|
|
public const FREE_SHIP_TRUE = 1;
|
|
public const FREE_SHIP = [
|
|
self::FREE_SHIP_FALSE => '不包邮',
|
|
self::FREE_SHIP_TRUE => '包邮',
|
|
];
|
|
|
|
/**
|
|
* @comment 门店
|
|
* @return BelongsTo
|
|
*/
|
|
public function store(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Store::class, 'store_id');
|
|
}
|
|
|
|
/**
|
|
* @comment 订单商品明细
|
|
* @return HasMany
|
|
*/
|
|
public function items(): HasMany
|
|
{
|
|
return $this->hasMany(ProductOrderItem::class, 'product_order_id');
|
|
}
|
|
|
|
/**
|
|
* @comment 退款单
|
|
* @return HasMany
|
|
*/
|
|
public function refunds(): HasMany
|
|
{
|
|
return $this->hasMany(ProductOrderRefund::class, 'order_id');
|
|
}
|
|
|
|
/**
|
|
* @comment 订单日志
|
|
* @return HasMany
|
|
*/
|
|
public function logs(): HasMany
|
|
{
|
|
return $this->hasMany(ProductOrderLog::class, 'p_id');
|
|
}
|
|
|
|
/**
|
|
* @comment 支付单
|
|
* @return MorphMany
|
|
*/
|
|
public function bills(): MorphMany
|
|
{
|
|
return $this->morphMany(Bill::class, 'billable');
|
|
}
|
|
|
|
/**
|
|
* @comment 已支付的支付单
|
|
* @return MorphOne
|
|
*/
|
|
public function billed(): MorphOne
|
|
{
|
|
return $this->morphOne(Bill::class, 'billable')->where('bill_status', Bill::BILL_STATUS_SUCCESSFUL)->latest();
|
|
}
|
|
|
|
/**
|
|
* @comment 物流信息
|
|
* @return BelongsTo
|
|
*/
|
|
public function expressNo(): BelongsTo
|
|
{
|
|
return $this->belongsTo(ExpressNo::class, 'express_no_id');
|
|
}
|
|
|
|
/**
|
|
* @comment 处方
|
|
* @return BelongsTo
|
|
*/
|
|
public function prescription(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Prescription::class, 'p_id');
|
|
}
|
|
|
|
/**
|
|
* status_string
|
|
*
|
|
* @comment 状态名称
|
|
* @return string
|
|
*/
|
|
public function getStatusStringAttribute(): string
|
|
{
|
|
return self::STATUS[$this['status']] ?? '';
|
|
}
|
|
|
|
/**
|
|
* type_string
|
|
*
|
|
* @comment 支付类型
|
|
* @return string
|
|
*/
|
|
public function getTypeStringAttribute(): string
|
|
{
|
|
return self::TYPE[$this->type] ?? '';
|
|
}
|
|
|
|
/**
|
|
* cancel_status_string
|
|
*
|
|
* @comment 取消状态
|
|
* @return string
|
|
*/
|
|
public function getCancelStatusStringAttribute(): string
|
|
{
|
|
return self::CANCEL_STATUS[$this->cancel_status] ?? '';
|
|
}
|
|
|
|
/**
|
|
* refund_status_string
|
|
*
|
|
* @comment 退款状态
|
|
* @return string
|
|
*/
|
|
public function getRefundStatusStringAttribute(): string
|
|
{
|
|
return self::CANCEL_STATUS[$this->refund_status] ?? '';
|
|
}
|
|
|
|
/**
|
|
* 支付成功处理
|
|
*
|
|
* @param Bill $bill
|
|
* @return void
|
|
*/
|
|
public function handlePied(Bill $bill): void
|
|
{
|
|
$this->is_pay = self::IS_PAY_TRUE;
|
|
$this->pay_time = strtotime($bill->pay_at);
|
|
$this->status = self::STATUS_WAIT_SEND;
|
|
$this->save();
|
|
|
|
$this->logs()->create([
|
|
'content' => '订单支付成功 - ' . $this->type_string,
|
|
]);
|
|
|
|
$this->createFundWater($this);
|
|
|
|
$this->createNotice($this, '您的订单已支付成功');
|
|
|
|
$this->loadMissing(['items.drugStoreRelation' => fn(Relation $relation) => $relation->where('store_id', $this->store_id)]);
|
|
foreach ($this->items as $item) {
|
|
if ($item->drugStoreRelation) {
|
|
$item->drugStoreRelation->true_sales_volume += $item->number;
|
|
$item->drugStoreRelation->save();
|
|
}
|
|
}
|
|
|
|
// // 同步数据
|
|
// $this->refresh();
|
|
// $this->load(['items']);
|
|
// Artisan::call('data:sync', [
|
|
// '--type' => 'product_order_sync',
|
|
// '--data' => $this->toArray(),
|
|
// ]);
|
|
|
|
if ($this->is_online == self::IS_ONLINE_TRUE && $this->sync_order_no) {
|
|
// 同步数据(老)
|
|
Artisan::call('data:sync-old', [
|
|
'--type' => 'syncOrder',
|
|
'--data' => json_encode([
|
|
'order_no' => $this->sync_order_no,
|
|
'status' => 1, // 1已支付 2已取消 3已退款
|
|
'time' => $bill->pay_at,
|
|
]),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 退款操作
|
|
*
|
|
* @throws \Throwable
|
|
*/
|
|
public function toRefund(int|string|float $refundAmount, $refundNo = null): array
|
|
{
|
|
if ($this->is_pay == ProductOrder::IS_PAY_FALSE) {
|
|
$message = '订单未支付:' . "[productOrderId:$this->id]";
|
|
log_s($message, 'order', 'refund');
|
|
return json_result($message, [], 1);
|
|
}
|
|
if ($this->cancel_status == ProductOrder::CANCEL_STATUS_TRUE) {
|
|
$message = '订单已取消:' . "[productOrderId:$this->id]";
|
|
log_s($message, 'order', 'refund');
|
|
return json_result($message, [], 1);
|
|
}
|
|
if ($this->refund_status == ProductOrder::REFUND_STATUS_PART) {
|
|
$message = '订单已退款完成:' . "[productOrderId:$this->id]";
|
|
log_s($message, 'order', 'refund');
|
|
return json_result($message, [], 1);
|
|
}
|
|
if (in_array($this->status, [
|
|
ProductOrder::STATUS_UNPAID,
|
|
ProductOrder::STATUS_REFUND,
|
|
ProductOrder::STATUS_CANCEL,
|
|
])) {
|
|
$message = '退款失败,订单状态为:' . $this->status_string . "[productOrderId:$this->id]";
|
|
log_s($message, 'order', 'refund');
|
|
return json_result($message, [], 1);
|
|
}
|
|
$this->loadMissing('billed');
|
|
if (!$this->billed) {
|
|
$message = '退款失败,无已支付的支付单:' . "[productOrderId:$this->id]";
|
|
log_s($message, 'order', 'refund');
|
|
return json_result($message, [], 1);
|
|
}
|
|
if ($this->billed->can_refund_amount < $refundAmount) {
|
|
$message = '退款失败,申请金额超过可退金额不足:' . "[productOrderId:$this->id]";
|
|
log_s($message, 'order', 'refund');
|
|
return json_result($message, [], 1);
|
|
}
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
$data = [
|
|
'refund_amount' => $refundAmount,
|
|
];
|
|
if ($refundNo) {
|
|
$data['refund_no'] = $refundNo;
|
|
}
|
|
|
|
/* @var RefundBill $refundBill */
|
|
$refundBill = $this->billed->refunds()->create($data);
|
|
$refundNo = $refundBill->refund_no;
|
|
|
|
$order = [
|
|
'out_trade_no' => $this->billed->pay_no,
|
|
'out_refund_no' => $refundBill->refund_no,
|
|
'amount' => [
|
|
'refund' => $refundBill->refund_amount * 100,
|
|
'total' => $this->billed->pay_amount * 100,
|
|
'currency' => 'CNY',
|
|
],
|
|
];
|
|
$result = Pay::wechat()->refund($order);
|
|
if (isset($result['code'])) {
|
|
$message = '退款失败:' . ($result['message'] ?? '');
|
|
log_s($message, 'order', 'refund');
|
|
return json_result($message, [], 1);
|
|
}
|
|
|
|
$this->logs()->create([
|
|
'content' => "开始退款:{$this->billed->pay_way_string}[$refundBill->refund_amount]"
|
|
]);
|
|
|
|
DB::commit();
|
|
$message = '退款申请成功:' . var_export($result, true);
|
|
log_s($message, 'order', 'refund');
|
|
return json_result('退款申请成功', ['refund_no' => $refundNo]);
|
|
} catch (Exception $exception) {
|
|
DB::rollBack();
|
|
$message = '退款错误:' . "[productOrderId:$this->id]" . $exception->getMessage() . $exception->getTraceAsString();
|
|
log_s($message, 'order', 'error');
|
|
return json_result($message, [], 1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 退款成功处理
|
|
*
|
|
* @param RefundBill $refundBill
|
|
* @return void
|
|
*/
|
|
public function handleRefunded(RefundBill $refundBill): void
|
|
{
|
|
$this->status = self::STATUS_REFUND;
|
|
$this->refund_status = ProductOrder::REFUND_STATUS_END;
|
|
$this->save();
|
|
|
|
$refund = ProductOrderRefund::where('refund_no', $refundBill->refund_no)->first();
|
|
$refund->update([
|
|
'is_refund' => ProductOrderRefund::IS_REFUND_TRUE,
|
|
'refund_time' => $refundBill->refund_at,
|
|
'status' => ProductOrderRefund::STATUS_PASS,
|
|
]);
|
|
|
|
$this->logs()->create([
|
|
'content' => '订单退款成功 - ' . $this->type_string,
|
|
]);
|
|
|
|
$this->createNotice($this, '您的订单已退款成功');
|
|
|
|
$this->loadMissing(['items.drugstoreDrug' => fn(Relation $relation) => $relation->where('drugstore_id', $this->drugstore_id)]);
|
|
foreach ($this->items as $item) {
|
|
if ($item->drugstoreDrug) {
|
|
$item->drugstoreDrug->stock += $item->number;
|
|
$item->drugstoreDrug->frozen_number -= $item->number;
|
|
$item->drugstoreDrug->save();
|
|
}
|
|
}
|
|
|
|
// // 同步数据
|
|
// $this->refresh();
|
|
// $this->load(['items']);
|
|
// Artisan::call('data:sync', [
|
|
// '--type' => 'product_order_sync',
|
|
// '--data' => $this->toArray(),
|
|
// ]);
|
|
|
|
if ($this->is_online == self::IS_ONLINE_TRUE && $this->sync_order_no) {
|
|
// 同步数据(老)
|
|
Artisan::call('data:sync-old', [
|
|
'--type' => 'syncOrder',
|
|
'--data' => json_encode([
|
|
'order_no' => $this->sync_order_no,
|
|
'status' => 3, // 1已支付 2已取消 3已退款
|
|
'time' => $refundBill->refund_at,
|
|
]),
|
|
]);
|
|
}
|
|
}
|
|
}
|