hospital-applets-api/app/Amqp/Consumer/AssignDoctorConsumer.php

304 lines
12 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace App\Amqp\Consumer;
use App\Amqp\Producer\CancelUnInquiryOrdersDelayDirectProducer;
use App\Amqp\Producer\CancelUnpayOrdersDelayDirectProducer;
use App\Constants\HttpEnumCode;
use App\Model\OrderInquiry;
use App\Model\UserDoctor;
use App\Services\ImService;
use App\Services\InquiryService;
use App\Services\MessagePush;
use App\Services\UserDoctorService;
use App\Utils\Log;
use Extend\TencentIm\Message;
use Extend\Wechat\WechatPay;
use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Amqp\Producer;
use Hyperf\Amqp\Result;
use Hyperf\Amqp\Annotation\Consumer;
use Hyperf\Amqp\Message\ConsumerMessage;
use Hyperf\DbConnection\Db;
use Hyperf\Redis\Redis;
use Hyperf\Snowflake\IdGeneratorInterface;
use PhpAmqpLib\Message\AMQPMessage;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
/**
* 自动分配医生
* 快速问诊、问诊购药等订单支付完成后,进行分配医生
*/
#[Consumer(exchange: 'amqp.direct', routingKey: 'AssignDoctor', queue: 'assign.doctor.queue', nums: 1)]
class AssignDoctorConsumer extends ConsumerMessage
{
/**
* @param $data
* @param AMQPMessage $message
* @return string
* @throws ContainerExceptionInterface
* @throws GuzzleException
* @throws NotFoundExceptionInterface
*/
public function consumeMessage($data, AMQPMessage $message): string
{
Log::getInstance('queue-AssignDoctor')->info("开始:" . json_encode($data, JSON_UNESCAPED_UNICODE));
Db::beginTransaction();
try {
// 获取订单数据
$params = array();
$params['order_inquiry_id'] = $data['order_inquiry_id'];
$order_inquiry = OrderInquiry::getOne($params);
if (empty($order_inquiry)) {
Db::rollBack();
Log::getInstance()->error("错误:未查询到对应订单数据");
return Result::DROP;// 销毁
}
$res = $this->checkInquiryStatus($order_inquiry);
if (!$res){
Db::rollBack();
Log::getInstance()->error("错误:订单状态错误");
return Result::DROP;// 销毁
}
// 检测分配时间
$pay_time = strtotime($order_inquiry['pay_time']);
$diff_time = time() - $pay_time;
if ($diff_time < 0) {
Db::rollBack();
Log::getInstance()->error("分配医生队列执行失败:订单支付状态错误:时间计算错误");
return Result::DROP;// 销毁
}
// 超出5分钟执行退款
if ($diff_time > 300) {
Log::getInstance()->error("分配医生队列执行失败:超出5分钟执行退款");
$InquiryService = new InquiryService();
// 检测问诊订单执行退款次数
Log::getInstance()->info("检测问诊订单执行退款次数");
$res = $InquiryService->checkInquiryRefundCount($order_inquiry['order_inquiry_id']);
if (!$res){
Db::rollBack();
Log::getInstance()->error("分配医生队列执行失败原因:超出最大退款次数");
return Result::ACK;
}
$InquiryService->inquiryRefund($order_inquiry['order_inquiry_id'], "无可分配医生");
// 取消问诊订单
$save_data = array();
$save_data['inquiry_status'] = 7;
$save_data['cancel_time'] = date("Y-m-d H:i:s", time());
$save_data['cancel_reason'] = 3; // 取消订单原因1:医生未接诊 2:主动取消 3:无可分配医生 4:客服取消 5:支付超时)
$save_data['cancel_remarks'] = "未分配到合适的医生"; // 取消订单备注
$save_data['updated_at'] = date("Y-m-d H:i:s", time());
$params = array();
$params['order_inquiry_id'] = $order_inquiry['order_inquiry_id'];
OrderInquiry::edit($params, $save_data);
Db::commit();
return Result::ACK;
}
// 检测当前是否符合系统问诊时间
$inquiryService = new InquiryService();
$is_system_time_pass = $inquiryService->checkSystemInquiryTime($order_inquiry['inquiry_type']);
if (!$is_system_time_pass && $order_inquiry['inquiry_type'] == 4){
// 非坐班时间
Log::getInstance()->error("分配医生队列执行失败:问诊购药非医生坐班时间,执行退款");
$InquiryService = new InquiryService();
// 检测问诊订单执行退款次数
Log::getInstance()->info("检测问诊订单执行退款次数");
$res = $InquiryService->checkInquiryRefundCount($order_inquiry['order_inquiry_id']);
if (!$res){
Db::rollBack();
Log::getInstance()->error("分配医生队列执行失败原因:超出最大退款次数");
return Result::ACK;
}
$InquiryService->inquiryRefund($order_inquiry['order_inquiry_id'], "无可分配医生");
// 取消问诊订单
$save_data = array();
$save_data['inquiry_status'] = 7;
$save_data['cancel_time'] = date("Y-m-d H:i:s", time());
$save_data['cancel_reason'] = 3; // 取消订单原因1:医生未接诊 2:主动取消 3:无可分配医生 4:客服取消 5:支付超时)
$save_data['cancel_remarks'] = "无可分配医生"; // 取消订单备注
$save_data['updated_at'] = date("Y-m-d H:i:s", time());
$params = array();
$params['order_inquiry_id'] = $order_inquiry['order_inquiry_id'];
OrderInquiry::edit($params, $save_data);
Db::commit();
return Result::ACK;
}
// 分配医生
$UserDoctorService = new UserDoctorService();
$doctor_id = $UserDoctorService->getInquiryAssignDoctor($order_inquiry['inquiry_type'],$order_inquiry['patient_id'],$is_system_time_pass);
if (empty($doctor_id)){
// 无合适医生
Db::rollBack();
Log::getInstance()->info("分配医生队列执行:目前没有合适医生");
$redis_value = $this->checkAssignCount($order_inquiry['order_inquiry_id']);
Log::getInstance()->info("分配医生队列执行:目前没有合适医生,重试第" . $redis_value . "");
// 执行睡眠,防止重复执行队列
// 执行规则第一次30秒第二次30秒。以30的倍数增加
sleep($redis_value * 5);
Log::getInstance()->info("分配医生队列执行:重回队列");
return Result::REQUEUE; // 重回队列
}
// 更改数据库
$save_data = array();
$save_data['doctor_id'] = $doctor_id;
$save_data['inquiry_status'] = 3; // 待接诊
$params = array();
$params['order_inquiry_id'] = $order_inquiry['order_inquiry_id'];
OrderInquiry::edit($params, $save_data);
// 加入未接诊取消订单延迟队列
$data = array();
$data['order_inquiry_id'] = $order_inquiry['order_inquiry_id'];
$message = new CancelUnInquiryOrdersDelayDirectProducer($data);
// 快速/购药-5分钟
$message->setDelayMs(1000 * 60 * 2);
$producer = $this->container->get(Producer::class);
$res = $producer->produce($message);
if (!$res) {
Db::rollBack();
Log::getInstance()->error("分配医生队列执行失败:加入未接诊取消订单延迟队列失败");
return Result::ACK;
}
Log::getInstance()->info("分配医生队列执行:加入未接诊取消订单延迟队列成功");
Db::commit();
Log::getInstance()->error("分配医生 队列执行成功");
} catch (\Exception $e) {
Db::rollBack();
Log::getInstance()->error("分配医生队列执行失败原因:" . $e->getMessage());
return Result::REQUEUE; // 重回队列
}
try {
// 分配医生成功,发送消息
// 获取订单医生数据
$params = array();
$params['doctor_id'] = $doctor_id;
$user_doctor = UserDoctor::getOne($params);
if (empty($user_doctor)) {
Log::getInstance()->info("医生数据错误");
return Result::ACK;
}
// 发送IM消息-等待医生接诊
$imService = new ImService();
$imService->waitDoctorInquiry($order_inquiry,$user_doctor['user_id'],$order_inquiry['user_id']);
// 医生-医生有新问诊 站内、订阅失败发送短信
$MessagePush = new MessagePush($user_doctor['user_id'],$order_inquiry['order_inquiry_id']);
$MessagePush->doctorHaveNewInquiry();
Log::getInstance()->info("分配医生成功,发送系统问诊消息成功");
} catch (\Exception $e) {
// 验证失败
Log::getInstance()->error("分配医生成功,发送系统问诊消息失败:" . $e->getMessage());
return Result::ACK;
}
return Result::ACK;
}
/**
* 检测问诊订单分配次数
* @param string $order_inquiry_id
* @return int
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function checkAssignCount(string $order_inquiry_id): int
{
Log::getInstance()->info("检测问诊订单分配次数");
$redis_value = 1;
try {
$redis = $this->container->get(Redis::class);
$redis_key = "AssignDoctor" . $order_inquiry_id;
$redis_value = $redis->get($redis_key);
if(empty($redis_value)){
$redis->set($redis_key, 1,60 * 60 * 24 * 5);
$redis_value = 1;
}else{
$redis_value = $redis->incr($redis_key);
}
} catch (\Exception $e) {
Log::getInstance()->error("检测问诊订单分配次数失败:抛出异常" . $e->getMessage());
}
Log::getInstance()->info("检测问诊订单分配次数成功");
return $redis_value;
}
/**
* 检测订单状态
* @param array|object $order_inquiry
* @return bool
*/
private function checkInquiryStatus(array|object $order_inquiry): bool
{
// 检测订单分配状态
if (!empty($order_inquiry['doctor_id'])) {
Log::getInstance()->error("分配医生队列执行失败:已分配医生");
return false;
}
// 检测订单类型
if ($order_inquiry['inquiry_type'] != 2 && $order_inquiry['inquiry_type'] != 4) {
Log::getInstance()->error("分配医生队列执行失败:订单非快速问诊、问诊购药类型");
return false;
}
// 检测订单退款状态
if (in_array($order_inquiry['inquiry_refund_status'], [1, 2, 3])) {
// 问诊订单退款状态0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭)
Log::getInstance()->error("分配医生队列执行失败:订单存在退款");
return false;
}
// 检测订单状态
if ($order_inquiry['inquiry_status'] != 2) {
// 问诊订单状态1:待支付 2:待分配 3:待接诊 4:已接诊 5:已完成 6:已结束 7:已取消)
Log::getInstance()->error("分配医生队列执行失败:订单状态错误:当前为" . $order_inquiry['inquiry_status'] . " 无法进行分配");
return false;
}
// 检测订单支付状态
if ($order_inquiry['inquiry_pay_status'] != 2) {
// 支付状态1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款)
Log::getInstance()->error("分配医生队列执行失败:订单支付状态错误:当前为" . $order_inquiry['inquiry_pay_status'] . " 无法进行分配");
return false;
}
return true;
}
}