hospital-applets-api/app/Amqp/Consumer/AssignDoctorDelayDirectConsumer.php
2024-04-28 11:14:44 +08:00

405 lines
16 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\AssignDoctorDelayDirectProducer;
use App\Amqp\Producer\CancelUnInquiryOrdersDelayDirectProducer;
use App\Amqp\Producer\DoctorNotYetInquiryDelayDirectProducer;
use App\Amqp\Producer\UserCouponExpiredDelayDirectProducer;
use App\Constants\HttpEnumCode;
use App\Model\Order;
use App\Model\OrderInquiry;
use App\Model\OrderInquiryCase;
use App\Model\UserDoctor;
use App\Services\ImService;
use App\Services\InquiryService;
use App\Services\MessagePush;
use App\Services\OrderService;
use App\Services\UserDoctorService;
use App\Utils\Log;
use App\Utils\Utils;
use Hyperf\Amqp\Message\ConsumerDelayedMessageTrait;
use Hyperf\Amqp\Message\ProducerDelayedMessageTrait;
use Hyperf\Amqp\Message\Type;
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 PhpAmqpLib\Message\AMQPMessage;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
/**
* 快速-购药分配医生
*/
#[Consumer(nums: 1)]
class AssignDoctorDelayDirectConsumer extends ConsumerMessage
{
use ProducerDelayedMessageTrait;
use ConsumerDelayedMessageTrait;
protected string $exchange = 'amqp.delay.direct';
protected ?string $queue = 'assign.doctor.delay.queue';
protected string $type = Type::DIRECT; //Type::FANOUT;
protected string|array $routingKey = 'AssignDoctor';
public function consumeMessage($data, AMQPMessage $message): string
{
return Result::ACK;
Log::getInstance('queue-AssignDoctor')->info(json_encode($data, JSON_UNESCAPED_UNICODE));
// 获取订单数据
$params = array();
$params['order_inquiry_id'] = $data['order_inquiry_id'];
$order_inquiry = OrderInquiry::getOne($params);
if (empty($order_inquiry)) {
Log::getInstance('queue-AssignDoctor')->error("未查询到对应订单数据");
return Result::DROP;// 销毁
}
// 获取病例数据
$params = array();
$params['order_inquiry_id'] = $order_inquiry['order_inquiry_id'];
$order_inquiry_case = OrderInquiryCase::getOne($params);
if (empty($order_inquiry_case)){
Log::getInstance('queue-AssignDoctor')->error("患者病例错误");
return Result::DROP;// 销毁
}
// 检测订单状态
$res = $this->checkInquiryStatus($order_inquiry);
if (!$res){
Log::getInstance('queue-AssignDoctor')->error("订单状态错误");
return Result::DROP;// 销毁
}
// 检测分配时间
$pay_time = strtotime($order_inquiry['pay_time']);
$diff_time = time() - $pay_time;
if ($diff_time < 0) {
Log::getInstance('queue-AssignDoctor')->error("支付时间错误");
return Result::DROP;// 销毁
}
Db::beginTransaction();
try {
// 检测当前是否符合系统问诊时间
$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("queue-AssignDoctor")->info("非坐班时间,执行退款");
// 检测执行次数
$Utils = new Utils();
$redis_key = "inquiryRefund" . $order_inquiry['inquiry_no'];
$res = $Utils->checkHandleNumber($redis_key);
if (!$res) {
Db::rollBack();
Log::getInstance("queue-CancelUnInquiryOrders")->error("超出最大执行次数或检测错误");
return Result::ACK;
}
$OrderService = new OrderService();
$OrderService->orderRefund($order_inquiry['inquiry_no'], "无可分配医生");
// 取消订单
$order_data = array();
$order_data['cancel_status'] = 1;
$order_data['cancel_time'] = date("Y-m-d H:i:s", time());
$order_data['cancel_remarks'] = "未分配到合适的医生";
$order_data['updated_at'] = date("Y-m-d H:i:s", time());
$params = array();
$params['order_id'] = $order_inquiry['order_id'];
Order::edit($params, $order_data);
$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();
try {
// 患者-分配医生失败-订阅
$MessagePush = new MessagePush($order_inquiry['user_id'],$order_inquiry['inquiry_no']);
$MessagePush->assignDoctorFail();
}catch (\Exception $e){
Log::getInstance("queue-AssignDoctor")->error( $e->getMessage());
}
return Result::ACK;
}
// 检测分配时间
if ($diff_time > 600) {
Log::getInstance("queue-AssignDoctor")->info("超出10分钟执行退款");
// 检测执行次数
$Utils = new Utils();
$redis_key = "inquiryRefund" . $order_inquiry['inquiry_no'];
$res = $Utils->checkHandleNumber($redis_key);
if (!$res) {
Db::rollBack();
Log::getInstance("queue-CancelUnInquiryOrders")->error("超出最大执行次数或检测错误");
return Result::ACK;
}
$OrderService = new OrderService();
$OrderService->orderRefund($order_inquiry['inquiry_no'], "未分配到合适的医生");
// 取消订单
$order_data = array();
$order_data['cancel_status'] = 1;
$order_data['cancel_time'] = date("Y-m-d H:i:s", time());
$order_data['cancel_remarks'] = "未分配到合适的医生";
$order_data['updated_at'] = date("Y-m-d H:i:s", time());
$params = array();
$params['order_id'] = $order_inquiry['order_id'];
Order::edit($params, $order_data);
$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);
Log::getInstance("queue-AssignDoctor")->info("已退款");
Db::commit();
try {
// 患者-分配医生失败-订阅
$MessagePush = new MessagePush($order_inquiry['user_id'],$order_inquiry['inquiry_no']);
$MessagePush->assignDoctorFail();
}catch (\Exception $e){
Log::getInstance("queue-AssignDoctor")->error($e->getMessage());
}
return Result::ACK;
}
// 检测执行次数
$res = $this->checkHandleNumber($data['order_inquiry_id']);
if (!$res) {
// 超出执行次数后,不再进行分配,按照结束分配时间,重新加入队列。
Log::getInstance("queue-AssignDoctor")->info("超出最大执行次数或检测错误");
Log::getInstance("queue-AssignDoctor")->info("重新加入延迟队列");
$queue_data = array();
$queue_data['order_inquiry_id'] = $data['order_inquiry_id'];
// 5分钟-支付时间-1s1000支付 此时1004 5-1004-1000
$time = 1000 * (300- (time() - $pay_time) - 1);
$message = new AssignDoctorDelayDirectProducer($queue_data);
$message->setDelayMs($time);
$producer = $this->container->get(Producer::class);
$res = $producer->produce($message);
if (!$res) {
Db::rollBack();
Log::getInstance("queue-AssignDoctor")->error("重新加入分配医生队列失败,重回队列");
return Result::REQUEUE;
}
Db::commit();
Log::getInstance("queue-AssignDoctor")->info("结束");
return Result::ACK;
}
Log::getInstance("queue-AssignDoctor")->info("分配医生");
$UserDoctorService = new UserDoctorService();
$doctor_id = $UserDoctorService->getInquiryAssignDoctor($order_inquiry['inquiry_type'],$order_inquiry['patient_id'],$is_system_time_pass);
if (empty($doctor_id)){
Log::getInstance("queue-AssignDoctor")->info("无合适医生");
Db::rollBack();
Log::getInstance("queue-AssignDoctor")->info("重新加入延迟队列");
$queue_data = array();
$queue_data['order_inquiry_id'] = $data['order_inquiry_id'];
$message = new AssignDoctorDelayDirectProducer($queue_data);
$message->setDelayMs(1000 * 60);
$producer = $this->container->get(Producer::class);
$res = $producer->produce($message);
if (!$res) {
Db::rollBack();
Log::getInstance("queue-AssignDoctor")->error("重新加入分配医生队列失败,重回队列");
return Result::REQUEUE;
}
Log::getInstance("queue-AssignDoctor")->info("重回队列");
return Result::ACK;
}
// 更改数据库
$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'];
$data['order_no'] = $order_inquiry['inquiry_no'];
$message = new CancelUnInquiryOrdersDelayDirectProducer($data);
// 快速/购药-5分钟
$message->setDelayMs(1000 * 60 * 10);
$producer = $this->container->get(Producer::class);
$res = $producer->produce($message);
if (!$res) {
Db::rollBack();
Log::getInstance("queue-AssignDoctor")->error("加入未接诊取消订单延迟队列失败");
return Result::REQUEUE;
}
Db::commit();
Log::getInstance("queue-AssignDoctor")->info("成功");
} catch (\Throwable $e) {
Db::rollBack();
Log::getInstance("queue-AssignDoctor")->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("queue-AssignDoctor")->error("医生数据错误");
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['inquiry_no']);
$MessagePush->doctorHaveNewInquiry();
// 加入xx时间未接诊通知队列
$data = array();
$data['order_inquiry_id'] = $order_inquiry['order_inquiry_id'];
$time = 1000 * 60 * 3;
$message = new DoctorNotYetInquiryDelayDirectProducer($data);
$message->setDelayMs($time);
$producer = $this->container->get(Producer::class);
$producer->produce($message);
}catch (\Throwable $e){
Log::getInstance("queue-AssignDoctor")->error($e->getMessage());
return Result::ACK;
}
return Result::ACK;
}
/**
* 检测订单状态
* @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;
}
/**
* 检测执行次数
* @param string $order_inquiry_id
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
protected function checkHandleNumber(string $order_inquiry_id): bool
{
try {
$redis = $this->container->get(Redis::class);
$redis_key = "assign_doctor_number_" . $order_inquiry_id;
$redis_value = $redis->get($redis_key);
if (empty($redis_value)) {
$redis->set($redis_key, 1, 60 * 60 * 24 * 5);
return true;
}
// 执行次数过多
if ($redis_value > 4) {
// 加入短信队列,通知管理员
return false;
}
$redis->incr($redis_key);
} catch (\Exception $e) {
return false;
}
return true;
}
}