dataLists(new PrescriptionOrderLists()); } /** * 处方业务订单导出(与 lists 相同筛选条件,Excel;参数 export=1 预估 export=2 下载) */ public function export() { return $this->dataLists(new PrescriptionOrderLists()); } /** * 指定诊单下可关联的支付单(待支付/已支付,创建/编辑业务订单时多选关联) */ public function paidPayOrders() { $params = (new PrescriptionOrderValidate())->get()->goCheck('paidPayOrders'); $exceptPo = (int) $this->request->get('prescription_order_id', 0); $lists = OrderLogic::listPaidOrdersForDiagnosis( (int) $params['diagnosis_id'], $this->adminId, $this->adminInfo, $exceptPo > 0 ? $exceptPo : null ); $min = PrescriptionOrderLogic::depositMinAmount(); // if ($min > 0) { // $lists = array_values(array_filter( // $lists, // static fn(array $r): bool => round((float) ($r['amount'] ?? 0), 2) >= $min // )); // } return $this->success('', [ 'lists' => $lists, 'deposit_min_amount' => $min, ]); } public function create() { $params = (new PrescriptionOrderValidate())->post()->goCheck('create'); $result = PrescriptionOrderLogic::create($params, $this->adminId, $this->adminInfo); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('创建成功', $result); } public function detail() { $params = (new PrescriptionOrderValidate())->get()->goCheck('detail'); $detail = PrescriptionOrderLogic::detail((int) $params['id'], $this->adminId, $this->adminInfo); if ($detail === null) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->data($detail); } /** * 快递轨迹查询(对接快递100;未配置时仍可跳转顺丰/京东官网) */ public function logisticsTrace() { $params = (new PrescriptionOrderValidate())->get()->goCheck('logisticsTrace'); $expressOverride = trim((string) $this->request->get('express_company', '')); $phoneTail = trim((string) ($params['phone_tail'] ?? '')); $data = PrescriptionOrderLogic::logisticsTrace( (int) $params['id'], $expressOverride, $this->adminId, $this->adminInfo, $phoneTail ); if ($data === null) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('', $data); } /** * 直接调用京东官方物流接口刷新轨迹并落库(绕过快递100缓存) */ public function logisticsJdUpdate() { $params = (new PrescriptionOrderValidate())->post()->goCheck('logisticsJdUpdate'); $data = PrescriptionOrderLogic::logisticsJdUpdate( (int) $params['id'], $this->adminId, $this->adminInfo ); if ($data === null) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success((string) ($data['message'] ?? '京东物流轨迹已更新'), $data); } public function edit() { $params = (new PrescriptionOrderValidate())->post()->goCheck('edit'); $result = PrescriptionOrderLogic::edit($params, $this->adminId, $this->adminInfo); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('保存成功', $result); } public function updateAmount() { $params = (new PrescriptionOrderValidate())->post()->goCheck('updateAmount'); $result = PrescriptionOrderLogic::updateAmount($params, $this->adminId, $this->adminInfo); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('修改成功'); } /** * 设置发货类型(甘草 / 洛阳) */ public function setShipMode() { $params = (new PrescriptionOrderValidate())->post()->goCheck('setShipMode'); $result = PrescriptionOrderLogic::setShipMode( (int) $params['id'], (string) ($params['ship_mode'] ?? 'gancao'), $this->adminId, $this->adminInfo ); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('已保存', $result); } /** * 修改关联处方的患者姓名与手机号(订单详情场景) */ public function patchPrescriptionPatient() { $params = (new PrescriptionOrderValidate())->post()->goCheck('patchPrescriptionPatient'); $ok = PrescriptionOrderLogic::patchPrescriptionPatient( (int) $params['id'], (string) $params['patient_name'], (string) $params['phone'], $this->adminId, $this->adminInfo ); if (!$ok) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('保存成功'); } public function auditPrescription() { $params = (new PrescriptionOrderValidate())->post()->goCheck('auditPrescription'); $result = PrescriptionOrderLogic::auditPrescription( (int) $params['id'], (string) $params['action'], (string) ($params['remark'] ?? ''), $this->adminId, $this->adminInfo ); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('操作成功', $result); } /** * 撤回处方审核 */ public function revokeRxAudit() { $params = (new PrescriptionOrderValidate())->post()->goCheck('detail'); $result = PrescriptionOrderLogic::revokeRxAudit( (int) $params['id'], $this->adminId, $this->adminInfo ); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('处方审核已撤回', $result); } public function auditPayment() { $params = (new PrescriptionOrderValidate())->post()->goCheck('auditPayment'); $result = PrescriptionOrderLogic::auditPaymentSlip( (int) $params['id'], (string) $params['action'], (string) ($params['remark'] ?? ''), $this->adminId, $this->adminInfo ); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('操作成功', $result); } /** * 撤回支付单审核 */ public function revokePayAudit() { $params = (new PrescriptionOrderValidate())->post()->goCheck('detail'); $result = PrescriptionOrderLogic::revokePayAudit( (int) $params['id'], $this->adminId, $this->adminInfo ); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('支付单审核已撤回', $result); } /** * 确认发货:将履约状态推进到 5(已发货),同时更新快递信息 */ public function ship() { $params = (new PrescriptionOrderValidate())->post()->goCheck('ship'); $result = PrescriptionOrderLogic::ship( (int) $params['id'], (string) ($params['express_company'] ?? 'auto'), (string) ($params['tracking_number'] ?? ''), (string) ($params['ship_mode'] ?? 'gancao'), $this->adminId, $this->adminInfo ); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('发货成功', $result); } /** * 医助/创建人撤回:仅「待双审通过」可撤(未通过或双审均驳回等仍为该状态) */ public function withdraw() { $params = (new PrescriptionOrderValidate())->post()->goCheck('withdraw'); $result = PrescriptionOrderLogic::withdraw((int) $params['id'], $this->adminId, $this->adminInfo); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('已撤回', $result); } /** * @notes 批量将处方业务订单改派给其他医助(写入 creator_id 并逐单记操作日志) */ public function batchAssignAssistant() { if (!PrescriptionOrderLogic::canSeeAllPrescriptionOrders($this->adminInfo)) { return $this->fail('无权限批量改派订单'); } $params = $this->request->post(); $rawIds = $params['order_ids'] ?? []; if (!\is_array($rawIds) || $rawIds === []) { return $this->fail('请选择订单'); } $assistantId = (int) ($params['assistant_id'] ?? 0); $result = PrescriptionOrderLogic::batchAssignAssistant($rawIds, $assistantId, $this->adminId, $this->adminInfo); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } $msg = '已改派 ' . (int) $result['success'] . ' 单'; if (!empty($result['errors'])) { $msg .= ';' . implode(';', $result['errors']); } return $this->success($msg, $result); } /** * 获取业务订单操作日志 */ public function logs() { $params = (new PrescriptionOrderValidate())->get()->goCheck('logs'); $result = PrescriptionOrderLogic::getLogs((int) $params['id'], $this->adminId, $this->adminInfo); // 遇到没有权限或者订单不存在,逻辑里设置了 self::$error if ($result === [] && PrescriptionOrderLogic::getError() !== '') { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('', $result); } /** * 手工新增操作日志(可选同步调整处方/支付单审核状态) */ public function addLog() { $params = (new PrescriptionOrderValidate())->post()->goCheck('addLog'); $result = PrescriptionOrderLogic::addLog($params, $this->adminId, $this->adminInfo); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('日志已添加', $result); } /** * 为「已发货」订单新增一条关联支付单,并重置支付单审核状态为待审核 */ public function addPayOrder() { $params = (new PrescriptionOrderValidate())->post()->goCheck('addPayOrder'); $result = PrescriptionOrderLogic::addPayOrder($params, $this->adminId, $this->adminInfo); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('新增支付单成功', $result); } /** * 为「已发货」订单关联已有支付单,并重置支付单审核状态为待审核 */ public function linkPayOrder() { $params = (new PrescriptionOrderValidate())->post()->goCheck('linkPayOrder'); $result = PrescriptionOrderLogic::linkPayOrder($params, $this->adminId, $this->adminInfo); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('关联支付单成功', $result); } /** * 已发货/已签收:仅提交完单申请(不新增/关联支付单),并重置支付审核为待审核 */ public function requestCompletion() { $params = (new PrescriptionOrderValidate())->post()->goCheck('requestCompletion'); $result = PrescriptionOrderLogic::requestCompletion($params, $this->adminId, $this->adminInfo); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('完单申请已提交', $result); } /** * 将「已发货」且支付审核已通过的订单标记为「已完成」 */ public function complete() { $params = (new PrescriptionOrderValidate())->post()->goCheck('complete'); $result = PrescriptionOrderLogic::complete( (int) $params['id'], $this->adminId, $this->adminInfo, (int) $params['fulfillment_status'] ); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('操作成功', $result); } /** * 业务订单退款(须填写原因;关联收款单标记已退款) */ public function refund() { $params = (new PrescriptionOrderValidate())->post()->goCheck('refund'); $rawRefundAmount = $params['refund_amount'] ?? null; $refundAmount = ($rawRefundAmount === null || $rawRefundAmount === '') ? null : round((float) $rawRefundAmount, 2); $result = PrescriptionOrderLogic::refund( (int) $params['id'], (string) ($params['reason'] ?? ''), $this->adminId, $this->adminInfo, $refundAmount ); if ($result === false) { return $this->fail(PrescriptionOrderLogic::getError()); } return $this->success('退款成功', $result); } /** * 甘草药管家:处方下单(CTM_PREVIEW → CTM_SUBMIT_RECIPEL) * * @see https://apidoc.igancao.com/service-doc/scm-outer-recipel.html */ public function submitGancaoRecipel() { try { $params = (new PrescriptionOrderValidate())->post()->goCheck('submitGancaoRecipel'); $result = PrescriptionOrderLogic::submitGancaoRecipel((int) $params['id'], $this->adminId, $this->adminInfo); if ($result === false) { $error = PrescriptionOrderLogic::getError(); \think\facade\Log::error('submitGancaoRecipel failed', ['error' => $error, 'params' => $params]); return $this->fail($error); } // 确保返回的数据是可序列化的 if (!is_array($result)) { \think\facade\Log::error('submitGancaoRecipel result is not array', ['result' => $result]); return $this->fail('返回数据格式错误'); } return $this->success('甘草药方上传成功', $result); } catch (\Throwable $e) { \think\facade\Log::error('submitGancaoRecipel exception', [ 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString() ]); return $this->fail('系统错误:' . $e->getMessage()); } } /** * 甘草药管家:预下单测试(仅 CTM_PREVIEW,不提交订单) * 用于在编辑订单时测试价格和配置 */ public function previewGancaoRecipel() { try { $params = (new PrescriptionOrderValidate())->post()->goCheck('previewGancaoRecipel'); $result = PrescriptionOrderLogic::previewGancaoRecipel((int) $params['id'], $this->adminId, $this->adminInfo, $params); if ($result === false) { $error = PrescriptionOrderLogic::getError(); \think\facade\Log::error('previewGancaoRecipel failed', ['error' => $error, 'params' => $params]); return $this->fail($error); } return $this->success('预下单成功', $result); } catch (\Throwable $e) { \think\facade\Log::error('previewGancaoRecipel exception', [ 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); return $this->fail('系统错误:' . $e->getMessage()); } } }