香洲二院小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mini_xzey/app/Models/Order.php

417 lines
13 KiB

<?php
declare(strict_types=1);
namespace App\Models;
use App\Dictionary\Order\NotifyStatus;
use App\Dictionary\Order\PayMode;
use App\Dictionary\Order\PayType;
use App\Dictionary\Order\SourceId;
use App\Dictionary\Order\Status;
use App\Dictionary\Order\Type;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
/**
* @method where(string $string, string $id)
* @method create(array $order_info)
*/
class Order extends Model
{
use HasFactory;
protected $table = 'orders';
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $fillable = [
'relate_id',
'order_id',
'his_order_id',
'transaction_id',
'status',
'notify_status',
'type',
'pay_type',
'pay_mode',
'fee',
'self_fee',
'reduce_fee',
'refund_fee',
'open_id',
'patient_id',
'patient_name',
'source_id',
'payment_at',
'refunded_at',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'id' => 'integer',
'relate_id' => 'integer',
'status' => 'integer',
'type' => 'integer',
'pay_type' => 'integer',
'pay_mode' => 'integer',
'fee' => 'integer',
'self_fee' => 'integer',
'reduce_fee' => 'integer',
'refund_fee' => 'integer',
'source_id' => 'integer',
'payment_at' => 'datetime',
'refunded_at' => 'datetime',
];
/**
* Relationships Patient.
*/
public function patient(): belongsTo
{
return $this->belongsTo(Patient::class, 'patient_id', 'patient_id');
}
/**
* Relationships Self Order.
*/
public function order(): HasMany
{
return $this->hasMany(__CLASS__, 'relate_id');
}
/**
* Relationships RegistrationRecord Model.
* @return HasOne
*/
public function registrationRecord(): HasOne
{
return $this->hasOne(RegistrationRecord::class, 'relate_order_id');
}
/**
* Relationships OutpatientPaymentRecord Model.
* @return HasOne
*/
public function outpatientPaymentRecord(): HasOne
{
return $this->hasOne(OutpatientPaymentRecord::class, 'relate_order_id');
}
/**
* 获取订单ID
* @param PayType $pay_type 支付类型
* @param string $user W 微信 D 大机器 X 小机器 H his
* @return string
*/
public function getOrderId(PayType $pay_type, string $user = 'D'): string
{
$order_id = $pay_type->order(). $user. date('YmdHis'). mt_rand(100, 999);
if ($this->where('order_id', $order_id)->first()) {
return $this->getOrderId($pay_type, $user);
}
return $order_id;
}
/**
* 获取退款订单ID
* @param string $order_id 原订单ID
* @param string $source_flag 退款来源标志 _ 程序自动冲正 R 人工退费 H His退款
* @return string
*/
public function getRefundOrderId(string $order_id, string $source_flag = '_'): string
{
$refund_order_id = $order_id. $source_flag. mt_rand(100, 999);
if ($this->where('order_id', $refund_order_id)->first()) {
return $this->getRefundOrderId($order_id);
}
return $refund_order_id;
}
/**
* 获取订单详情by id
* @param string $id
* @return mixed
*/
public function getOrderInfoById(string $id): mixed
{
return $this->where('id', $id)->with('patient')->first();
}
/**
* 获取订单详情by order_id
* @param string $order_id
* @return mixed
*/
public function getOrderInfoByOrderId(string $order_id): mixed
{
return $this->where('order_id', $order_id)->with('patient')->first();
}
/**
* 创建订单
* @param string $order_id
* @param PayType $pay_type
* @param float $fee
* @param string $open_id
* @param string $patient_id
* @param string $patient_name
* @param Type $order_type
* @param SourceId $source_id
* @param array $reg_info
* @param array $outpatient_info
* @return mixed
*/
public function createOrder(string $order_id, PayType $pay_type, float $fee, string $open_id, string $patient_id, string $patient_name, Type $order_type, SourceId $source_id, array $reg_info = [], array $outpatient_info = []): mixed
{
$order_info = [
'relate_id' => 0,
'order_id' => $order_id,
'his_order_id' => '',
'transaction_id' => '',
'status' => Status::NORMAL->value,
'notify_status' => NotifyStatus::NO_ACCEPTED->value,
'type' => $order_type->value,
'pay_type' => $pay_type,
'pay_mode' => PayMode::PAYMENT->value,
'fee' => $fee, //分
'self_fee' => $fee, //分
'refund_fee' => 0,
'open_id' => $open_id,
'patient_id' => $patient_id,
'patient_name' => $patient_name,
'source_id' => $source_id,
];
// 操作订单记录进行创建操作
if (in_array($order_type->value, [
Type::TODAY_REGISTRATION->value,
Type::APPOINTMENT_REGISTRATION->value,
Type::OUTPATIENT_PAYMENT->value
])) {
$result = $this->create($order_info);
if (!empty($result)) {
switch ($order_type->value) {
case Type::TODAY_REGISTRATION->value:
case Type::APPOINTMENT_REGISTRATION->value:
$result->registrationRecord()->create($reg_info);
break;
case Type::OUTPATIENT_PAYMENT->value:
$result->outpatientPaymentRecord()->create($outpatient_info);
break;
default:
break;
}
}
return $result;
}
return $this->create($order_info);
}
/**
* 创建退费/冲正订单
* @param int $relate_order_id
* @param string $order_id
* @param PayType $pay_type
* @param float $fee
* @param string $open_id
* @param string $patient_id
* @param string $patient_name
* @param Type $order_type
* @param SourceId $source_id
* @return mixed
*/
public function createRefundOReverseOrder(int $relate_order_id, string $order_id, PayType $pay_type, float $fee, string $open_id, string $patient_id, string $patient_name, Type $order_type, SourceId $source_id): mixed
{
$order_info = [
'relate_id' => $relate_order_id,
'order_id' => $order_id,
'his_order_id' => '',
'transaction_id' => '',
'status' => Status::NORMAL->value,
'notify_status' => NotifyStatus::NO_ACCEPTED->value,
'type' => $order_type,
'pay_type' => $pay_type,
'pay_mode' => PayMode::REFUND->value,
'fee' => $fee, //分
'self_fee' => 0, //分
'refund_fee' => 0,
'open_id' => $open_id,
'patient_id' => $patient_id,
'patient_name' => $patient_name,
'source_id' => $source_id,
];
return $this->create($order_info);
}
/**
* 订单确认
* @param string $order_id
* @param string $his_order_id
* @param array $response
*/
public function orderConfirm(string $order_id, string $his_order_id = '', array $response = []): void
{
$order = $this->where('order_id', $order_id)->first();
!empty($his_order_id) && $order->his_order_id = $his_order_id;
$order->status = Status::SUCCESS->value;
$order->save();
if (in_array($order->type, [Type::TODAY_REGISTRATION->value, Type::APPOINTMENT_REGISTRATION->value, Type::OUTPATIENT_PAYMENT->value]) && !empty($response)) {
switch ($order->type) {
case Type::TODAY_REGISTRATION->value:
case Type::APPOINTMENT_REGISTRATION->value:
$record = $order->registrationRecord;
$extra_info = json_decode($record->extra_info, true);
$extra_info['confirm_response'] = $response;
$record->update(['reg_id' => $response['AdmNo'] ?? '', 'extra_info' => json_encode($extra_info, JSON_UNESCAPED_UNICODE)]);
break;
case Type::OUTPATIENT_PAYMENT->value:
$record = $order->outpatientPaymentREcord;
$extra_info = json_decode($record->extra_info, true);
$extra_info['confirm_response'] = $response;
$record->update(['extra_info' => json_encode($extra_info, JSON_UNESCAPED_UNICODE)]);
break;
default:
break;
}
}
}
/**
* 修改订单状态
* @param string $order_id
* @param Status $status
*/
public function changeOrderStatus(string $order_id, Status $status): void
{
$order = $this->where('order_id', $order_id)->first();
$order->status = $status;
$order->save();
}
/**
* 订单异常(用户交钱成功,his业务确认异常
* @param string $order_id
*/
public function abnormalOrderOpera(string $order_id): void
{
$order = $this->where('order_id', $order_id)->first();
$order->status = Status::ABNORMAL->value;
$order->save();
}
/**
* 订单冲正(用户交钱成功,his业务确认失败)
* @param string $order_id
* @param float $refund_fee 此处是元
* @param bool $is_success 退款是否成功
*/
public function reverseOrderOpera(string $order_id, float $refund_fee, bool $is_success): void
{
$r_order = $this->where('order_id', $order_id)->first();
//原订单
if ($is_success) {
$order = $this->where('id', $r_order->relate_id)->first();
$order->refund_fee += $refund_fee * 100;
$order->status = Status::REVERSE->value;
$order->save();
}
// 保存退费/冲正订单
$r_order->status = $is_success ? Status::SUCCESS->value : Status::FAILURE->value;
$r_order->refunded_at = date('Y-m-d H:i:s');
$r_order->save();
}
/**
* 挂号订单解锁
* @param string $order_id
* @return void
*/
public function regOrderUnlock(string $order_id): void
{
$order = $this->where('order_id', $order_id)->with('registrationRecord')->first();
$order->registrationRecord->lock_status = 2;
$order->registrationRecord->unlock_at = date('Y-m-d H:i:s');
$order->registrationRecord->save();
$order->status = Status::FAILURE->value;
$order->save();
}
/**
* 订单取消预结算
* @param string $order_id
* @return void
*/
public function outpatientOderCancelPreSettle(string $order_id): void
{
$order = $this->where('order_id', $order_id)->with('outpatientPaymentRecord')->first();
$order->outpatientPaymentRecord->pre_settle_status = 2;
$order->outpatientPaymentRecord->cancel_pre_settle_at = date('Y-m-d H:i:s');
$order->outpatientPaymentRecord->save();
$order->status = Status::FAILURE->value;
$order->save();
}
/**
* 操作订单冲正
* @param string $order_id
* @param int $order_type
* @param string $patient_id
* @param string $patient_name
* @param PayType $pay_type
* @param float $fee
* @param array $pay_params
* @param array $pay_res_data
* @return string
*/
public function handleOrderReverse(string $order_id, int $order_type, string $patient_id, string $patient_name, PayType $pay_type, float $fee, array $pay_params, array $pay_res_data)
{
$relate_order_info = $this->getOrderInfoByOrderId($order_id);
// 创建冲正订单
$r_order_id = $this->getRefundOrderId($order_id);
$this->createRefundOReverseOrder($relate_order_info['id'], $r_order_id, $pay_type, $fee * 100, $patient_id, $patient_name, $order_type);
// 退款
$refund_res = fastOrderRefund($pay_type, $order_id, $r_order_id, $fee, $pay_params, $pay_res_data);
$this->addLog('order reverse', '订单冲正', $refund_res);
// 冲正失败
if (!$refund_res[0]) {
$this->reverseOrderOpera($r_order_id, $fee, false);
return '冲正失败,失败原因:'. $refund_res[1]. ',请前往人工窗口进行退款!';
}
$this->reverseOrderOpera($r_order_id, $fee, true);
return '冲正成功,请稍后再行尝试!';
}
}