feat: 添加HisHttpClient,添加挂号,门诊,回调模块,添加数据库文件,

master
Rmiku 2 weeks ago
parent 4ce8774ffd
commit 90a80a5767
  1. 15
      app/Dictionary/Order/PayType.php
  2. 94
      app/Http/Controllers/Notify/NotifyController.php
  3. 47
      app/Http/Controllers/Outpatient/PaymentController.php
  4. 64
      app/Http/Controllers/Outpatient/PendingController.php
  5. 2
      app/Http/Controllers/Outpatient/RecordController.php
  6. 40
      app/Http/Controllers/Registration/RegisterController.php
  7. 10
      app/Http/Logics/Dictionary/ItemLogic.php
  8. 338
      app/Http/Logics/Notify/NotifyLogic.php
  9. 237
      app/Http/Logics/Outpatient/PaymentLogic.php
  10. 104
      app/Http/Logics/Outpatient/PendingLogic.php
  11. 10
      app/Http/Logics/Outpatient/RecordLogic.php
  12. 12
      app/Http/Logics/Registration/RecordLogic.php
  13. 250
      app/Http/Logics/Registration/RegisterLogic.php
  14. 10
      app/Http/Logics/Registration/ScheduleLogic.php
  15. 66
      app/Http/Requests/Registration/RegisterRequest.php
  16. 58
      app/Http/Resources/Outpatient/Pending/PendingDetailsResource.php
  17. 50
      app/Http/Resources/Outpatient/Pending/PendingListsResource.php
  18. 3
      app/Models/Order.php
  19. 12
      app/Providers/AppServiceProvider.php
  20. 51
      app/Services/HisHttp/Client.php
  21. 21
      app/Utils/Helpers.php
  22. 37
      app/Utils/Transfer/HisHttpClient/ClientMockHttpTransfer.php
  23. 3
      app/Utils/Transfer/HisSoapClient/ClientMockSoapTransfer.php
  24. 4
      app/Utils/Transfer/HttpTransferAbstract.php
  25. 27
      config/logging.php
  26. 2
      database/migrations/2023_03_03_080715_create_registration_records_table.php
  27. 2
      database/migrations/2023_03_03_080952_create_outpatient_payment_records_table.php
  28. 2
      packagist/unify_payment/src/Cores/Exceptions/RuntimeException.php
  29. 11
      routes/api.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',
};
}
}

@ -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());
}
}

@ -47,7 +47,7 @@ class RecordController
}
/**
* 退号
* 获取缴费记录详情
* @param Request $request
* @param string $patient_id
* @param string $serial_no

@ -1 +1,41 @@
<?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());
}
}

@ -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);
}

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

@ -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);

@ -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') {

@ -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);
}
}
}

@ -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);
}

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

@ -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;

@ -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();
});
}
}

@ -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,必填

@ -1,6 +1,7 @@
<?php
use EasyWeChat\MiniApp\Application;
use EasyWeChat\MiniApp\Application as MiniApplication;
use EasyWeChat\Pay\Application as PayApplication;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Route;
@ -758,12 +759,24 @@ if (!function_exists('generateTree')) {
if (!function_exists('getWeChatMiniProgramApp')) {
/**
* 获取小程序app示例
* @return Application
* @return MiniApplication
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
*/
function getWeChatMiniProgramApp(): Application
function getWeChatMiniProgramApp(): MiniApplication
{
return new Application(config('wechat.mini'));
return new MiniApplication(config('wechat.mini'));
}
}
if (!function_exists('getWeChatMiniProgramPaymentApp')) {
/**
* 获取小程序支付app
* @return PayApplication
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
*/
function getWeChatMiniProgramPaymentApp(): PayApplication
{
return new PayApplication(config('wechat.payment'));
}
}

