From 90a80a57671a056a0113eb8dd240b455669b9e88 Mon Sep 17 00:00:00 2001
From: Rmiku <46063139+Rmiku@users.noreply.github.com>
Date: Mon, 6 Jan 2025 18:20:52 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0HisHttpClient?=
=?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=8C=82=E5=8F=B7=EF=BC=8C=E9=97=A8?=
=?UTF-8?q?=E8=AF=8A=EF=BC=8C=E5=9B=9E=E8=B0=83=E6=A8=A1=E5=9D=97=EF=BC=8C?=
=?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=95=B0=E6=8D=AE=E5=BA=93=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=EF=BC=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/Dictionary/Order/PayType.php | 15 +
.../Controllers/Notify/NotifyController.php | 94 +++++
.../Outpatient/PaymentController.php | 47 +++
.../Outpatient/PendingController.php | 64 ++++
.../Outpatient/RecordController.php | 2 +-
.../Registration/RegisterController.php | 40 +++
app/Http/Logics/Dictionary/ItemLogic.php | 10 +-
app/Http/Logics/Notify/NotifyLogic.php | 338 ++++++++++++++++++
app/Http/Logics/Outpatient/PaymentLogic.php | 237 ++++++++++++
app/Http/Logics/Outpatient/PendingLogic.php | 104 ++++++
app/Http/Logics/Outpatient/RecordLogic.php | 10 +-
app/Http/Logics/Registration/RecordLogic.php | 12 +-
.../Logics/Registration/RegisterLogic.php | 250 +++++++++++++
.../Logics/Registration/ScheduleLogic.php | 10 +-
.../Requests/Registration/RegisterRequest.php | 66 ++++
.../Pending/PendingDetailsResource.php | 58 +++
.../Pending/PendingListsResource.php | 50 +++
app/Models/Order.php | 3 +-
app/Providers/AppServiceProvider.php | 12 +-
app/Services/HisHttp/Client.php | 51 ++-
app/Utils/Helpers.php | 21 +-
.../HisHttpClient/ClientMockHttpTransfer.php | 37 +-
.../HisSoapClient/ClientMockSoapTransfer.php | 3 +-
app/Utils/Transfer/HttpTransferAbstract.php | 4 +-
config/logging.php | 27 ++
...0715_create_registration_records_table.php | 2 +-
...reate_outpatient_payment_records_table.php | 2 +-
.../src/Cores/Exceptions/RuntimeException.php | 2 -
routes/api.php | 11 +
29 files changed, 1517 insertions(+), 65 deletions(-)
create mode 100644 app/Http/Controllers/Notify/NotifyController.php
create mode 100644 app/Http/Controllers/Outpatient/PaymentController.php
create mode 100644 app/Http/Controllers/Outpatient/PendingController.php
create mode 100644 app/Http/Logics/Notify/NotifyLogic.php
create mode 100644 app/Http/Logics/Outpatient/PaymentLogic.php
create mode 100644 app/Http/Logics/Outpatient/PendingLogic.php
create mode 100644 app/Http/Logics/Registration/RegisterLogic.php
create mode 100644 app/Http/Requests/Registration/RegisterRequest.php
create mode 100644 app/Http/Resources/Outpatient/Pending/PendingDetailsResource.php
create mode 100644 app/Http/Resources/Outpatient/Pending/PendingListsResource.php
diff --git a/app/Dictionary/Order/PayType.php b/app/Dictionary/Order/PayType.php
index 03d1b88..378c423 100644
--- a/app/Dictionary/Order/PayType.php
+++ b/app/Dictionary/Order/PayType.php
@@ -47,4 +47,19 @@ enum PayType: int
self::MEDICAL_INSURANCE_PAY => 'YB',
};
}
+
+ /**
+ * His System Pay Code
+ * @return string
+ */
+ public function hisCode(): string
+ {
+ return match ($this) {
+ self::AGGREGATION_PAY => '12',
+ self::UNION_PAY => '12',
+ self::WECHAT_PAY => '88',
+ self::ALI_PAY => '89',
+ self::MEDICAL_INSURANCE_PAY => '3',
+ };
+ }
}
diff --git a/app/Http/Controllers/Notify/NotifyController.php b/app/Http/Controllers/Notify/NotifyController.php
new file mode 100644
index 0000000..ea959d7
--- /dev/null
+++ b/app/Http/Controllers/Notify/NotifyController.php
@@ -0,0 +1,94 @@
+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();
+ }
+}
diff --git a/app/Http/Controllers/Outpatient/PaymentController.php b/app/Http/Controllers/Outpatient/PaymentController.php
new file mode 100644
index 0000000..5be5409
--- /dev/null
+++ b/app/Http/Controllers/Outpatient/PaymentController.php
@@ -0,0 +1,47 @@
+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());
+ }
+}
diff --git a/app/Http/Controllers/Outpatient/PendingController.php b/app/Http/Controllers/Outpatient/PendingController.php
new file mode 100644
index 0000000..3986e89
--- /dev/null
+++ b/app/Http/Controllers/Outpatient/PendingController.php
@@ -0,0 +1,64 @@
+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());
+ }
+}
diff --git a/app/Http/Controllers/Outpatient/RecordController.php b/app/Http/Controllers/Outpatient/RecordController.php
index 3f8c379..e245418 100644
--- a/app/Http/Controllers/Outpatient/RecordController.php
+++ b/app/Http/Controllers/Outpatient/RecordController.php
@@ -47,7 +47,7 @@ class RecordController
}
/**
- * 退号
+ * 获取缴费记录详情
* @param Request $request
* @param string $patient_id
* @param string $serial_no
diff --git a/app/Http/Controllers/Registration/RegisterController.php b/app/Http/Controllers/Registration/RegisterController.php
index b3d9bbc..8c1cf25 100644
--- a/app/Http/Controllers/Registration/RegisterController.php
+++ b/app/Http/Controllers/Registration/RegisterController.php
@@ -1 +1,41 @@
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());
+ }
+}
diff --git a/app/Http/Logics/Dictionary/ItemLogic.php b/app/Http/Logics/Dictionary/ItemLogic.php
index aaea387..7e68628 100644
--- a/app/Http/Logics/Dictionary/ItemLogic.php
+++ b/app/Http/Logics/Dictionary/ItemLogic.php
@@ -4,7 +4,7 @@ declare(strict_types = 1);
namespace App\Http\Logics\Dictionary;
use App\Exceptions\GeneralException;
-use App\Services\HisSoap\Client;
+use App\Services\HisHttp\Client;
use App\Utils\Traits\Logger;
use App\Utils\Traits\MiniProgramAuth;
use App\Utils\Traits\UniversalEncryption;
@@ -17,7 +17,7 @@ class ItemLogic
use MiniProgramAuth;
use UniversalEncryption;
- private Client $his_soap;
+ private Client $his_client;
/**
* ItemLogic Construct
@@ -26,7 +26,7 @@ class ItemLogic
public function __construct()
{
$this->authInitialize();
- $this->his_soap = app('HisSoapService');
+ $this->his_client = app('HisHttpService');
}
/**
@@ -35,7 +35,7 @@ class ItemLogic
*/
public function getLists()
{
- $response = $this->his_soap->getDictionaryLists();
+ $response = $this->his_client->getDictionaryLists();
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') {
throw new GeneralException($response['ERRORMSG'] ?? '找不到缴费项目分类列表!', Response::HTTP_SERVICE_UNAVAILABLE);
}
@@ -51,7 +51,7 @@ class ItemLogic
*/
public function getDetails(int $type_id): array
{
- $response = $this->his_soap->getDictionaryDetails($type_id);
+ $response = $this->his_client->getDictionaryDetails($type_id);
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') {
throw new GeneralException($response['ERRORMSG'] ?? '找不到缴费项目分类详情!', Response::HTTP_SERVICE_UNAVAILABLE);
}
diff --git a/app/Http/Logics/Notify/NotifyLogic.php b/app/Http/Logics/Notify/NotifyLogic.php
new file mode 100644
index 0000000..b54c9d3
--- /dev/null
+++ b/app/Http/Logics/Notify/NotifyLogic.php
@@ -0,0 +1,338 @@
+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;
+ }
+ }
+}
diff --git a/app/Http/Logics/Outpatient/PaymentLogic.php b/app/Http/Logics/Outpatient/PaymentLogic.php
new file mode 100644
index 0000000..3398053
--- /dev/null
+++ b/app/Http/Logics/Outpatient/PaymentLogic.php
@@ -0,0 +1,237 @@
+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);
+ }
+ }
+}
diff --git a/app/Http/Logics/Outpatient/PendingLogic.php b/app/Http/Logics/Outpatient/PendingLogic.php
new file mode 100644
index 0000000..c4e4d7e
--- /dev/null
+++ b/app/Http/Logics/Outpatient/PendingLogic.php
@@ -0,0 +1,104 @@
+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;
+ }
+}
diff --git a/app/Http/Logics/Outpatient/RecordLogic.php b/app/Http/Logics/Outpatient/RecordLogic.php
index 4aa98e8..64f50c0 100644
--- a/app/Http/Logics/Outpatient/RecordLogic.php
+++ b/app/Http/Logics/Outpatient/RecordLogic.php
@@ -6,7 +6,7 @@ namespace App\Http\Logics\Outpatient;
use App\Exceptions\GeneralException;
use App\Models\Order;
use App\Models\RegistrationRecord;
-use App\Services\HisSoap\Client;
+use App\Services\HisHttp\Client;
use App\Utils\Traits\Logger;
use App\Utils\Traits\MiniProgramAuth;
use Illuminate\Auth\AuthenticationException;
@@ -18,7 +18,7 @@ class RecordLogic
use Logger;
use MiniProgramAuth;
- private Client $his_soap;
+ private Client $his_client;
/**
* RecordLogic Construct
@@ -27,7 +27,7 @@ class RecordLogic
public function __construct()
{
$this->authInitialize();
- $this->his_soap = app('HisSoapService');
+ $this->his_client = app('HisHttpService');
}
/**
@@ -40,7 +40,7 @@ class RecordLogic
*/
public function getRecordLists(string $patient_id, string $start_date, string $end_date): array
{
- $response = $this->his_soap->getPaidLists($patient_id, $start_date, $end_date);
+ $response = $this->his_client->getPaidLists($patient_id, $start_date, $end_date);
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') {
throw new GeneralException($response['ERRORMSG'] ?? '暂无相关挂号记录!', Response::HTTP_SERVICE_UNAVAILABLE);
@@ -62,7 +62,7 @@ class RecordLogic
{
$this->getCacheRecordInfo($patient_id, $serial_no);
- $response = $this->his_soap->getPaidDetails($serial_no);
+ $response = $this->his_client->getPaidDetails($serial_no);
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') {
throw new GeneralException($response['ERRORMSG'] ?? '暂无相关缴费详情!', Response::HTTP_SERVICE_UNAVAILABLE);
diff --git a/app/Http/Logics/Registration/RecordLogic.php b/app/Http/Logics/Registration/RecordLogic.php
index b39be41..21becdb 100644
--- a/app/Http/Logics/Registration/RecordLogic.php
+++ b/app/Http/Logics/Registration/RecordLogic.php
@@ -9,7 +9,7 @@ use App\Dictionary\Order\Type;
use App\Exceptions\GeneralException;
use App\Models\Order;
use App\Models\RegistrationRecord;
-use App\Services\HisSoap\Client;
+use App\Services\HisHttp\Client;
use App\Utils\Traits\Logger;
use App\Utils\Traits\MiniProgramAuth;
use Illuminate\Auth\AuthenticationException;
@@ -24,7 +24,7 @@ class RecordLogic
use Logger;
use MiniProgramAuth;
- private Client $his_soap;
+ private Client $his_client;
private RegistrationRecord $reg_record_model;
@@ -38,7 +38,7 @@ class RecordLogic
{
$this->authInitialize();
$this->setChannel('refund');
- $this->his_soap = app('HisSoapService');
+ $this->his_client = app('HisHttpService');
$this->reg_record_model = new RegistrationRecord();
$this->order_model = new Order();
}
@@ -53,7 +53,7 @@ class RecordLogic
*/
public function getRecordLists(string $patient_id, string $start_date, string $end_date): array
{
- $response = $this->his_soap->getRegisterRecordLists($patient_id, $start_date, $end_date);
+ $response = $this->his_client->getRegisterRecordLists($patient_id, $start_date, $end_date);
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') {
throw new GeneralException($response['ERRORMSG'] ?? '暂无相关挂号记录!', Response::HTTP_SERVICE_UNAVAILABLE);
@@ -109,7 +109,7 @@ class RecordLogic
$this->info('患者需退号的数据库挂号记录', $reg_record->toArray());
// 检查是否可以退号
- $response = $this->his_soap->checkRefundRegisterStatus($reg_serial_no);
+ $response = $this->his_client->checkRefundRegisterStatus($reg_serial_no);
$this->info('检查是否可进行退号', $response);
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') {
@@ -117,7 +117,7 @@ class RecordLogic
}
// 开始退号
- $response = $this->his_soap->refundRegister($reg_serial_no, $order_id, date('Y-m-d'), date('H:i:s'), (string) ($fee / 100));
+ $response = $this->his_client->refundRegister($reg_serial_no, $order_id, date('Y-m-d'), date('H:i:s'), (string) ($fee / 100));
$this->info('退号结果', $response);
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') {
diff --git a/app/Http/Logics/Registration/RegisterLogic.php b/app/Http/Logics/Registration/RegisterLogic.php
new file mode 100644
index 0000000..64178bb
--- /dev/null
+++ b/app/Http/Logics/Registration/RegisterLogic.php
@@ -0,0 +1,250 @@
+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);
+ }
+ }
+}
diff --git a/app/Http/Logics/Registration/ScheduleLogic.php b/app/Http/Logics/Registration/ScheduleLogic.php
index f3e5025..1181ff3 100644
--- a/app/Http/Logics/Registration/ScheduleLogic.php
+++ b/app/Http/Logics/Registration/ScheduleLogic.php
@@ -4,7 +4,7 @@ declare(strict_types = 1);
namespace App\Http\Logics\Registration;
use App\Exceptions\GeneralException;
-use App\Services\HisSoap\Client;
+use App\Services\HisHttp\Client;
use App\Utils\Traits\Logger;
use Symfony\Component\HttpFoundation\Response;
@@ -12,14 +12,14 @@ class ScheduleLogic
{
use Logger;
- private Client $his_soap;
+ private Client $his_client;
/**
* PatientLogic Construct
*/
public function __construct()
{
- $this->his_soap = app('HisSoapService');
+ $this->his_client = app('HisHttpService');
}
/**
@@ -30,7 +30,7 @@ class ScheduleLogic
*/
public function getDeptLists(string $date): array
{
- $response = $this->his_soap->getDepLists('', '','01', $date);
+ $response = $this->his_client->getDepType('', '','01', $date);
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') {
throw new GeneralException($response['ERRORMSG'] ?? '暂无科室排班!', Response::HTTP_SERVICE_UNAVAILABLE);
@@ -50,7 +50,7 @@ class ScheduleLogic
{
$type = $date === date('Y-m-d') ? '3' : '1';
- $response = $this->his_soap->getDoctorLists($dept_id, $type, '', $date);
+ $response = $this->his_client->getDoctorLists($dept_id, $type, '', $date);
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') {
throw new GeneralException($response['ERRORMSG'] ?? '该科室暂无医生排班!', Response::HTTP_SERVICE_UNAVAILABLE);
}
diff --git a/app/Http/Requests/Registration/RegisterRequest.php b/app/Http/Requests/Registration/RegisterRequest.php
new file mode 100644
index 0000000..72122ce
--- /dev/null
+++ b/app/Http/Requests/Registration/RegisterRequest.php
@@ -0,0 +1,66 @@
+
+ */
+ /**
+ * 规则
+ * @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' => '挂号时间段',
+ ];
+ }
+}
diff --git a/app/Http/Resources/Outpatient/Pending/PendingDetailsResource.php b/app/Http/Resources/Outpatient/Pending/PendingDetailsResource.php
new file mode 100644
index 0000000..1246701
--- /dev/null
+++ b/app/Http/Resources/Outpatient/Pending/PendingDetailsResource.php
@@ -0,0 +1,58 @@
+
+ */
+ 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;
+ }
+}
diff --git a/app/Http/Resources/Outpatient/Pending/PendingListsResource.php b/app/Http/Resources/Outpatient/Pending/PendingListsResource.php
new file mode 100644
index 0000000..d43c772
--- /dev/null
+++ b/app/Http/Resources/Outpatient/Pending/PendingListsResource.php
@@ -0,0 +1,50 @@
+
+ */
+ 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;
+ }
+}
diff --git a/app/Models/Order.php b/app/Models/Order.php
index 9b99ea9..fde8825 100644
--- a/app/Models/Order.php
+++ b/app/Models/Order.php
@@ -276,7 +276,6 @@ class Order extends Model
$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:
@@ -284,7 +283,7 @@ class Order extends Model
$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)]);
+ $record->update(['extra_info' => json_encode($extra_info, JSON_UNESCAPED_UNICODE)]);
break;
case Type::OUTPATIENT_PAYMENT->value:
$record = $order->outpatientPaymentREcord;
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index 8de5fcb..988056e 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -2,7 +2,8 @@
namespace App\Providers;
-use App\Services\HisSoap\Client;
+use App\Services\HisSoap\Client as HisSoapClient;
+use App\Services\HisHttp\Client as HisHttpClient;
use Illuminate\Support\Facades\Route;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\Facades\Schema;
@@ -54,9 +55,14 @@ class AppServiceProvider extends ServiceProvider
protected function registerHisService(): void
{
- // His平台服务
+ // His平台服务 - soap
$this->app->singleton('HisSoapService', function () {
- return new Client();
+ return new HisSoapClient();
+ });
+
+ // His平台服务 - http
+ $this->app->singleton('HisHttpService', function () {
+ return new HisHttpClient();
});
}
}
diff --git a/app/Services/HisHttp/Client.php b/app/Services/HisHttp/Client.php
index caafcd3..dfe1d5c 100644
--- a/app/Services/HisHttp/Client.php
+++ b/app/Services/HisHttp/Client.php
@@ -416,7 +416,7 @@ class Client
*/
public function getPendingLists(string $patient_id): mixed
{
- return $this->requestHandle('POST', 'ListVisitRec ', [
+ return $this->requestHandle('POST', 'ListVisitRec', [
'patientID' => $patient_id,
'registerArea' => '',
... $this->commonRequestData()
@@ -448,6 +448,55 @@ class Client
]);
}
+ /**
+ * 确认缴费
+ * @param string $patient_id 患者ID
+ * @param string $settle_type 结算类型 0 自费,1 门诊统筹
+ * @param string $settle_date 结算日期 yyyy-mm-dd
+ * @param string $prescription_ids 处方号,多张处方用,隔开
+ * @param string $reg_id 就诊序号
+ * @param string $reg_type 就诊类别
+ * @param string $order_id 交易流水号
+ * @param string $tran_type 支付方式 12 银联 3 医保 88 微信 89 支付宝
+ * @param string $total_fee 本次医疗费用
+ * @param string $self_fee 个人自付总额
+ * @param string $register_area 挂号区域
+ * @return mixed
+ * @throws GeneralException
+ */
+ public function confirmOutpatient(
+ string $patient_id,
+ string $settle_type,
+ string $settle_date,
+ string $prescription_ids,
+ string $reg_id,
+ string $reg_type,
+ string $order_id,
+ string $tran_type,
+ string $total_fee,
+ string $self_fee,
+ string $register_area = '01'
+ ): mixed
+ {
+ // 调用请求处理方法
+ return $this->requestHandle('POST', 'PayBillTrade', [
+ 'json' => [
+ 'patientID' => $patient_id,
+ 'settleType' => $settle_type,
+ 'jsrq' => $settle_date,
+ 'cfid' => $prescription_ids,
+ 'jzxh' => $reg_id,
+ 'jzlb' => $reg_type,
+ 'orderId' => $order_id,
+ 'tranType' => $tran_type,
+ 'ylfyze' => $total_fee,
+ 'grzfje' => $self_fee,
+ 'registerArea' => $register_area,
+ ... $this->commonRequestData()
+ ]
+ ]);
+ }
+
/**
* 获取门诊费用清单列表
* @param string $patient_id 患者ID,必填
diff --git a/app/Utils/Helpers.php b/app/Utils/Helpers.php
index fe815d8..9cbc52d 100644
--- a/app/Utils/Helpers.php
+++ b/app/Utils/Helpers.php
@@ -1,6 +1,7 @@
$this->mockRegisterCard($request_data),
'GetCardInfo' => $this->mockGetPatientInfo($request_data),
'GetDepType' => $this->mockGetDepLists($request_data),
@@ -59,7 +59,7 @@ class ClientMockHttpTransfer extends HttpTransferAbstract
'SendOutpatientinvoiceEBill' => $this->mockSendElectronInvoiceToHis($request_data),
'GetDictionary' => $this->mockGetDictionaryLists($request_data),
'GetChargeList' => $this->mockGetChargeList($request_data),
- default => throw new GeneralException("Method '{$method_name}' not found"),
+ default => throw new GeneralException("Method '{$request_name}' not found"),
};
}
@@ -72,8 +72,9 @@ class ClientMockHttpTransfer extends HttpTransferAbstract
public function responseFormat(mixed $data): mixed
{
try {
- // 此处为json格式
- return json_decode((string)$data, true);
+ // 此处为xml格式
+ $obj = simplexml_load_string((string)$data, 'SimpleXMLElement', LIBXML_NOCDATA);
+ return json_decode((string)json_encode($obj), true);
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
@@ -177,30 +178,16 @@ class ClientMockHttpTransfer extends HttpTransferAbstract
private function mockGetPendingLists(array $params)
{
- return [
- 'status' => 'success',
- 'message' => 'Pending list retrieved successfully.',
- 'data' => [
- [
- 'visit_no' => '12345',
- 'patient_id' => $params['PATIENTID'],
- 'amount' => '100.00'
- ]
- ]
- ];
+ $this->transfer_response = '0- 0441827197303226022门诊202107171.急性胃肠炎2.湿热证226发热门诊04-555585781.5316.210395麦明杰无特殊备注126719474-55558572普通医疗K52.9急性胃肠炎自费0
- 1441827199405226019住院202312151.高血压2.冠心病112心内科13-45678901050.75450.520876李海涛长期病管理037582913-45678901住院医疗I10高血压自费1
';
+
+ return $this;
}
private function mockGetPendingDetails(array $params)
{
- return [
- 'status' => 'success',
- 'message' => 'Pending details retrieved successfully.',
- 'data' => [
- 'cf_ids' => $params['CFID'],
- 'jz_xh' => $params['JZXH'],
- 'details' => 'Detailed description of the treatment.'
- ]
- ];
+ $this->transfer_response = '0- 2021-07-14130727842220尿妊娠试验(金标法)5.6715.6715.674-5549038项妊娠检查检验单8妇科门诊10537邝国超123451次口服1天口服给药0无0000
- 2021-07-14130727852231血常规检查12.34112.340.22.474-5549040项常规检查检验单8妇科门诊10538张伟678901次静脉注射1天静脉注射0无0000
- 2021-07-15130727863001超声波检查80.00180.000.540.004-5549041次影像检查影像单6放射科10539李明78901一次其他1天无1无0000
- 2021-07-16130727874002CT检查300.001300.000.390.004-5549042次影像检查影像单7影像科10540王磊345671次其他1天无1无0000
- 2021-07-17130727885003心电图检查25.00125.000.12.504-5549043次心电检查检查单9心内科10541赵云456781次其他1天无1无0000
';
+
+ return $this;
}
/**
diff --git a/app/Utils/Transfer/HisSoapClient/ClientMockSoapTransfer.php b/app/Utils/Transfer/HisSoapClient/ClientMockSoapTransfer.php
index 7bc92ee..ea551d4 100644
--- a/app/Utils/Transfer/HisSoapClient/ClientMockSoapTransfer.php
+++ b/app/Utils/Transfer/HisSoapClient/ClientMockSoapTransfer.php
@@ -143,8 +143,7 @@ class ClientMockSoapTransfer extends SoapTransferAbstract
*/
private function mockGetDoctorLists(array $params): self
{
- $this->transfer_response = '0Success- 1000120001张三内科一诊室主任医师110001300012024-12-271上午班08:0012:0050.00001201510001300022024-12-282下午班14:0018:0055.00002181210001300032024-12-293夜班20:0000:0060.00003108XM0011234567890挂号诊查费5010500
- 1000220002李四外科二诊室副主任医师010002300042024-12-271上午班08:0012:0060.00004252010002300052024-12-282下午班14:0018:0065.000052018XM0020987654321挂号诊查费100151500
-';
+ $this->transfer_response = '0Success- 1000120001张三内科一诊室主任医师110001300012024-12-271上午班08:0012:0050.00001201510001300022024-12-282下午班14:0018:0055.00002181210001300032024-12-293夜班20:0000:0060.00003108XM0011234567890挂号诊查费5010500
- 1000220002李四外科二诊室副主任医师010002300042024-12-271上午班08:0012:0060.00004252010002300052024-12-282下午班14:0018:0065.000052018XM0020987654321挂号诊查费100151500
';
return $this;
}
diff --git a/app/Utils/Transfer/HttpTransferAbstract.php b/app/Utils/Transfer/HttpTransferAbstract.php
index 244aed7..733ca1c 100644
--- a/app/Utils/Transfer/HttpTransferAbstract.php
+++ b/app/Utils/Transfer/HttpTransferAbstract.php
@@ -26,8 +26,8 @@ abstract class HttpTransferAbstract
// 调用接口参数
public mixed $transfer_parameter;
- // 调用返回结果
- public ResponseInterface $transfer_response;
+ // 调用返回结果 string格式用于mock数据
+ public ResponseInterface|string $transfer_response;
// 运行时间
public array $request_time;
diff --git a/config/logging.php b/config/logging.php
index 53b5a21..0095816 100644
--- a/config/logging.php
+++ b/config/logging.php
@@ -165,6 +165,24 @@ return [
'max_files' => 360,
],
+ // 挂号日志
+ 'registration' => [
+ 'driver' => 'custom',
+ 'via' => GeneralDailyLogger::class,
+ 'service_type' => 'RegisterLog',
+ 'level' => Level::Info,
+ 'max_files' => 30,
+ ],
+
+ // 挂号日志
+ 'outpatient' => [
+ 'driver' => 'custom',
+ 'via' => GeneralDailyLogger::class,
+ 'service_type' => 'OutpatientLog',
+ 'level' => Level::Info,
+ 'max_files' => 30,
+ ],
+
// 退费相关日志
'refund' => [
'driver' => 'custom',
@@ -173,6 +191,15 @@ return [
'level' => Level::Info,
'max_files' => 0,
],
+
+ // 通知相关日志
+ 'notify' => [
+ 'driver' => 'custom',
+ 'via' => GeneralDailyLogger::class,
+ 'service_type' => 'NotifyLog',
+ 'level' => Level::Info,
+ 'max_files' => 0,
+ ],
],
];
diff --git a/database/migrations/2023_03_03_080715_create_registration_records_table.php b/database/migrations/2023_03_03_080715_create_registration_records_table.php
index 68d4023..a5965cb 100644
--- a/database/migrations/2023_03_03_080715_create_registration_records_table.php
+++ b/database/migrations/2023_03_03_080715_create_registration_records_table.php
@@ -24,7 +24,7 @@ return new class () extends Migration {
$table->string('visit_date', 10)->index()->comment('就诊日期');
$table->string('begin_time', 5)->index()->comment('开始时间');
$table->string('end_time', 5)->comment('结束时间');
- $table->tinyInteger('lock_status')->index()->comment('锁号状态 1 已锁号 2 已解锁');
+ $table->tinyInteger('lock_status')->index()->comment('锁号状态 0 系统不支持锁号 1 已锁号 2 已解锁');
$table->timestamp('lock_at')->nullable()->comment('锁号时间');
$table->timestamp('unlock_at')->nullable()->comment('解锁时间');
$table->text('extra_info')->comment('额外的挂号信息');
diff --git a/database/migrations/2023_03_03_080952_create_outpatient_payment_records_table.php b/database/migrations/2023_03_03_080952_create_outpatient_payment_records_table.php
index ba8afae..da9e8bd 100644
--- a/database/migrations/2023_03_03_080952_create_outpatient_payment_records_table.php
+++ b/database/migrations/2023_03_03_080952_create_outpatient_payment_records_table.php
@@ -21,7 +21,7 @@ return new class () extends Migration {
$table->string('doctor_name', 20)->comment('医生名称');
$table->string('visit_date', 10)->index()->comment('就诊日期');
$table->integer('total_amount')->comment('处方总金额');
- $table->tinyInteger('pre_settle_status')->index()->comment('预结算状态 1 已预结算 2 已取消预结算');
+ $table->tinyInteger('pre_settle_status')->index()->comment('预结算状态 0 无需预结算 1 已预结算 2 已取消预结算');
$table->timestamp('pre_settle_at')->nullable()->comment('预结算时间');
$table->timestamp('cancel_pre_settle_at')->nullable()->comment('取消预结算时间');
$table->text('extra_info')->comment('额外的门诊信息');
diff --git a/packagist/unify_payment/src/Cores/Exceptions/RuntimeException.php b/packagist/unify_payment/src/Cores/Exceptions/RuntimeException.php
index 40c7053..cc04d7a 100644
--- a/packagist/unify_payment/src/Cores/Exceptions/RuntimeException.php
+++ b/packagist/unify_payment/src/Cores/Exceptions/RuntimeException.php
@@ -4,8 +4,6 @@ declare(strict_types=1);
namespace UnifyPayment\Cores\Exceptions;
-use Exception;
-
class RuntimeException extends Exception
{
/**
diff --git a/routes/api.php b/routes/api.php
index 3738cb0..4282575 100644
--- a/routes/api.php
+++ b/routes/api.php
@@ -1,9 +1,13 @@
group(function() {
Route::post('login', [AuthController::class, 'login']);
Route::any('unauthorized', [AuthController::class, 'unauthorized'])->name('login');
+ // 支付回调
+ Route::any('notify', [NotifyController::class, 'notify']);
+
Route::middleware(['auth:sanctum'])->group(function() {
// 患者模块
Route::prefix('Patient')->group(function () {
@@ -28,6 +35,7 @@ Route::middleware(['apiLog'])->group(function() {
Route::prefix('Registration')->group(function () {
Route::get('/dept', [ScheduleController::class, 'dept']);
Route::get('/doctor', [ScheduleController::class, 'doctor']);
+ Route::post('/{patient_id}/register', [RegisterController::class, 'register']);
Route::get('/{patient_id}/record', [RegistrationRecordController::class, 'lists']);
Route::post('/{patient_id}/record/{serial_no}/refund', [RegistrationRecordController::class, 'refund']);
@@ -35,6 +43,9 @@ Route::middleware(['apiLog'])->group(function() {
// 缴费模块
Route::prefix('Outpatient')->group(function () {
+ Route::get('/{patient_id}/pending', [PendingController::class, 'lists']);
+ Route::get('/{patient_id}/pending/{serial_no}/', [PendingController::class, 'details']);
+ Route::post('/{patient_id}/pending/{serial_no}/payment', [PaymentController::class, 'payment']);
Route::get('/{patient_id}/record', [OutpatientRecordController::class, 'lists']);
Route::get('/{patient_id}/record/{serial_no}/', [OutpatientRecordController::class, 'details']);