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.
340 lines
11 KiB
340 lines
11 KiB
<?php
|
|
|
|
declare(strict_types = 1);
|
|
|
|
namespace App\Http\Logics\Notify;
|
|
|
|
use App\Dictionary\Order\NotifyStatus;
|
|
use App\Dictionary\Order\PayType;
|
|
use App\Dictionary\Order\SourceId;
|
|
use App\Dictionary\Order\Status;
|
|
use App\Dictionary\Order\Type;
|
|
use App\Exceptions\GeneralException;
|
|
use App\Models\Order as OrderModel;
|
|
use App\Models\Patient as PatientModel;
|
|
use App\Services\HisHttp\Client;
|
|
use App\Utils\Traits\Logger;
|
|
use App\Utils\Traits\RedisLockUtil;
|
|
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
|
|
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
|
|
use EasyWeChat\Pay\Application as PaymentApplication;
|
|
use EasyWeChat\Pay\Message;
|
|
use RedisException;
|
|
use Exception;
|
|
use ReflectionException;
|
|
use UnifyPayment\Cores\Struct\ConfirmOrderForEx;
|
|
use UnifyPayment\Cores\Struct\RefundOrder;
|
|
use UnifyPayment\Mock\ConfirmOrderForExHandler;
|
|
use UnifyPayment\Mock\RefundOrderHandler;
|
|
use UnifyPayment\Unify;
|
|
|
|
class NotifyLogic
|
|
{
|
|
use Logger;
|
|
use RedisLockUtil;
|
|
|
|
protected Client $his_client;
|
|
|
|
protected PaymentApplication $payment_app;
|
|
|
|
protected PatientModel $patient_model;
|
|
|
|
protected OrderModel $order_model;
|
|
|
|
/**
|
|
* NotifyLogic constructor.
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$this->setChannel('notify');
|
|
$this->his_client = app('HisHttpService');
|
|
$this->patient_model = new PatientModel();
|
|
$this->order_model = new OrderModel();
|
|
$this->payment_app = getWeChatMiniProgramPaymentApp();
|
|
}
|
|
|
|
/**
|
|
* 回调消息确费操作
|
|
* @param Message $notify
|
|
* @return bool
|
|
* @throws InvalidConfigException|RedisException
|
|
*/
|
|
public function notifyHandle(Message $notify): bool
|
|
{
|
|
$lock_id = $this->addLockOrder($notify->out_trade_no);
|
|
if (!$lock_id) {
|
|
return false;
|
|
}
|
|
|
|
// 查找订单信息
|
|
$order_info = $this->order_model->getOrderInfoByOrderId($notify['out_trade_no']);
|
|
|
|
// 如果订单不存在 / 订单状态不为初始状态 / 订单已经处理过了
|
|
if (
|
|
empty($order_info) ||
|
|
$order_info->status != Status::NORMAL->value ||
|
|
$order_info->notify_status == NotifyStatus::ACCEPTED->value
|
|
) {
|
|
$this->unlockOrder($notify['out_trade_no'], $lock_id);
|
|
return true;
|
|
}
|
|
|
|
// 设置状态为1
|
|
$order_info->notify_status = NotifyStatus::ACCEPTED->value;
|
|
$order_info->transaction_id = $notify->transaction_id;
|
|
$order_info->payment_at = date('Y-m-d H:i:s', strtotime($notify->time_end));
|
|
$order_info->save();
|
|
|
|
try {
|
|
switch ($order_info->type) {
|
|
case Type::TODAY_REGISTRATION->value:
|
|
case Type::APPOINTMENT_REGISTRATION->value:
|
|
$this->registrationOrderHandle($order_info, $notify);
|
|
break;
|
|
case Type::OUTPATIENT_PAYMENT->value:
|
|
$this->outpatientOrderHandle($order_info, $notify);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} catch (GeneralException|Exception $e) {
|
|
$err_msg = $e->getMessage().' ON '. $e->getFile(). ':'. $e->getLine();
|
|
recordLog('NotifyLog', $err_msg);
|
|
$this->unlockOrder($notify->out_trade_no, $lock_id);
|
|
return false;
|
|
}
|
|
|
|
$this->unlockOrder($notify->out_trade_no, $lock_id);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 挂号订单操作
|
|
* @param OrderModel $order_info
|
|
* @param Message $notify
|
|
* @throws GeneralException
|
|
*/
|
|
protected function registrationOrderHandle(OrderModel $order_info, Message $notify): void
|
|
{
|
|
// 挂号确认
|
|
$patient = $order_info->patient;
|
|
$record = $order_info->registrationRecord;
|
|
$extra = json_decode($record->extra_info, true);
|
|
$pay_time = strtotime($notify->time_end);
|
|
|
|
$data = [
|
|
$order_info->patient_id,
|
|
$order_info->patient_name,
|
|
$record->dept_id,
|
|
$record->docttor_id,
|
|
$record->reg_id,
|
|
$extra['SHIFT']['RANKID'],
|
|
$record->date,
|
|
PayType::WECHAT_PAY->hisCode(),
|
|
$order_info->order_id,
|
|
'',
|
|
'',
|
|
'',
|
|
'',
|
|
(string) ($notify->total_fee / 100),
|
|
''
|
|
];
|
|
$response = $this->his_client->registerConfirm(... $data);
|
|
$this->info('挂号订单出入参:'.$order_info->order_id, [$data, $response]);
|
|
|
|
if (isset($response['RESULTCODE']) && $response['RESULTCODE'] === '0') {
|
|
// 成功流程
|
|
$order_info->orderConfirm($order_info->order_id, $response['VISITNO'], $response);
|
|
|
|
// 支付平台业务确认
|
|
$this->unifyConfirm($notify['out_trade_no'], $response['VISITNO'], $notify['openid'], $notify['transaction_id']);
|
|
|
|
// 推送成功
|
|
} else if (isset($response['RESULTCODE'])) {
|
|
// 失败流程
|
|
$this->handleOrderReverse($order_info, $response['ERRORMSG'] ?? '');
|
|
|
|
// 推送失败
|
|
} else {
|
|
// 异常流程
|
|
$order_info->abnormalOrderOpera($order_info->id);
|
|
|
|
// 推送异常
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 门诊缴费订单操作
|
|
* @param OrderModel $order_info
|
|
* @param Message $notify
|
|
* @throws GeneralException
|
|
*/
|
|
protected function outpatientOrderHandle(OrderModel $order_info, Message $notify): void
|
|
{
|
|
// 挂号确认
|
|
$patient = $order_info->patient;
|
|
$record = $order_info->outpatientPaymentRecord;
|
|
$extra = json_decode($record->extra_info, true);
|
|
$pay_time = strtotime($notify->time_end);
|
|
|
|
$data = [
|
|
$order_info->patient_id,
|
|
'0',
|
|
date('Y-m-d', $extra['JSRQ']),
|
|
$extra['prescription_ids'],
|
|
$extra['TREAID'],
|
|
'',
|
|
$order_info->order_id,
|
|
PayType::WECHAT_PAY->hisCode(),
|
|
(string) ($order_info['total_fee'] / 100),
|
|
(string) ($order_info['self_fee'] / 100)
|
|
];
|
|
$response = $this->his_client->confirmOutpatient(... $data);
|
|
$this->info('缴费订单出入参:'.$order_info->order_id, [$data, $response]);
|
|
|
|
// 保存返回信息
|
|
if (isset($response['ResultCode']) && $response['ResultCode'] === '0') {
|
|
// 成功流程
|
|
$order_info->orderConfirm($order_info->order_id, $response['HOSTRANNO'], $response);
|
|
|
|
// 支付平台业务确认
|
|
$this->unifyConfirm($notify['out_trade_no'], $response['HOSTRANNO'], $notify['openid'], $notify['transaction_id']);
|
|
|
|
// 推送成功
|
|
|
|
} else if (isset($response['ResultCode'])) {
|
|
// 失败流程
|
|
$this->handleOrderReverse($order_info, $response['ERRORMSG']);
|
|
|
|
// 推送失败
|
|
|
|
} else {
|
|
// 异常流程
|
|
$order_info->abnormalOrderOpera($order_info->id);
|
|
|
|
// 推送异常
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 退款
|
|
* @param string $order_id
|
|
* @param string $refund_order_id
|
|
* @param int $refund_fee
|
|
* @param string $refund_reason
|
|
* @return bool
|
|
*/
|
|
protected function refundPaidOrder(string $order_id, string $refund_order_id, int $refund_fee, string $refund_reason): bool
|
|
{
|
|
try {
|
|
$refund = new RefundOrder($order_id, $refund_order_id, (string)($refund_fee / 100), '确认挂号失败,自动冲正,错误消息:'. $refund_reason);
|
|
$response = Unify::common(config('unify'))->order->setMockHandler([new RefundOrderHandler(true)])->refund($refund);
|
|
$this->info('退号退费结果', $response);
|
|
|
|
if ($response['status'] === 200 || $response['success'] === true) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
} catch (ReflectionException|Exception $e) {
|
|
$err_msg = "订单号:{$order_id}, 退款异常,错误消息:{$e->getMessage()} ON {$e->getFile()}:{$e->getLine()}";
|
|
$this->error($err_msg);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 订单冲正
|
|
* @param OrderModel $order_info
|
|
* @param string $err_msg
|
|
* @return void
|
|
*/
|
|
protected function handleOrderReverse(OrderModel $order_info, string $err_msg): void
|
|
{
|
|
$refund_order_id = $order_info->getRefundOrderId($order_info->order_id);
|
|
$order_info->createRefundOReverseOrder(
|
|
$order_info->id,
|
|
$refund_order_id,
|
|
PayType::from($order_info->pay_type),
|
|
$order_info->fee,
|
|
$order_info->open_id,
|
|
$order_info->patient_id,
|
|
$order_info->patient_name,
|
|
Type::from($order_info->type),
|
|
SourceId::OFFICIAL_ACCOUNT
|
|
);
|
|
|
|
$refund_res = $this->refundPaidOrder($order_info->order_id, $refund_order_id, $order_info->fee, $err_msg);
|
|
|
|
// 冲正失败
|
|
if (!$refund_res) {
|
|
$this->info('订单号'. $order_info->order_id. '冲正失败');
|
|
$order_info->reverseOrderOpera($refund_order_id, $order_info->fee, false);
|
|
return;
|
|
}
|
|
|
|
$this->info('订单号'. $order_info->order_id. '冲正成功');
|
|
$order_info->reverseOrderOpera($refund_order_id, $order_info->fee, true);
|
|
}
|
|
|
|
/**
|
|
* 订单加锁
|
|
* @param string $order_id
|
|
* @return false|string
|
|
* @throws RedisException
|
|
*/
|
|
protected function addLockOrder(string $order_id): false|string
|
|
{
|
|
$result = $this->addLock($order_id);
|
|
$this->info('订单加锁', [$order_id, $result]);
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* 订单解锁
|
|
* @param string $order_id
|
|
* @param string $lock_id
|
|
* @return bool
|
|
* @throws RedisException
|
|
*/
|
|
protected function unlockOrder(string $order_id, string $lock_id): bool
|
|
{
|
|
// 解锁
|
|
$result = $this->unlock($order_id, $lock_id);
|
|
$this->info('订单解锁', [$order_id, $lock_id, $result]);
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* 支付平台业务确认
|
|
* @param string $order_id
|
|
* @param string $his_serial_no
|
|
* @param string $pay_account
|
|
* @param string $tran_no
|
|
* @return bool
|
|
*/
|
|
protected function unifyConfirm(string $order_id, string $his_serial_no, string $pay_account, string $tran_no): bool
|
|
{
|
|
try {
|
|
$confirm_order = new ConfirmOrderForEx($order_id, $his_serial_no, $pay_account, $tran_no);
|
|
$response = Unify::common(config('unify'))->order->setMockHandler([new ConfirmOrderForExHandler(true)])->confirmForEx($confirm_order);
|
|
$this->info('支付平台确认结果', $response);
|
|
|
|
if ($response['status'] === 200 || $response['success'] === true) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
} catch (ReflectionException|Exception $e) {
|
|
$err_msg = "订单号:{$order_id}, 支付平台确认结果异常,错误消息:{$e->getMessage()} ON {$e->getFile()}:{$e->getLine()}";
|
|
$this->error($err_msg);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|