parent
4ce8774ffd
commit
90a80a5767
@ -0,0 +1,94 @@ |
|||||||
|
<?php |
||||||
|
declare(strict_types = 1); |
||||||
|
|
||||||
|
namespace App\Http\Controllers\Notify; |
||||||
|
|
||||||
|
use App\Dictionary\WeChat\Payment\V2Api; |
||||||
|
use App\Http\Controllers\Controller; |
||||||
|
use App\Http\Logics\Notify\NotifyLogic; |
||||||
|
use App\Utils\Traits\Logger; |
||||||
|
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; |
||||||
|
use EasyWeChat\Kernel\Exceptions\RuntimeException; |
||||||
|
use EasyWeChat\Pay\Message; |
||||||
|
use Psr\Http\Message\ResponseInterface; |
||||||
|
use ReflectionException; |
||||||
|
use Throwable; |
||||||
|
|
||||||
|
class NotifyController extends Controller |
||||||
|
{ |
||||||
|
|
||||||
|
use Logger; |
||||||
|
|
||||||
|
protected NotifyLogic $notify_logic; |
||||||
|
|
||||||
|
/** |
||||||
|
* NotifyController Construct |
||||||
|
*/ |
||||||
|
public function __construct() |
||||||
|
{ |
||||||
|
$this->notify_logic = new NotifyLogic(); |
||||||
|
$this->setChannel('notify'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return ResponseInterface |
||||||
|
* @throws InvalidArgumentException |
||||||
|
* @throws RuntimeException |
||||||
|
* @throws ReflectionException |
||||||
|
* @throws Throwable |
||||||
|
*/ |
||||||
|
public function notify(): ResponseInterface |
||||||
|
{ |
||||||
|
$app = getWeChatMiniProgramPaymentApp(); |
||||||
|
$server = $app->getServer(); |
||||||
|
|
||||||
|
$server->handlePaid(function (Message $message, \Closure $next) use ($app) { |
||||||
|
// $message->out_trade_no 获取商户订单号 |
||||||
|
// $message->payer['openid'] 获取支付者 openid |
||||||
|
// 🚨🚨🚨 注意:推送信息不一定靠谱哈,请务必验证 |
||||||
|
// 建议是拿订单号调用微信支付查询接口, |
||||||
|
$this->info('接收回调消息', $message->toArray()); |
||||||
|
try{ |
||||||
|
// 验证通过,业务处理 |
||||||
|
$app->getValidator()->validate($app->getRequest()); |
||||||
|
|
||||||
|
// 查询订单 |
||||||
|
$response = $app->getClient()->postXml(V2Api::QUERY_ORDER->value, [ |
||||||
|
'body' => [ |
||||||
|
'appid' => config('wechat.payment.app_id'), |
||||||
|
'mch_id' => config('wechat.payment.mch_id'), |
||||||
|
'out_trade_no' => $message->out_trade_no |
||||||
|
] |
||||||
|
]); |
||||||
|
if ($response->isFailed()) { |
||||||
|
// 查询失败 |
||||||
|
$this->warning('订单查询失败', [$message->out_trade_no]); |
||||||
|
return $next($message); |
||||||
|
} |
||||||
|
|
||||||
|
// 不成功 |
||||||
|
if ( |
||||||
|
!isset($response['return_code'], $response['result_code']) || |
||||||
|
$response["return_code"] !== "SUCCESS" || |
||||||
|
$response["result_code"] !== "SUCCESS" |
||||||
|
) { |
||||||
|
$this->warning('订单查询支付失败', [$message->out_trade_no, $response]); |
||||||
|
return $next($message); |
||||||
|
} |
||||||
|
|
||||||
|
// 业务处理 |
||||||
|
$result = $this->notify_logic->notifyHandle($message); |
||||||
|
|
||||||
|
$this->info('接受回调消息结果', ['result' => $result]); |
||||||
|
} catch(\Exception $e){ |
||||||
|
// 验证失败 |
||||||
|
$err_msg = '订单验证签名失败:'. $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine(); |
||||||
|
$this->error($err_msg, [$message->toArray()]); |
||||||
|
} |
||||||
|
|
||||||
|
return $next($message); |
||||||
|
}); |
||||||
|
|
||||||
|
return $server->serve(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
<?php |
||||||
|
declare(strict_types = 1); |
||||||
|
|
||||||
|
namespace App\Http\Controllers\Outpatient; |
||||||
|
|
||||||
|
use App\Exceptions\GeneralException; |
||||||
|
use App\Http\Logics\Outpatient\PaymentLogic; |
||||||
|
use App\Http\Resources\Outpatient\Pending\PendingListsResource; |
||||||
|
use Illuminate\Http\JsonResponse; |
||||||
|
use Illuminate\Http\Request; |
||||||
|
use Symfony\Component\HttpFoundation\Response; |
||||||
|
|
||||||
|
class PaymentController |
||||||
|
{ |
||||||
|
protected PaymentLogic $payment_logic; |
||||||
|
|
||||||
|
/** |
||||||
|
* PaymentController Construct. |
||||||
|
*/ |
||||||
|
public function __construct() |
||||||
|
{ |
||||||
|
$this->payment_logic = new PaymentLogic(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 缴费 |
||||||
|
* @param Request $request |
||||||
|
* @param string $patient_id |
||||||
|
* @param string $serial_no |
||||||
|
* @return JsonResponse |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
public function payment(Request $request, string $patient_id, string $serial_no): JsonResponse |
||||||
|
{ |
||||||
|
$validated = $request->validate([ |
||||||
|
'prescription_ids' => 'required', |
||||||
|
'reg_id' => 'required', |
||||||
|
], [ |
||||||
|
'prescription_ids.required' => '请选择要缴纳的处方', |
||||||
|
'reg_id.required' => '请选择要缴纳的处方', |
||||||
|
]); |
||||||
|
|
||||||
|
$response = $this->payment_logic->payment($patient_id, $serial_no, $validated['prescription_ids'], $validated['reg_id']); |
||||||
|
|
||||||
|
return jsonResponse(Response::HTTP_OK, 'success', PendingListsResource::make($response)->toArray()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
<?php |
||||||
|
declare(strict_types = 1); |
||||||
|
|
||||||
|
namespace App\Http\Controllers\Outpatient; |
||||||
|
|
||||||
|
use App\Exceptions\GeneralException; |
||||||
|
use App\Http\Logics\Outpatient\PendingLogic; |
||||||
|
use App\Http\Resources\Outpatient\Pending\PendingDetailsResource; |
||||||
|
use App\Http\Resources\Outpatient\Pending\PendingListsResource; |
||||||
|
use App\Http\Resources\Outpatient\Record\RecordDetailsResource; |
||||||
|
use App\Http\Resources\Outpatient\Record\RecordListsResource; |
||||||
|
use Illuminate\Http\JsonResponse; |
||||||
|
use Illuminate\Http\Request; |
||||||
|
use Symfony\Component\HttpFoundation\Response; |
||||||
|
|
||||||
|
class PendingController |
||||||
|
{ |
||||||
|
protected PendingLogic $pending_logic; |
||||||
|
|
||||||
|
/** |
||||||
|
* PendingController Construct. |
||||||
|
*/ |
||||||
|
public function __construct() |
||||||
|
{ |
||||||
|
$this->pending_logic = new PendingLogic(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取缴费记录列表 |
||||||
|
* @param Request $request |
||||||
|
* @param string $patient_id |
||||||
|
* @return JsonResponse |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
public function lists(Request $request, string $patient_id): JsonResponse |
||||||
|
{ |
||||||
|
$response = $this->pending_logic->getLists($patient_id); |
||||||
|
|
||||||
|
return jsonResponse(Response::HTTP_OK, 'success', PendingListsResource::make($response)->toArray()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取待缴费详情 |
||||||
|
* @param Request $request |
||||||
|
* @param string $patient_id |
||||||
|
* @param string $serial_no |
||||||
|
* @return JsonResponse |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
public function details(Request $request, string $patient_id, string $serial_no): JsonResponse |
||||||
|
{ |
||||||
|
$validated = $request->validate([ |
||||||
|
'prescription_ids' => 'required', |
||||||
|
'reg_id' => 'required', |
||||||
|
], [ |
||||||
|
'prescription_ids.required' => '请选择要缴纳的处方', |
||||||
|
'reg_id.required' => '请选择要缴纳的处方', |
||||||
|
]); |
||||||
|
|
||||||
|
$response = $this->pending_logic->getDetails($patient_id, $serial_no, $validated['prescription_ids'], $validated['reg_id']); |
||||||
|
|
||||||
|
return jsonResponse(Response::HTTP_OK, 'success.', PendingDetailsResource::make($response)->toArray()); |
||||||
|
} |
||||||
|
} |
@ -1 +1,41 @@ |
|||||||
<?php |
<?php |
||||||
|
declare(strict_types = 1); |
||||||
|
|
||||||
|
namespace App\Http\Controllers\Registration; |
||||||
|
|
||||||
|
use App\Exceptions\GeneralException; |
||||||
|
use App\Http\Logics\Registration\RegisterLogic; |
||||||
|
use App\Http\Requests\Registration\RegisterRequest; |
||||||
|
use App\Http\Resources\Registration\Record\RecordListsResource; |
||||||
|
use Illuminate\Http\JsonResponse; |
||||||
|
use Illuminate\Http\Request; |
||||||
|
use Symfony\Component\HttpFoundation\Response; |
||||||
|
|
||||||
|
class RegisterController |
||||||
|
{ |
||||||
|
protected RegisterLogic $register_logic; |
||||||
|
|
||||||
|
/** |
||||||
|
* Patient Construct. |
||||||
|
*/ |
||||||
|
public function __construct() |
||||||
|
{ |
||||||
|
$this->register_logic = new RegisterLogic(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取挂号记录列表 |
||||||
|
* @param RegisterRequest $request |
||||||
|
* @param string $patient_id |
||||||
|
* @return JsonResponse |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
public function register(RegisterRequest $request, string $patient_id): JsonResponse |
||||||
|
{ |
||||||
|
$validated = $request->safe()->only(['date', 'dept_id', 'doctor_id', 'reg_id']); |
||||||
|
|
||||||
|
$response = $this->register_logic->register($patient_id, $validated['date'], $validated['dept_id'], $validated['doctor_id'], $validated['reg_id']); |
||||||
|
|
||||||
|
return jsonResponse(Response::HTTP_OK, 'success', RecordListsResource::make($response)->toArray()); |
||||||
|
} |
||||||
|
} |
||||||
|
@ -0,0 +1,338 @@ |
|||||||
|
<?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\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(env('unify'))->order->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(env('unify'))->order->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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,237 @@ |
|||||||
|
<?php |
||||||
|
declare(strict_types = 1); |
||||||
|
|
||||||
|
namespace App\Http\Logics\Outpatient; |
||||||
|
|
||||||
|
use App\Dictionary\Order\PayType; |
||||||
|
use App\Dictionary\Order\SourceId; |
||||||
|
use App\Dictionary\Order\Type; |
||||||
|
use App\Dictionary\Patient\CardType; |
||||||
|
use App\Exceptions\GeneralException; |
||||||
|
use App\Models\Order; |
||||||
|
use App\Services\HisHttp\Client; |
||||||
|
use App\Utils\Traits\Logger; |
||||||
|
use App\Utils\Traits\MiniProgramAuth; |
||||||
|
use Illuminate\Auth\AuthenticationException; |
||||||
|
use ReflectionException; |
||||||
|
use Symfony\Component\HttpFoundation\Response; |
||||||
|
use UnifyPayment\Cores\Exceptions\InvalidConfigException; |
||||||
|
use UnifyPayment\Cores\Exceptions\RuntimeException; |
||||||
|
use UnifyPayment\Cores\Struct\CreateOrder; |
||||||
|
use UnifyPayment\Unify; |
||||||
|
|
||||||
|
class PaymentLogic |
||||||
|
{ |
||||||
|
use Logger; |
||||||
|
use MiniProgramAuth; |
||||||
|
|
||||||
|
private Client $his_client; |
||||||
|
|
||||||
|
private Order $order_model; |
||||||
|
|
||||||
|
/** |
||||||
|
* PaymentLogic Construct |
||||||
|
* @throws AuthenticationException |
||||||
|
*/ |
||||||
|
public function __construct() |
||||||
|
{ |
||||||
|
$this->authInitialize(); |
||||||
|
$this->setChannel('outpatient'); |
||||||
|
$this->his_client = app('HisHttpService'); |
||||||
|
$this->order_model = new Order(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 支付 |
||||||
|
* @param string $patient_id |
||||||
|
* @param string $serial_no |
||||||
|
* @param string $prescription_ids |
||||||
|
* @param string $reg_id |
||||||
|
* @return array |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
public function payment(string $patient_id, string $serial_no, string $prescription_ids, string $reg_id): array |
||||||
|
{ |
||||||
|
// 基础信息 |
||||||
|
$patient_info = $this->getPatientInfo($patient_id, $this->open_id); |
||||||
|
$pending_info = $this->getPendingPrescriptionDetails($patient_id, $serial_no, $prescription_ids, $reg_id); |
||||||
|
|
||||||
|
// 创建订单 |
||||||
|
$order_type = Type::OUTPATIENT_PAYMENT; |
||||||
|
$pay_type = PayType::WECHAT_PAY; |
||||||
|
$order_id = $this->order_model->getOrderId($pay_type, 'M'); |
||||||
|
$total_fee = (float)(string) array_sum(array_column($pending_info['prescription_lists'], 'ZFJE')); |
||||||
|
|
||||||
|
$order = $this->createOrder($order_id, $pay_type, $total_fee, $order_type, $patient_info, $pending_info); |
||||||
|
|
||||||
|
// 申请支付 |
||||||
|
$pay_data = $this->applyPayment($order_type, $order_id, $total_fee, $patient_info['PATIENTID'], $patient_info['NAME']); |
||||||
|
|
||||||
|
// 去除无用数据 |
||||||
|
unset($pay_data['merchantId'], $pay_data['merchantName'], $pay_data['channelId'], $pay_data['channelName']); |
||||||
|
|
||||||
|
return $pay_data; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取患者信息 |
||||||
|
* @param string $patient_id |
||||||
|
* @param string $open_id |
||||||
|
* @return mixed |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
protected function getPatientInfo(string $patient_id, string $open_id): mixed |
||||||
|
{ |
||||||
|
$info = $this->patient_model->getBindPatientInfo($open_id, $patient_id); |
||||||
|
if (empty($info)) { |
||||||
|
throw new GeneralException('找不到患者信息,请重新再试!', Response::HTTP_BAD_REQUEST); |
||||||
|
} |
||||||
|
|
||||||
|
$patient_info = $this->his_client->getPatientInfo($info['patient_id'], CardType::OUTPATIENT_NO, $info['name']); |
||||||
|
if (!isset($patient_info['RESULTCODE']) || $patient_info['RESULTCODE'] !== '0') { |
||||||
|
throw new GeneralException($patient_info['ERRORMSG'] ?? '找不到患者信息,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
// 添加Patient 表ID |
||||||
|
$patient_info['id'] = $info['id']; |
||||||
|
|
||||||
|
$this->info('缴费患者信息', $info); |
||||||
|
return $info; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取缴费处方详情 |
||||||
|
* @param string $patient_id |
||||||
|
* @param string $serial_no |
||||||
|
* @param string $prescription_ids |
||||||
|
* @param string $reg_id |
||||||
|
* @return array |
||||||
|
* @ |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
protected function getPendingPrescriptionDetails(string $patient_id, string $serial_no, string $prescription_ids, string $reg_id): array |
||||||
|
{ |
||||||
|
$response = $this->his_client->getPendingLists($patient_id); |
||||||
|
|
||||||
|
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') { |
||||||
|
throw new GeneralException($response['ERRORMSG'] ?? '暂无相关缴费记录!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
// 获取具体的缴费详情 |
||||||
|
$response = xmlArrayToListByKey($response, 'ITEM'); |
||||||
|
foreach ($response['ITEM'] as $v) { |
||||||
|
if ($v['JZXH'] === $serial_no) { |
||||||
|
$info = $v; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (empty($info)) { |
||||||
|
throw new GeneralException('查询不到待缴费处方,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
$response = $this->his_client->getPendingDetails($prescription_ids, $serial_no, $reg_id); |
||||||
|
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') { |
||||||
|
throw new GeneralException($response['ERRORMSG'] ?? '暂无相关缴费记录!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
// 获取具体的缴费详情 |
||||||
|
$response = xmlArrayToListByKey($response, 'ITEM'); |
||||||
|
foreach ($response['ITEM'] as $v) { |
||||||
|
if (strpos($prescription_ids, $v['CFID'])) { |
||||||
|
$info['prescription_lists'][] = $v; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (empty($info['prescription_lists'])) { |
||||||
|
throw new GeneralException('查询不到待缴费处方详情,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
$info['prescription_ids'] = $prescription_ids; |
||||||
|
return $info; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 创建订单表 |
||||||
|
* @param string $order_id |
||||||
|
* @param PayType $pay_type |
||||||
|
* @param float $total_fee |
||||||
|
* @param Type $order_type |
||||||
|
* @param array $patient_info |
||||||
|
* @param array $pending_info |
||||||
|
* @return mixed |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
protected function createOrder(string $order_id, PayType $pay_type, float $total_fee, Type $order_type, array $patient_info, array $pending_info): mixed |
||||||
|
{ |
||||||
|
|
||||||
|
// 挂号记录表 |
||||||
|
$pay_record_data = [ |
||||||
|
'relate_patient_id' => $patient_info['id'], |
||||||
|
'dept_id' => $pending_info['BQDM'], |
||||||
|
'dept_name' => $pending_info['BQMC'], |
||||||
|
'doctor_id' => $pending_info['YSGH'], |
||||||
|
'doctor_name' => $pending_info['YSMC'], |
||||||
|
'visit_date' => date('Y-m-d', strtotime($pending_info['JZRQ'])), |
||||||
|
'total_amount' => $total_fee, |
||||||
|
'pre_settle_status' => 0, |
||||||
|
'extra_info' => json_encode($pending_info, JSON_UNESCAPED_UNICODE), |
||||||
|
]; |
||||||
|
|
||||||
|
$order = $this->order_model->createOrder( |
||||||
|
$order_id, |
||||||
|
$pay_type, |
||||||
|
$total_fee * 100, |
||||||
|
$this->open_id, |
||||||
|
$patient_info['PATIENTID'], |
||||||
|
$patient_info['NAME'], |
||||||
|
$order_type, |
||||||
|
SourceId::MINI_PROGRAM, |
||||||
|
$pay_record_data |
||||||
|
); |
||||||
|
if (empty($order)) { |
||||||
|
throw new GeneralException('创建缴费单失败,请重新再试!'); |
||||||
|
} |
||||||
|
|
||||||
|
$this->info('创建订单,ID:'. $order_id->id); |
||||||
|
return $order; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 申请支付 |
||||||
|
* @param Type $order_type |
||||||
|
* @param string $order_id |
||||||
|
* @param float $reg_fee |
||||||
|
* @param string $patient_id |
||||||
|
* @param string $patient_name |
||||||
|
* @return array |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
protected function applyPayment(Type $order_type, string $order_id, float $reg_fee, string $patient_id, string $patient_name): array |
||||||
|
{ |
||||||
|
try { |
||||||
|
$order_obj = new CreateOrder( |
||||||
|
$order_type->label(), |
||||||
|
$order_id, |
||||||
|
(string) $reg_fee, |
||||||
|
'1', |
||||||
|
$patient_id. '|'. $patient_name, |
||||||
|
'A', |
||||||
|
$this->open_id, |
||||||
|
url('/Api/Notify', [], true) |
||||||
|
); |
||||||
|
|
||||||
|
$response = Unify::pay(env('unify'))->mini->jsapi($order_obj); |
||||||
|
$this->info('jsapi 支付参数', $response); |
||||||
|
|
||||||
|
if (!$response['success'] || empty($response['response'])) { |
||||||
|
throw new GeneralException('申请支付失败,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
return $response['response']; |
||||||
|
} catch (InvalidConfigException|RuntimeException|ReflectionException $e) { |
||||||
|
throw new GeneralException('申请支付失败,请重新再试!', Response::HTTP_INTERNAL_SERVER_ERROR); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,104 @@ |
|||||||
|
<?php |
||||||
|
declare(strict_types = 1); |
||||||
|
|
||||||
|
namespace App\Http\Logics\Outpatient; |
||||||
|
|
||||||
|
use App\Exceptions\GeneralException; |
||||||
|
use App\Services\HisHttp\Client; |
||||||
|
use App\Utils\Traits\Logger; |
||||||
|
use App\Utils\Traits\MiniProgramAuth; |
||||||
|
use Illuminate\Auth\AuthenticationException; |
||||||
|
use Illuminate\Support\Facades\Cache; |
||||||
|
use Symfony\Component\HttpFoundation\Response; |
||||||
|
|
||||||
|
class PendingLogic |
||||||
|
{ |
||||||
|
use Logger; |
||||||
|
use MiniProgramAuth; |
||||||
|
|
||||||
|
private Client $his_client; |
||||||
|
|
||||||
|
/** |
||||||
|
* RecordLogic Construct |
||||||
|
* @throws AuthenticationException |
||||||
|
*/ |
||||||
|
public function __construct() |
||||||
|
{ |
||||||
|
$this->authInitialize(); |
||||||
|
$this->his_client = app('HisHttpService'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取挂号记录列表 |
||||||
|
* @param string $patient_id |
||||||
|
* @return array |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
public function getLists(string $patient_id,): array |
||||||
|
{ |
||||||
|
$response = $this->his_client->getPendingLists($patient_id); |
||||||
|
|
||||||
|
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') { |
||||||
|
throw new GeneralException($response['ERRORMSG'] ?? '暂无相关缴费记录!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
// 缓存2小时 |
||||||
|
Cache::set('Outpatient.Pending.'. $this->open_id.'.'. $patient_id, json_encode($response, JSON_UNESCAPED_UNICODE), 2 * 60 * 60); |
||||||
|
return $response; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取缴费记录详情 |
||||||
|
* @param string $patient_id |
||||||
|
* @param string $serial_no |
||||||
|
* @param string $prescription_ids |
||||||
|
* @param string $reg_id |
||||||
|
* @return array |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
public function getDetails(string $patient_id, string $serial_no, string $prescription_ids, string $reg_id): array |
||||||
|
{ |
||||||
|
$this->getCachePendingLists($patient_id, $serial_no); |
||||||
|
|
||||||
|
$response = $this->his_client->getPendingDetails($prescription_ids, $serial_no, $reg_id); |
||||||
|
|
||||||
|
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') { |
||||||
|
throw new GeneralException($response['ERRORMSG'] ?? '暂无相关缴费详情!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
return $response; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取缓存里的记录详情 |
||||||
|
* @param string $patient_id |
||||||
|
* @param string $serial_no |
||||||
|
* @return mixed |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
protected function getCachePendingLists(string $patient_id, string $serial_no): mixed |
||||||
|
{ |
||||||
|
$cache_key = 'Outpatient.Pending.'. $this->open_id.'.'. $patient_id; |
||||||
|
|
||||||
|
$pending_lists = Cache::get($cache_key); |
||||||
|
if (empty($pending_lists)) { |
||||||
|
throw new GeneralException($response['ERRORMSG'] ?? '查询不到缴费记录,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
$pending_lists = json_decode($pending_lists, true); |
||||||
|
|
||||||
|
// 获取具体的缴费详情 |
||||||
|
$pending_lists = xmlArrayToListByKey($pending_lists, 'ITEM'); |
||||||
|
foreach ($pending_lists['ITEM'] as $v) { |
||||||
|
if ($v['JZXH'] === $serial_no) { |
||||||
|
$info = $v; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (empty($info)) { |
||||||
|
throw new GeneralException('查询不到待缴费处方,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
return $info; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,250 @@ |
|||||||
|
<?php |
||||||
|
declare(strict_types = 1); |
||||||
|
|
||||||
|
namespace App\Http\Logics\Registration; |
||||||
|
|
||||||
|
use App\Dictionary\Order\PayType; |
||||||
|
use App\Dictionary\Order\SourceId; |
||||||
|
use App\Dictionary\Order\Type; |
||||||
|
use App\Dictionary\Patient\CardType; |
||||||
|
use App\Exceptions\GeneralException; |
||||||
|
use App\Models\Order; |
||||||
|
use App\Models\Patient; |
||||||
|
use App\Services\HisHttp\Client; |
||||||
|
use App\Utils\Traits\Logger; |
||||||
|
use App\Utils\Traits\MiniProgramAuth; |
||||||
|
use Illuminate\Auth\AuthenticationException; |
||||||
|
use ReflectionException; |
||||||
|
use Symfony\Component\HttpFoundation\Response; |
||||||
|
use UnifyPayment\Cores\Exceptions\InvalidConfigException; |
||||||
|
use UnifyPayment\Cores\Exceptions\RuntimeException; |
||||||
|
use UnifyPayment\Cores\Struct\CreateOrder; |
||||||
|
use UnifyPayment\Unify; |
||||||
|
|
||||||
|
class RegisterLogic |
||||||
|
{ |
||||||
|
use Logger; |
||||||
|
use MiniProgramAuth; |
||||||
|
|
||||||
|
private Client $his_client; |
||||||
|
|
||||||
|
private Order $order_model; |
||||||
|
|
||||||
|
private Patient $patient_model; |
||||||
|
|
||||||
|
/** |
||||||
|
* RegisterLogic Construct |
||||||
|
* @throws AuthenticationException |
||||||
|
*/ |
||||||
|
public function __construct() |
||||||
|
{ |
||||||
|
$this->authInitialize(); |
||||||
|
$this->setChannel('registration'); |
||||||
|
$this->his_client = app('HisHttpService'); |
||||||
|
$this->order_model = new Order(); |
||||||
|
$this->patient_model = new Patient(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $patient_id |
||||||
|
* @param string $date |
||||||
|
* @param string $dept_id |
||||||
|
* @param string $doctor_id |
||||||
|
* @param string $reg_id |
||||||
|
* @return array |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
public function register(string $patient_id, string $date, string $dept_id, string $doctor_id, string $reg_id): array |
||||||
|
{ |
||||||
|
// 基础信息 |
||||||
|
$patient_info = $this->getPatientInfo($patient_id, $this->open_id); |
||||||
|
$schedule_info = $this->getRegisterScheduleDetails($date, $dept_id, $doctor_id, $reg_id); |
||||||
|
|
||||||
|
// 锁号? |
||||||
|
|
||||||
|
// 创建订单 |
||||||
|
$order_type = $date === date('Y-m-d') ? Type::TODAY_REGISTRATION : Type::APPOINTMENT_REGISTRATION; |
||||||
|
$pay_type = PayType::WECHAT_PAY; |
||||||
|
$order_id = $this->order_model->getOrderId($pay_type, 'M'); |
||||||
|
$reg_fee = (float)(string) $schedule_info['FEE']; |
||||||
|
|
||||||
|
$order = $this->createOrder($order_id, $pay_type, $reg_fee, $order_type, $patient_info, $schedule_info); |
||||||
|
|
||||||
|
// 申请支付 |
||||||
|
$pay_data = $this->applyPayment($order_type, $order_id, $reg_fee, $patient_info['PATIENTID'], $patient_info['NAME']); |
||||||
|
|
||||||
|
// 去除无用数据 |
||||||
|
unset($pay_data['merchantId'], $pay_data['merchantName'], $pay_data['channelId'], $pay_data['channelName']); |
||||||
|
|
||||||
|
return $pay_data; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取患者信息 |
||||||
|
* @param string $patient_id |
||||||
|
* @param string $open_id |
||||||
|
* @return mixed |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
protected function getPatientInfo(string $patient_id, string $open_id): mixed |
||||||
|
{ |
||||||
|
$info = $this->patient_model->getBindPatientInfo($open_id, $patient_id); |
||||||
|
if (empty($info)) { |
||||||
|
throw new GeneralException('找不到患者信息,请重新再试!', Response::HTTP_BAD_REQUEST); |
||||||
|
} |
||||||
|
|
||||||
|
$patient_info = $this->his_client->getPatientInfo($info['patient_id'], CardType::OUTPATIENT_NO, $info['name']); |
||||||
|
if (!isset($patient_info['RESULTCODE']) || $patient_info['RESULTCODE'] !== '0') { |
||||||
|
throw new GeneralException($patient_info['ERRORMSG'] ?? '找不到患者信息,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
// 添加Patient 表ID |
||||||
|
$patient_info['id'] = $info['id']; |
||||||
|
|
||||||
|
$this->info('挂号患者信息', $info); |
||||||
|
return $info; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取挂号信息 |
||||||
|
* @param string $date |
||||||
|
* @param string $dept_id |
||||||
|
* @param string $doctor_id |
||||||
|
* @param string $reg_id |
||||||
|
* @return array |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
protected function getRegisterScheduleDetails(string $date, string $dept_id, string $doctor_id, string $reg_id): array |
||||||
|
{ |
||||||
|
// 获取排班医生信息 |
||||||
|
$is_today = $dept_id === date('Y-m-d') ? '3' : '1'; |
||||||
|
$schedule_info = $this->his_client->getDoctorLists($dept_id, $is_today, '', $date); |
||||||
|
if (!isset($schedule_info['RESULTCODE']) || $schedule_info['RESULTCODE'] !== '0') { |
||||||
|
throw new GeneralException($schedule_info['ERRORMSG'] ?? '找不到该号源,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
// 获取号源信息 |
||||||
|
$schedule_info = xmlArrayToListByKey($schedule_info, 'ITEM'); |
||||||
|
foreach ($schedule_info['ITEM'] as $v) { |
||||||
|
if ($v['DOCTID'] === $doctor_id) { |
||||||
|
$v = xmlArrayToListByKey($v, 'SHIFT'); |
||||||
|
foreach ($v['SHIFT'] as $v2) { |
||||||
|
if ($v2['REGID'] === $reg_id && $v['FDATE'] === $date) { |
||||||
|
$v['SHIFT'] = $v2; |
||||||
|
$info = $v; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (empty($info)) { |
||||||
|
throw new GeneralException('找不到该号源,请重新再试!', Response::HTTP_BAD_REQUEST); |
||||||
|
} |
||||||
|
|
||||||
|
if (!isset($info['SHIFT']['REGCOUNT']) || $info['SHIFT']['REGCOUNT'] <= 0) { |
||||||
|
throw new GeneralException('该号源已挂完,请重新选择号源!', Response::HTTP_BAD_REQUEST); |
||||||
|
} |
||||||
|
|
||||||
|
// 获取科室名称 |
||||||
|
$dept_lists = $this->his_client->getDepType('', '','01', $date); |
||||||
|
if (!isset($schedule_info['RESULTCODE']) || $schedule_info['RESULTCODE'] !== '0') { |
||||||
|
throw new GeneralException($schedule_info['ERRORMSG'] ?? '找不到该号源,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
$dept_lists = xmlArrayToListByKey($dept_lists, 'ITEM'); |
||||||
|
foreach ($dept_lists['ITEM'] as $v) { |
||||||
|
if ($v['DEPID'] === $dept_id) { |
||||||
|
$info['dept_id'] = $v['DEPID']; |
||||||
|
$info['dept_name'] = $v['DEPNAME']; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
$this->info('挂号排班信息', $info); |
||||||
|
return $info; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 创建订单表 |
||||||
|
* @param string $order_id |
||||||
|
* @param PayType $pay_type |
||||||
|
* @param float $reg_fee |
||||||
|
* @param Type $order_type |
||||||
|
* @param array $patient_info |
||||||
|
* @param array $schedule_info |
||||||
|
* @return mixed |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
protected function createOrder(string $order_id, PayType $pay_type, float $reg_fee, Type $order_type, array $patient_info, array $schedule_info): mixed |
||||||
|
{ |
||||||
|
// 挂号记录表 |
||||||
|
$reg_record_data = [ |
||||||
|
'relate_patient_id' => $patient_info['id'], |
||||||
|
'reg_id' => $schedule_info, |
||||||
|
'dept_id' => $schedule_info['dept_id'], |
||||||
|
'dept_name' => $schedule_info['dept_name'], |
||||||
|
'dept_location' => $schedule_info['DEPLOCATION'], |
||||||
|
'doctor_id' => $schedule_info['DOCTID'], |
||||||
|
'doctor_name' => $schedule_info['DOCTNAME'], |
||||||
|
'visit_date' => $schedule_info['SHIFT']['FDATE'], |
||||||
|
'begin_time' => $schedule_info['SHIFT']['STARTTIME'], |
||||||
|
'end_time' => $schedule_info['SHIFT']['ENDTIME'], |
||||||
|
'lock_status' => 0, |
||||||
|
'extra_info' => json_encode($schedule_info, JSON_UNESCAPED_UNICODE), |
||||||
|
]; |
||||||
|
|
||||||
|
$order = $this->order_model->createOrder( |
||||||
|
$order_id, |
||||||
|
$pay_type, |
||||||
|
$reg_fee * 100, |
||||||
|
$this->open_id, |
||||||
|
$patient_info['PATIENTID'], |
||||||
|
$patient_info['NAME'], |
||||||
|
$order_type, |
||||||
|
SourceId::MINI_PROGRAM, |
||||||
|
$reg_record_data |
||||||
|
); |
||||||
|
if (empty($order)) { |
||||||
|
throw new GeneralException('创建挂号单失败,请重新再试!'); |
||||||
|
} |
||||||
|
|
||||||
|
$this->info('创建订单,ID:'. $order_id->id); |
||||||
|
return $order; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 申请支付 |
||||||
|
* @param Type $order_type |
||||||
|
* @param string $order_id |
||||||
|
* @param float $reg_fee |
||||||
|
* @param string $patient_id |
||||||
|
* @param string $patient_name |
||||||
|
* @return array|string |
||||||
|
* @throws GeneralException |
||||||
|
*/ |
||||||
|
protected function applyPayment(Type $order_type, string $order_id, float $reg_fee, string $patient_id, string $patient_name): array|string |
||||||
|
{ |
||||||
|
try { |
||||||
|
$order_obj = new CreateOrder( |
||||||
|
$order_type->label(), |
||||||
|
$order_id, |
||||||
|
(string) $reg_fee, |
||||||
|
'1', |
||||||
|
$patient_id. '|'. $patient_name, |
||||||
|
'A', |
||||||
|
$this->open_id, |
||||||
|
url('/Api/Notify', [], true) |
||||||
|
); |
||||||
|
|
||||||
|
$response = Unify::pay(env('unify'))->mini->jsapi($order_obj); |
||||||
|
$this->info('jsapi 支付参数', $response); |
||||||
|
|
||||||
|
if (!$response['success'] || empty($response['response'])) { |
||||||
|
throw new GeneralException('申请支付失败,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
return $response['response']; |
||||||
|
} catch (InvalidConfigException|RuntimeException|ReflectionException $e) { |
||||||
|
throw new GeneralException('申请支付失败,请重新再试!', Response::HTTP_INTERNAL_SERVER_ERROR); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,66 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace App\Http\Requests\Registration; |
||||||
|
|
||||||
|
use App\Dictionary\Patient\IdentifyCardType; |
||||||
|
use Illuminate\Contracts\Validation\ValidationRule; |
||||||
|
use Illuminate\Foundation\Http\FormRequest; |
||||||
|
|
||||||
|
class RegisterRequest extends FormRequest |
||||||
|
{ |
||||||
|
/** |
||||||
|
* Determine if the user is authorized to make this request. |
||||||
|
*/ |
||||||
|
public function authorize(): bool |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the validation rules that apply to the request. |
||||||
|
* |
||||||
|
* @return array<string, ValidationRule|array|string> |
||||||
|
*/ |
||||||
|
/** |
||||||
|
* 规则 |
||||||
|
* @return array |
||||||
|
*/ |
||||||
|
public function rules(): array |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'date' => 'required|date_format:Y-m-d', |
||||||
|
'dept_id' => 'required', |
||||||
|
'doctor_id' => 'required', |
||||||
|
'reg_id' => 'required' |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 错误提示语句 |
||||||
|
* @return array |
||||||
|
*/ |
||||||
|
public function messages(): array |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'date.required' => '必须选择挂号日期', |
||||||
|
'date.date_format' => '必须选择挂号日期', |
||||||
|
'dept_id.required' => '必须选择挂号科室', |
||||||
|
'doctor_id.required' => '必须选择挂号医生', |
||||||
|
'reg_id.required' => '必须选择挂号时间段', |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 字段名称 |
||||||
|
* @return array |
||||||
|
*/ |
||||||
|
public function attributes(): array |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'date' => '挂号日期', |
||||||
|
'dept_id' => '挂号科室', |
||||||
|
'doctor_id' => '挂号医生', |
||||||
|
'reg_id' => '挂号时间段', |
||||||
|
]; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
<?php |
||||||
|
declare(strict_types = 1); |
||||||
|
|
||||||
|
namespace App\Http\Resources\Outpatient\Pending; |
||||||
|
|
||||||
|
use Illuminate\Http\Request; |
||||||
|
use Illuminate\Http\Resources\Json\JsonResource; |
||||||
|
|
||||||
|
class PendingDetailsResource extends JsonResource |
||||||
|
{ |
||||||
|
/** |
||||||
|
* Transform the resource into an array. |
||||||
|
* |
||||||
|
* @return array<string, mixed> |
||||||
|
*/ |
||||||
|
public function toArray(Request $request = null): array |
||||||
|
{ |
||||||
|
$lists = []; |
||||||
|
$this->resource = xmlArrayToListByKey($this->resource, 'ITEM'); |
||||||
|
|
||||||
|
foreach ($this->resource['ITEM'] as $v) { |
||||||
|
$lists[] = [ |
||||||
|
'fee_date' => $v['FYRQ'], |
||||||
|
'item_id' => $v['XMXH'], |
||||||
|
'item_code' => $v['XMBH'], |
||||||
|
'item_name' => $v['XMMC'], |
||||||
|
'price' => (float) $v['JG'], |
||||||
|
'quantity' => $v['MCYL'], |
||||||
|
'total_price' => $v['JE'], |
||||||
|
'package_name' => $v['ZTMC'], |
||||||
|
'self_pay_ratio' => $v['ZFBL'], |
||||||
|
'self_pay_fee' => (float) $v['ZFJE'], |
||||||
|
'prescription_id' => $v['CFID'], |
||||||
|
'unit' => $v['UNIT'], |
||||||
|
'prescription_type' => $v['CFTYPE'], |
||||||
|
'dept_id' => $v['BQDM'], |
||||||
|
'dept_name' => $v['BQMC'], |
||||||
|
'doctor_id' => $v['YSGH'], |
||||||
|
'doctor_name' => $v['YSMC'], |
||||||
|
// 冗余字段 |
||||||
|
'national_catalog_code' => $v['GJMLBM'] ?: '', |
||||||
|
'single_dose' => $v['YCJL'] ?: '', |
||||||
|
'frequency' => $v['YPYF'] ?: '', |
||||||
|
'medication_days' => $v['YYTS'] ?: '', |
||||||
|
'administration_route' => $v['GYTJ'] ?: '', |
||||||
|
'hospital_approval_flag' => $v['HOSP_APPR_FLAG'] ?: '', |
||||||
|
'chinese_medicine_usage' => $v['TCMDRUG_USED_WAY'] ?: '', |
||||||
|
'external_inspection_flag' => $v['ETIP_FLAG'] ?: '', |
||||||
|
'external_inspection_hospital_code' => $v['ETIP_HOSP_CODE'] ?: '', |
||||||
|
'discharge_medication_flag' => $v['DSCG_TKDRUG_FLAG'] ?: '', |
||||||
|
'maternity_fee_flag' => $v['MATN_FEE_FLAG'] ?: '', |
||||||
|
'external_purchase_prescription_flag' => $v['RX_CIRC_FLAG'] ?: '', |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
return $lists; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,50 @@ |
|||||||
|
<?php |
||||||
|
declare(strict_types = 1); |
||||||
|
|
||||||
|
namespace App\Http\Resources\Outpatient\Pending; |
||||||
|
|
||||||
|
use Illuminate\Http\Request; |
||||||
|
use Illuminate\Http\Resources\Json\JsonResource; |
||||||
|
|
||||||
|
class PendingListsResource extends JsonResource |
||||||
|
{ |
||||||
|
/** |
||||||
|
* Transform the resource into an array. |
||||||
|
* |
||||||
|
* @return array<string, mixed> |
||||||
|
*/ |
||||||
|
public function toArray(Request $request = null): array |
||||||
|
{ |
||||||
|
$this->resource = xmlArrayToListByKey($this->resource, 'ITEM'); |
||||||
|
|
||||||
|
$lists = []; |
||||||
|
foreach ($this->resource['ITEM'] as $v) { |
||||||
|
$lists[] = [ |
||||||
|
'category' => $v['JZLB'], |
||||||
|
'visit_date' => $v['JZRQ'], |
||||||
|
'diagnosis' => $v['CYZD'], |
||||||
|
'dept_id' => $v['BQDM'], |
||||||
|
'dept_name' => $v['BQMC'], |
||||||
|
'reg_id' => $v['REGID'], |
||||||
|
'prescription_id' => $v['CFID'], |
||||||
|
'total_prescription_amount' => (float) $v['YLFYZE'], |
||||||
|
'single_prescription_amount' => (float) $v['CFFYJE'] ?? 0, |
||||||
|
'doctor_id' => $v['YSGH'], |
||||||
|
'doctor_name' => $v['YSMC'], |
||||||
|
'remark' => $v['BZ'], |
||||||
|
'is_self_pay' => $v['ZFCF'], |
||||||
|
'visit_no' => $v['JZXH'], |
||||||
|
'prescription_number' => $v['CHHM'] ?: '', |
||||||
|
'prescription_type' => $v['CFTYPE'] ?: '', |
||||||
|
'exec_address' => $v['YFMC'] ?: '', |
||||||
|
'medical_type' => $v['MED_TYPE'] ?: '', |
||||||
|
'disease_code' => $v['DISE_CODG'] ?: '', |
||||||
|
'disease_name' => $v['DISE_NAME'] ?: '', |
||||||
|
'settlement_method' => $v['PSN_SETLWAY'] ?: '', |
||||||
|
'out_of_area_flag' => $v['OUT_FLAG'] ?: '' |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
return $lists; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue