香洲二院小程序
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/Http/Logics/Notify/NotifyLogic.php

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