@ -40,10 +40,10 @@ class ClientMockHttpTransfer extends HttpTransferAbstract
/**
* @throws GeneralException
*/
public function transferMethod(string $method_name, array $request_data = []): self
public function transferMethod(string $method, string $request_name, array $request_data = []): self
{
// 使用 match 替代 switch
return match ($method_name) {
return match ($request_name) {
'CreateCardPatInfo' => $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 = '<RESPONSE><RESULTCODE>0</RESULTCODE><ERRORMSG></ERRORMSG><ITEM><YFMC>0</YFMC><GMSFHM>441827197303226022</GMSFHM><JZLB>门诊</JZLB><JZRQ>20210717</JZRQ><CYZD>1.急性胃肠炎2.湿热证</CYZD><BQDM>226</BQDM><BQMC>发热门诊</BQMC><REGID>0</REGID><CFID>4-5555857</CFID><YLFYZE>81.53</YLFYZE><CFFYJE>16.2</CFFYJE><YSGH>10395</YSGH><YSMC>麦明杰</YSMC><BZ>无特殊备注</BZ><ZFCF>1</ZFCF><JZXH>2671947</JZXH><CHHM>4-5555857</CHHM><CFTYPE>2</CFTYPE><MED_TYPE>普通医疗</MED_TYPE><DISE_CODG>K52.9</DISE_CODG><DISE_NAME>急性胃肠炎</DISE_NAME><PSN_SETLWAY>自费</PSN_SETLWAY><OUT_FLAG>0</OUT_FLAG></ITEM><ITEM><YFMC>1</YFMC><GMSFHM>441827199405226019</GMSFHM><JZLB>住院</JZLB><JZRQ>20231215</JZRQ><CYZD>1.高血压2.冠心病</CYZD><BQDM>112</BQDM><BQMC>心内科</BQMC><REGID>1</REGID><CFID>3-4567890</CFID><YLFYZE>1050.75</YLFYZE><CFFYJE>450.5</CFFYJE><YSGH>20876</YSGH><YSMC>李海涛</YSMC><BZ>长期病管理</BZ><ZFCF>0</ZFCF><JZXH>3758291</JZXH><CHHM>3-4567890</CHHM><CFTYPE>1</CFTYPE><MED_TYPE>住院医疗</MED_TYPE><DISE_CODG>I10</DISE_CODG><DISE_NAME>高血压</DISE_NAME><PSN_SETLWAY>自费</PSN_SETLWAY><OUT_FLAG>1</OUT_FLAG></ITEM></RESPONSE>';
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 = '<RESPONSE><RESULTCODE>0</RESULTCODE><ERRORMSG></ERRORMSG><ITEM><FYRQ>2021-07-14</FYRQ><XMXH>13072784</XMXH><XMBH>2220</XMBH><XMMC>尿妊娠试验(金标法)</XMMC><JG>5.67</JG><MCYL>1</MCYL><JE>5.67</JE><ZFBL>1</ZFBL><ZFJE>5.67</ZFJE><CFID>4-5549038</CFID><UNIT></UNIT><ZTMC>妊娠检查</ZTMC><CFTYPE>检验单</CFTYPE><BQDM>8</BQDM><BQMC>妇科门诊</BQMC><YSGH>10537</YSGH><YSMC>邝国超</YSMC><GJMLBM>12345</GJMLBM><YCJL>1次</YCJL><YPYF>口服</YPYF><YYTS>1天</YYTS><GYTJ>口服给药</GYTJ><HOSP_APPR_FLAG>0</HOSP_APPR_FLAG><TCMDRUG_USED_WAY></TCMDRUG_USED_WAY><ETIP_FLAG>0</ETIP_FLAG><ETIP_HOSP_CODE></ETIP_HOSP_CODE><DSCG_TKDRUG_FLAG>0</DSCG_TKDRUG_FLAG><MATN_FEE_FLAG>0</MATN_FEE_FLAG><RX_CIRC_FLAG>0</RX_CIRC_FLAG></ITEM><ITEM><FYRQ>2021-07-14</FYRQ><XMXH>13072785</XMXH><XMBH>2231</XMBH><XMMC>血常规检查</XMMC><JG>12.34</JG><MCYL>1</MCYL><JE>12.34</JE><ZFBL>0.2</ZFBL><ZFJE>2.47</ZFJE><CFID>4-5549040</CFID><UNIT></UNIT><ZTMC>常规检查</ZTMC><CFTYPE>检验单</CFTYPE><BQDM>8</BQDM><BQMC>妇科门诊</BQMC><YSGH>10538</YSGH><YSMC>张伟</YSMC><GJMLBM>67890</GJMLBM><YCJL>1次</YCJL><YPYF>静脉注射</YPYF><YYTS>1天</YYTS><GYTJ>静脉注射</GYTJ><HOSP_APPR_FLAG>0</HOSP_APPR_FLAG><TCMDRUG_USED_WAY></TCMDRUG_USED_WAY><ETIP_FLAG>0</ETIP_FLAG><ETIP_HOSP_CODE></ETIP_HOSP_CODE><DSCG_TKDRUG_FLAG>0</DSCG_TKDRUG_FLAG><MATN_FEE_FLAG>0</MATN_FEE_FLAG><RX_CIRC_FLAG>0</RX_CIRC_FLAG></ITEM><ITEM><FYRQ>2021-07-15</FYRQ><XMXH>13072786</XMXH><XMBH>3001</XMBH><XMMC>超声波检查</XMMC><JG>80.00</JG><MCYL>1</MCYL><JE>80.00</JE><ZFBL>0.5</ZFBL><ZFJE>40.00</ZFJE><CFID>4-5549041</CFID><UNIT></UNIT><ZTMC>影像检查</ZTMC><CFTYPE>影像单</CFTYPE><BQDM>6</BQDM><BQMC>放射科</BQMC><YSGH>10539</YSGH><YSMC>李明</YSMC><GJMLBM>78901</GJMLBM><YCJL>一次</YCJL><YPYF>其他</YPYF><YYTS>1天</YYTS><GYTJ></GYTJ><HOSP_APPR_FLAG>1</HOSP_APPR_FLAG><TCMDRUG_USED_WAY></TCMDRUG_USED_WAY><ETIP_FLAG>0</ETIP_FLAG><ETIP_HOSP_CODE></ETIP_HOSP_CODE><DSCG_TKDRUG_FLAG>0</DSCG_TKDRUG_FLAG><MATN_FEE_FLAG>0</MATN_FEE_FLAG><RX_CIRC_FLAG>0</RX_CIRC_FLAG></ITEM><ITEM><FYRQ>2021-07-16</FYRQ><XMXH>13072787</XMXH><XMBH>4002</XMBH><XMMC>CT检查</XMMC><JG>300.00</JG><MCYL>1</MCYL><JE>300.00</JE><ZFBL>0.3</ZFBL><ZFJE>90.00</ZFJE><CFID>4-5549042</CFID><UNIT></UNIT><ZTMC>影像检查</ZTMC><CFTYPE>影像单</CFTYPE><BQDM>7</BQDM><BQMC>影像科</BQMC><YSGH>10540</YSGH><YSMC>王磊</YSMC><GJMLBM>34567</GJMLBM><YCJL>1次</YCJL><YPYF>其他</YPYF><YYTS>1天</YYTS><GYTJ></GYTJ><HOSP_APPR_FLAG>1</HOSP_APPR_FLAG><TCMDRUG_USED_WAY></TCMDRUG_USED_WAY><ETIP_FLAG>0</ETIP_FLAG><ETIP_HOSP_CODE></ETIP_HOSP_CODE><DSCG_TKDRUG_FLAG>0</DSCG_TKDRUG_FLAG><MATN_FEE_FLAG>0</MATN_FEE_FLAG><RX_CIRC_FLAG>0</RX_CIRC_FLAG></ITEM><ITEM><FYRQ>2021-07-17</FYRQ><XMXH>13072788</XMXH><XMBH>5003</XMBH><XMMC>心电图检查</XMMC><JG>25.00</JG><MCYL>1</MCYL><JE>25.00</JE><ZFBL>0.1</ZFBL><ZFJE>2.50</ZFJE><CFID>4-5549043</CFID><UNIT></UNIT><ZTMC>心电检查</ZTMC><CFTYPE>检查单</CFTYPE><BQDM>9</BQDM><BQMC>心内科</BQMC><YSGH>10541</YSGH><YSMC>赵云</YSMC><GJMLBM>45678</GJMLBM><YCJL>1次</YCJL><YPYF>其他</YPYF><YYTS>1天</YYTS><GYTJ></GYTJ><HOSP_APPR_FLAG>1</HOSP_APPR_FLAG><TCMDRUG_USED_WAY></TCMDRUG_USED_WAY><ETIP_FLAG>0</ETIP_FLAG><ETIP_HOSP_CODE></ETIP_HOSP_CODE><DSCG_TKDRUG_FLAG>0</DSCG_TKDRUG_FLAG><MATN_FEE_FLAG>0</MATN_FEE_FLAG><RX_CIRC_FLAG>0</RX_CIRC_FLAG></ITEM></RESPONSE>';
return $this;
}
/**

@ -143,8 +143,7 @@ class ClientMockSoapTransfer extends SoapTransferAbstract
*/
private function mockGetDoctorLists(array $params): self
{
$this->transfer_response = '<RESPONSE><RESULTCODE>0</RESULTCODE><ERRORMSG>Success</ERRORMSG><ITEM><DOCTID>10001</DOCTID><YBDOCTID>20001</YBDOCTID><DOCTNAME>张三</DOCTNAME><DEPLOCATION>内科一诊室</DEPLOCATION><TYPENAME>主任医师</TYPENAME><ISKSDOC>1</ISKSDOC><SHIFT><DOCTID>10001</DOCTID><REGID>30001</REGID><FDATE>2024-12-27</FDATE><RANKID>1</RANKID><RANKNAME>上午班</RANKNAME><STARTTIME>08:00</STARTTIME><ENDTIME>12:00</ENDTIME><FEE>50.00</FEE><FEECODE>001</FEECODE><REGCOUNT>20</REGCOUNT><JZCOUNT>15</JZCOUNT></SHIFT><SHIFT><DOCTID>10001</DOCTID><REGID>30002</REGID><FDATE>2024-12-28</FDATE><RANKID>2</RANKID><RANKNAME>下午班</RANKNAME><STARTTIME>14:00</STARTTIME><ENDTIME>18:00</ENDTIME><FEE>55.00</FEE><FEECODE>002</FEECODE><REGCOUNT>18</REGCOUNT><JZCOUNT>12</JZCOUNT></SHIFT><SHIFT><DOCTID>10001</DOCTID><REGID>30003</REGID><FDATE>2024-12-29</FDATE><RANKID>3</RANKID><RANKNAME>夜班</RANKNAME><STARTTIME>20:00</STARTTIME><ENDTIME>00:00</ENDTIME><FEE>60.00</FEE><FEECODE>003</FEECODE><REGCOUNT>10</REGCOUNT><JZCOUNT>8</JZCOUNT></SHIFT><XMBH>XM001</XMBH><GJMLBM>1234567890</GJMLBM><XMMC>挂号诊查费</XMMC><JG>50</JG><MCYL>10</MCYL><JE>500</JE></ITEM><ITEM><DOCTID>10002</DOCTID><YBDOCTID>20002</YBDOCTID><DOCTNAME>李四</DOCTNAME><DEPLOCATION>外科二诊室</DEPLOCATION><TYPENAME>副主任医师</TYPENAME><ISKSDOC>0</ISKSDOC><SHIFT><DOCTID>10002</DOCTID><REGID>30004</REGID><FDATE>2024-12-27</FDATE><RANKID>1</RANKID><RANKNAME>上午班</RANKNAME><STARTTIME>08:00</STARTTIME><ENDTIME>12:00</ENDTIME><FEE>60.00</FEE><FEECODE>004</FEECODE><REGCOUNT>25</REGCOUNT><JZCOUNT>20</JZCOUNT></SHIFT><SHIFT><DOCTID>10002</DOCTID><REGID>30005</REGID><FDATE>2024-12-28</FDATE><RANKID>2</RANKID><RANKNAME>下午班</RANKNAME><STARTTIME>14:00</STARTTIME><ENDTIME>18:00</ENDTIME><FEE>65.00</FEE><FEECODE>005</FEECODE><REGCOUNT>20</REGCOUNT><JZCOUNT>18</JZCOUNT></SHIFT><XMBH>XM002</XMBH><GJMLBM>0987654321</GJMLBM><XMMC>挂号诊查费</XMMC><JG>100</JG><MCYL>15</MCYL><JE>1500</JE></ITEM></RESPONSE>
';
$this->transfer_response = '<RESPONSE><RESULTCODE>0</RESULTCODE><ERRORMSG>Success</ERRORMSG><ITEM><DOCTID>10001</DOCTID><YBDOCTID>20001</YBDOCTID><DOCTNAME>张三</DOCTNAME><DEPLOCATION>内科一诊室</DEPLOCATION><TYPENAME>主任医师</TYPENAME><ISKSDOC>1</ISKSDOC><SHIFT><DOCTID>10001</DOCTID><REGID>30001</REGID><FDATE>2024-12-27</FDATE><RANKID>1</RANKID><RANKNAME>上午班</RANKNAME><STARTTIME>08:00</STARTTIME><ENDTIME>12:00</ENDTIME><FEE>50.00</FEE><FEECODE>001</FEECODE><REGCOUNT>20</REGCOUNT><JZCOUNT>15</JZCOUNT></SHIFT><SHIFT><DOCTID>10001</DOCTID><REGID>30002</REGID><FDATE>2024-12-28</FDATE><RANKID>2</RANKID><RANKNAME>下午班</RANKNAME><STARTTIME>14:00</STARTTIME><ENDTIME>18:00</ENDTIME><FEE>55.00</FEE><FEECODE>002</FEECODE><REGCOUNT>18</REGCOUNT><JZCOUNT>12</JZCOUNT></SHIFT><SHIFT><DOCTID>10001</DOCTID><REGID>30003</REGID><FDATE>2024-12-29</FDATE><RANKID>3</RANKID><RANKNAME>夜班</RANKNAME><STARTTIME>20:00</STARTTIME><ENDTIME>00:00</ENDTIME><FEE>60.00</FEE><FEECODE>003</FEECODE><REGCOUNT>10</REGCOUNT><JZCOUNT>8</JZCOUNT></SHIFT><XMBH>XM001</XMBH><GJMLBM>1234567890</GJMLBM><XMMC>挂号诊查费</XMMC><JG>50</JG><MCYL>10</MCYL><JE>500</JE></ITEM><ITEM><DOCTID>10002</DOCTID><YBDOCTID>20002</YBDOCTID><DOCTNAME>李四</DOCTNAME><DEPLOCATION>外科二诊室</DEPLOCATION><TYPENAME>副主任医师</TYPENAME><ISKSDOC>0</ISKSDOC><SHIFT><DOCTID>10002</DOCTID><REGID>30004</REGID><FDATE>2024-12-27</FDATE><RANKID>1</RANKID><RANKNAME>上午班</RANKNAME><STARTTIME>08:00</STARTTIME><ENDTIME>12:00</ENDTIME><FEE>60.00</FEE><FEECODE>004</FEECODE><REGCOUNT>25</REGCOUNT><JZCOUNT>20</JZCOUNT></SHIFT><SHIFT><DOCTID>10002</DOCTID><REGID>30005</REGID><FDATE>2024-12-28</FDATE><RANKID>2</RANKID><RANKNAME>下午班</RANKNAME><STARTTIME>14:00</STARTTIME><ENDTIME>18:00</ENDTIME><FEE>65.00</FEE><FEECODE>005</FEECODE><REGCOUNT>20</REGCOUNT><JZCOUNT>18</JZCOUNT></SHIFT><XMBH>XM002</XMBH><GJMLBM>0987654321</GJMLBM><XMMC>挂号诊查费</XMMC><JG>100</JG><MCYL>15</MCYL><JE>1500</JE></ITEM></RESPONSE>';
return $this;
}

@ -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;

@ -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,
],
],
];

@ -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('额外的挂号信息');

@ -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('额外的门诊信息');

@ -4,8 +4,6 @@ declare(strict_types=1);
namespace UnifyPayment\Cores\Exceptions;
use Exception;
class RuntimeException extends Exception
{
/**

@ -1,9 +1,13 @@
<?php
use App\Http\Controllers\Auth\AuthController;
use App\Http\Controllers\Notify\NotifyController;
use App\Http\Controllers\Outpatient\PaymentController;
use App\Http\Controllers\Outpatient\PendingController;
use App\Http\Controllers\Outpatient\RecordController as OutpatientRecordController;
use App\Http\Controllers\Patient\PatientController;
use App\Http\Controllers\Registration\RecordController as RegistrationRecordController;
use App\Http\Controllers\Registration\RegisterController;
use App\Http\Controllers\Registration\ScheduleController;
use App\Http\Controllers\Dictionary\ItemController;
use Illuminate\Support\Facades\Route;
@ -13,6 +17,9 @@ Route::middleware(['apiLog'])->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']);

Loading…
Cancel
Save