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