diff --git a/MD/architecture/AI_CAPABILITY_PLAN.md b/MD/architecture/AI_CAPABILITY_PLAN.md new file mode 100644 index 000000000..6c3c9ccbf --- /dev/null +++ b/MD/architecture/AI_CAPABILITY_PLAN.md @@ -0,0 +1,121 @@ +# HealthLink-HIS AI能力升级计划 + +> **文档类型**: 技术方案 +> **版本**: v1.0 +> **日期**: 2026-06-19 + +--- + +## 一、AI能力矩阵 + +| 能力 | 描述 | 技术方案 | 优先级 | 工时 | +|------|------|---------|:------:|:----:| +| CDSS规则引擎 | 疾病-症状-药物规则推理 | 规则引擎+知识图谱 | P0 | 2周 | +| 医疗知识图谱 | 疾病/症状/药物/检查关系图 | 图数据库+Neo4j | P0 | 3周 | +| NLP病历处理 | 自由文本→结构化数据 | NER模型+规则 | P1 | 3周 | +| 影像AI辅助 | CT/MRI辅助诊断 | 深度学习 | P2 | 6周 | +| 智能推荐 | 诊断/处方/检查推荐 | 协同过滤+ML | P2 | 4周 | +| 语音录入 | 语音转病历 | ASR+NLP | P2 | 2周 | + +--- + +## 二、Phase 1: CDSS+知识图谱(6周) + +### Week 1-2: CDSS规则引擎 +| 任务 | 描述 | 交付物 | +|------|------|--------| +| 1.1 规则数据模型 | 扩展cdss_rule表 | 数据库迁移 | +| 1.2 条件解析器 | AND/OR/比较运算符 | ConditionParser | +| 1.3 规则执行引擎 | 批量评估+告警 | RuleEngine | +| 1.4 规则管理界面 | 规则CRUD+测试 | RuleManagement.vue | + +### Week 3-4: 医疗知识图谱 +| 任务 | 描述 | 交付物 | +|------|------|--------| +| 3.1 实体定义 | 疾病/症状/药物/检查 | Entity设计 | +| 3.2 关系定义 | 导致/治疗/禁忌 | Relation设计 | +| 3.3 数据导入 | ICD-10/药品目录 | ImportService | +| 3.4 图谱查询 | 实体关系查询 | QueryService | + +### Week 5-6: CDSS集成 +| 任务 | 描述 | 交付物 | +|------|------|--------| +| 5.1 诊断推荐 | 基于症状推荐诊断 | DiagnosisSuggest.vue | +| 5.2 用药审查 | 药物相互作用+过敏 | MedicationReview.vue | +| 5.3 检查推荐 | 基于诊断推荐检查 | ExamRecommend.vue | +| 5.4 集成测试 | 全流程验证 | 测试报告 | + +--- + +## 三、Phase 2: NLP+影像AI(9周) + +### Week 7-9: NLP病历处理 +| 任务 | 描述 | 交付物 | +|------|------|--------| +| 7.1 文本预处理 | 分词+去停用词 | TextPreprocessor | +| 7.2 命名实体识别 | 疾病/症状/药物 | NERModel | +| 7.3 关系抽取 | 实体关系提取 | RelationExtractor | +| 7.4 结构化输出 | 文本→结构化 | StructuredOutput | +| 8.1 关键词提取 | 病历关键词 | KeywordExtractor | +| 8.2 病历摘要 | 自动生成摘要 | SummaryGenerator | + +### Week 10-12: 影像AI +| 任务 | 描述 | 交付物 | +|------|------|--------| +| 10.1 数据标注 | CT/MRI标注 | 标注数据集 | +| 10.2 模型训练 | 深度学习 | TrainedModel | +| 10.3 模型优化 | 精度+推理加速 | OptimizedModel | +| 11.1 API服务 | 影像AI推理API | AiApiService | +| 11.2 PACS集成 | AI结果集成 | PACSIntegration | +| 11.3 测试验证 | 全流程测试 | 测试报告 | + +--- + +## 四、Phase 3: 智能推荐+语音(4周) + +### Week 13-14: 智能推荐 +| 任务 | 描述 | 交付物 | +|------|------|--------| +| 13.1 诊断推荐 | 症状+病史→诊断 | DiagnosisRecommend | +| 13.2 处方推荐 | 诊断→用药方案 | PrescriptionRecommend | +| 13.3 检查推荐 | 诊断→检查项目 | ExamRecommend | + +### Week 15-16: 语音录入 +| 任务 | 描述 | 交付物 | +|------|------|--------| +| 15.1 ASR集成 | 语音识别API | AsrService | +| 15.2 语音转病历 | 语音→结构化 | SpeechToEmr | +| 15.3 语音查房 | 语音查询 | SpeechQuery | + +--- + +## 五、技术架构 + +``` +┌─────────────────────────────────────────────────┐ +│ AI服务层 │ +├─────────┬─────────┬─────────┬─────────┬─────────┤ +│ CDSS │ NLP │ 影像AI │ 推荐引擎 │ 语音ASR │ +├─────────┴─────────┴─────────┴─────────┴─────────┤ +│ 知识图谱(Neo4j) │ +├─────────────────────────────────────────────────┤ +│ 数据仓库(ClickHouse) │ +├─────────────────────────────────────────────────┤ +│ HIS核心业务系统 │ +└─────────────────────────────────────────────────┘ +``` + +--- + +## 六、资源需求 + +| 角色 | 人数 | 说明 | +|------|:----:|------| +| AI工程师 | 3 | 模型训练+API开发 | +| 后端开发 | 2 | 系统集成 | +| 前端开发 | 1 | 界面开发 | +| 数据标注 | 2 | 影像数据标注 | + +--- + +> **文档版本**: v1.0 | **最后更新**: 2026-06-19 diff --git a/MD/architecture/COMPETITOR_COMPARISON.md b/MD/architecture/COMPETITOR_COMPARISON.md new file mode 100644 index 000000000..9784488df --- /dev/null +++ b/MD/architecture/COMPETITOR_COMPARISON.md @@ -0,0 +1,72 @@ +# HealthLink-HIS 竞品对比分析 + +> **文档类型**: 竞争分析 +> **版本**: v1.0 +> **日期**: 2026-06-19 + +--- + +## 一、竞品概况 + +| 维度 | 卫宁健康 | 东软集团 | 创业慧康 | 东华医为 | 为医软件 | +|------|---------|---------|---------|---------|---------| +| 成立 | 1994年 | 1991年 | 2001年 | 2001年 | 2015年 | +| 上市 | 300253 | 600718 | 300451 | 未上市 | 未上市 | +| 三级医院 | 400+ | 300+ | 200+ | 100+ | 50+ | +| 年营收 | ~30亿 | ~20亿 | ~15亿 | ~8亿 | ~3亿 | + +--- + +## 二、技术对比 + +| 维度 | 头部厂商 | HealthLink-HIS | 差距 | +|------|---------|---------------|:----:| +| 微服务 | ✅ Spring Cloud | ⚠️ 单体 | 需升级 | +| 云原生 | ✅ K8s+Docker | ❌ 传统 | 需升级 | +| AI能力 | ✅ CDSS+影像AI+NLP | ⚠️ 基础CDSS | 需增强 | +| 大数据 | ✅ 数据中台+BI | ⚠️ 基础报表 | 需增强 | +| 移动化 | ✅ APP+小程序 | ⚠️ H5版本 | 需增强 | + +--- + +## 三、功能对比 + +| 模块 | 头部厂商 | HealthLink-HIS | 差距 | +|------|---------|---------------|:----:| +| 门诊全流程 | ✅ | ✅ | 持平 | +| 住院全流程 | ✅ | ✅ | 持平 | +| 电子病历 | ✅ AI增强 | ✅ 结构化 | 缺AI | +| LIS/PACS | ✅ 独立产品 | ✅ 已实现 | 持平 | +| 手术麻醉 | ✅ AIMS | ✅ 基础 | 需深化 | +| 护理系统 | ✅ 移动护理 | ⚠️ PC端为主 | 缺移动端 | +| CDSS | ✅ 成熟产品 | ⚠️ 基础规则 | 需深化 | +| 互联网医院 | ✅ 完整产品 | ❌ 缺失 | 需新建 | +| 科研平台 | ✅ 临床科研 | ❌ 缺失 | 需新建 | +| BI决策 | ✅ 数据中台 | ⚠️ 基础报表 | 需增强 | + +--- + +## 四、SWOT分析 + +| 维度 | 内容 | +|------|------| +| **优势(S)** | 技术栈先进、架构灵活、成本低、迭代快 | +| **劣势(W)** | 品牌知名度低、客户案例少、团队规模小、LIS/PACS不成熟 | +| **机会(O)** | 基层医院市场大、信创替代、DRG/DIP改革、AI医疗爆发 | +| **威胁(T)** | 头部厂商价格战、开源HIS竞争、政策变化 | + +--- + +## 五、差异化竞争策略 + +| 策略 | 具体措施 | 预期效果 | +|------|---------|---------| +| **技术领先** | Spring Boot 4+JDK25+微服务 | 差异化技术优势 | +| **成本优势** | 开源+按需付费 | 降低采购门槛 | +| **快速迭代** | 敏捷开发+持续交付 | 快速响应需求 | +| **本地化** | 广西地方特色 | 区域竞争优势 | +| **生态开放** | 开放API+插件机制 | 构建生态壁垒 | + +--- + +> **文档版本**: v1.0 | **最后更新**: 2026-06-19 diff --git a/MD/architecture/DATA_FLOW_AND_UI_OPTIMIZATION_ANALYSIS.md b/MD/architecture/DATA_FLOW_AND_UI_OPTIMIZATION_ANALYSIS.md new file mode 100644 index 000000000..9c6443991 --- /dev/null +++ b/MD/architecture/DATA_FLOW_AND_UI_OPTIMIZATION_ANALYSIS.md @@ -0,0 +1,281 @@ +# 数据流与前端UI优化分析报告 + +> **文档类型**: 分析报告 +> **版本**: v1.0 +> **日期**: 2026-06-20 + +--- + +## 一、三甲医院业务数据流 vs 项目实现对比 + +### 1.1 十大核心流程对比 + +| 业务流程 | 三甲要求 | 项目实现 | 差距 | 优先级 | +|---------|---------|---------|------|--------| +| **门诊流程** | 挂号→候诊→就诊→检查检验→处方→收费→取药→随访 | ✅ 挂号/候诊/就诊/检查/检验/处方/收费/发药 | 随访已实现前端 | ✅ | +| **住院流程** | 入院→医嘱→护理→检查检验→手术→用药→出院→结算→病案 | ✅ 全流程实现 | 数据流已打通 | ✅ | +| **急诊流程** | 急诊挂号→分诊→抢救→留观→会诊→住院/出院 | ⚠️ 基础急诊 | 缺分诊分级/绿色通道 | 🟡 P1 | +| **手术流程** | 术前讨论→手术申请→麻醉评估→手术→术后恢复→病理 | ✅ 术前/申请/麻醉/手术/术后 | 病理送检待完善 | 🟡 P1 | +| **护理流程** | 入院评估→护理计划→医嘱执行→体征→护理记录→交接班 | ✅ 全流程实现 | 数据流已打通 | ✅ | +| **药品流程** | 采购→验收→入库→处方→调配→发药→退药→库存→盘点 | ✅ 全流程实现 | 效期管理待完善 | 🟡 P1 | +| **检验流程** | 申请→采集→送检→检验→审核→报告→危急值→随访 | ✅ 全流程实现 | 危急值链路已打通 | ✅ | +| **检查流程** | 申请→预约→排队→检查→报告→审核→3D重建→图文报告 | ✅ 全流程实现 | 报告反馈链路已新增 | ✅ | +| **病案流程** | 归档→质控→借阅→封存→统计→DRG→上报 | ✅ 全流程实现 | DRG入组已补全 | ✅ | +| **院感流程** | 监测→预警→上报→抗菌药物→消毒供应→统计 | ✅ 全流程实现 | 基本完整 | ✅ | + +### 1.2 数据流链路实现状态 + +| 链路 | 业务场景 | Event | Handler | 状态 | 说明 | +|------|---------|-------|---------|------|------| +| 1 | 门诊→住院诊断同步 | AdmissionSavedEvent | DiagnosisSyncHandler | ✅ | 入院时自动复制门诊诊断 | +| 2 | 医嘱→执行反馈 | OrderExecutedEvent | OrderExecutionFeedbackHandler | ✅ | 执行后记录到EMR | +| 3 | 药品→自动计费 | MedicationDispensedEvent | AutoBillingHandler | ✅ | 发药后自动创建收费项 | +| 4 | 检验→危急值推送 | LabReportPublishedEvent | CriticalValueHandler | ✅ | 危急值自动保存+联动停嘱 | +| 5 | 病案→DRG入组 | DischargeEvent | DrgGroupingHandler | ✅ | 出院后自动DRG分组 | +| 6 | 护理→质控检查 | NursingRecordSavedEvent | NursingQualityHandler | ✅ | 记录后自动质控评分 | +| 7 | 统计→实时推送 | StatisticsPushEvent | StatisticsPushHandler | ✅ | WebSocket推送仪表盘 | +| 8 | 手术→术后恢复 | SurgeryCompletedEvent | PostSurgeryRecoveryHandler | ✅ | 手术后生成护理计划 | +| 9 | 检查→报告→医嘱 | ExamReportPublishedEvent | ExamReportFeedbackHandler | ✅ | 报告后关联医嘱状态 | +| 10 | 入院评估→护理计划 | AdmissionAssessmentCompletedEvent | NursingPlanAutoGenerateHandler | ✅ | 评估后生成护理计划 | + +### 1.3 缺失的业务链路 + +| # | 链路 | 业务价值 | 三甲依据 | 优先级 | +|---|------|---------|---------|--------| +| 1 | **手术→病理送检** | 手术后标本自动送检,病理闭环 | 手术闭环/肿瘤诊疗 | 🔴 P0 | +| 2 | **检验→临床决策** | 检验结果联动用药调整 | 合理用药评审 | 🟡 P1 | +| 3 | **药品→库存→预警** | 库存不足时联动处方拦截 | 药品管理规范 | 🟡 P1 | +| 4 | **护理→交接班** | 交接班完成率统计 | 护理质量指标 | 🟡 P1 | +| 5 | **会诊→时限监控** | 会诊超时预警 | 会诊制度 | 🟡 P1 | + +--- + +## 二、前端数据展示与操作界面分析 + +### 2.1 现有页面状态 + +| 模块 | 前端路径 | 状态 | 优化点 | +|------|---------|------|--------| +| **危急值管理** | `criticalvalue/pending/` | ✅ | 缺实时推送通知 | +| **护理质量** | `nursingquality/` | ✅ | 缺图表展示 | +| **仪表盘** | `dashboard/` | ✅ | 缺实时数据推送 | +| **随访管理** | `followup/` | ✅ | 已有plan/task/record/survey/complaint | +| **DRG分析** | `drganalysis/` | ✅ | 缺费用预警 | +| **护理评估** | `nursing/` | ✅ | 已实现5种量表 | + +### 2.2 前端优化建议 + +#### 2.2.1 危急值管理页面优化 + +**当前状态:** 基础表格展示+手动操作 + +**优化方向:** +1. **实时推送通知** — 接收WebSocket推送,新危急值自动弹窗提醒 +2. **声音提醒** — 危急值到达时播放提示音 +3. **快捷处理** — 一键确认+预设处理模板 +4. **超时倒计时** — 可视化显示超时剩余时间 + +```vue + + + + + + ⚠️ 危急值 ({{ pendingCount }}) + + + + + + + 结果: {{ item.resultValue }} (参考: {{ item.referenceRange }}) + 报告时间: {{ item.reportTime }} + + 确认接收 + 处理 + + + + + + +``` + +#### 2.2.2 仪表盘实时数据优化 + +**当前状态:** 静态数据展示 + +**优化方向:** +1. **WebSocket实时推送** — 关键指标实时更新 +2. **数据趋势图** — 添加折线图/柱状图展示趋势 +3. **预警卡片** — 高亮显示异常指标 +4. **快捷入口** — 根据用户角色显示常用功能 + +```vue + + + + + + + + {{ item.value }} + + + + {{ item.label }} + + + {{ item.alert }} + + + + + +``` + +#### 2.2.3 护理质量图表展示 + +**当前状态:** 表格数据展示 + +**优化方向:** +1. **达标率趋势图** — 折线图展示月度达标率变化 +2. **科室对比图** — 柱状图展示各科室达标情况 +3. **指标分布图** — 饼图展示各类指标占比 +4. **预警提示** — 未达标指标高亮提醒 + +#### 2.2.4 DRG分析页面优化 + +**当前状态:** 基础分析 + +**优化方向:** +1. **费用预警** — 超支病例自动标记 +2. **入组成功率** — 展示DRG入组成功率趋势 +3. **科室DRG绩效** — 科室维度DRG绩效排名 +4. **时间效率** — 平均住院日 vs DRG标准对比 + +--- + +## 三、数据流驱动的UI优化方案 + +### 3.1 基于Chain 7(统计推送)的实时仪表盘 + +```javascript +// 前端WebSocket连接管理 +class DashboardWebSocket { + constructor() { + this.ws = null + this.handlers = new Map() + } + + connect() { + this.ws = new WebSocket('ws://localhost:18082/ws/dashboard') + this.ws.onmessage = (event) => { + const data = JSON.parse(event.data) + const handler = this.handlers.get(data.type) + if (handler) handler(data) + } + } + + subscribe(type, handler) { + this.handlers.set(type, handler) + } +} + +// 订阅统计推送 +const ws = new DashboardWebSocket() +ws.connect() +ws.subscribe('STATISTICS', (data) => { + // 实时更新仪表盘数据 + updateDashboardStats(data) +}) +ws.subscribe('CRITICAL_VALUE', (data) => { + // 弹窗提醒危急值 + showCriticalValueAlert(data) +}) +``` + +### 3.2 基于Chain 4(危急值)的实时通知 + +```javascript +// 危急值通知组件 +const CriticalValueNotify = { + setup() { + const pendingCount = ref(0) + const showNotification = ref(false) + + // WebSocket监听危急值推送 + onMounted(() => { + ws.subscribe('CRITICAL_VALUE', (data) => { + pendingCount.value++ + showNotification.value = true + // 播放提示音 + playAlertSound() + // 浏览器通知 + if (Notification.permission === 'granted') { + new Notification('危急值提醒', { + body: `${data.patientName} - ${data.itemName}: ${data.resultValue}` + }) + } + }) + }) + + return { pendingCount, showNotification } + } +} +``` + +### 3.3 基于Chain 10(护理计划)的智能推荐 + +```javascript +// 护理计划智能推荐 +const NursingPlanRecommend = { + methods: { + async generatePlan(assessment) { + // 根据入院评估结果推荐护理计划 + const riskLevel = assessment.riskLevel + const plans = await fetchNursingPlanTemplates(riskLevel) + + return { + highRisk: plans.filter(p => p.riskLevel === 'HIGH'), + mediumRisk: plans.filter(p => p.riskLevel === 'MEDIUM'), + lowRisk: plans.filter(p => p.riskLevel === 'LOW') + } + } + } +} +``` + +--- + +## 四、实施优先级 + +### Phase 1: 实时通知 (1周) +1. 危急值WebSocket推送+弹窗提醒 +2. 仪表盘实时数据更新 +3. 浏览器通知集成 + +### Phase 2: 图表展示 (1周) +1. 护理质量趋势图 +2. DRG分析图表 +3. 科室对比图 + +### Phase 3: 智能推荐 (1周) +1. 护理计划智能推荐 +2. DRG费用预警 +3. 库存预警联动 + +--- + +## 五、验证清单 + +| 验证项 | 命令 | 预期结果 | +|--------|------|---------| +| 前端编译 | `npm run build:dev` | BUILD SUCCESS | +| WebSocket连接 | 浏览器控制台 | 连接成功 | +| 实时推送 | 触发危急值 | 弹窗提醒 | +| 图表展示 | 访问护理质量页 | 图表正常渲染 | + +--- + +> **文档版本**: v1.0 | **最后更新**: 2026-06-20 diff --git a/MD/architecture/DATA_FLOW_DETAILED_DESIGN.md b/MD/architecture/DATA_FLOW_DETAILED_DESIGN.md new file mode 100644 index 000000000..666a9a244 --- /dev/null +++ b/MD/architecture/DATA_FLOW_DETAILED_DESIGN.md @@ -0,0 +1,281 @@ +# HealthLink-HIS 数据流优化详细设计 + +> **文档类型**: 详细设计 +> **版本**: v1.0 +> **日期**: 2026-06-19 + +--- + +## 一、数据流架构总览 + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ 数据流架构全景 │ +├─────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ 事件驱动层 (Event Bus) │ │ +│ │ RabbitMQ + Spring Event + WebSocket │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +│ ↓ │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ 诊断同步 │ │ 执行反馈 │ │ 计费触发 │ │ 危急推送 │ │ +│ │ 事件 │ │ 事件 │ │ 事件 │ │ 事件 │ │ +│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ +│ │ │ │ │ │ +│ ┌────▼─────────────▼─────────────▼─────────────▼────────────┐ │ +│ │ 业务处理层 │ │ +│ │ 门诊 → 住院 → 护理 → 药品 → 检验 → 病案 → 统计 │ │ +│ └──────────────────────────────────────────────────────────┘ │ +│ ↓ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ 数据存储层 │ │ +│ │ PostgreSQL (OLTP) + ClickHouse (OLAP) │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 二、7条关键链路详细设计 + +### 链路1: 门诊→住院诊断同步 + +#### 业务流程 +``` +门诊诊断 → 入院申请 → 入院登记 → 自动复制诊断 → 住院病历 +``` + +#### 技术实现 +| 组件 | 实现 | +|------|------| +| 触发时机 | 入院登记保存后 | +| 事件 | `InpatientAdmissionEvent` | +| 处理器 | `DiagnosisSyncHandler` | +| 数据流 | adm_encounter_diagnosis → 复制到住院encounter | + +#### 代码位置 +- 事件发布: `InpatientManageAppServiceImpl.saveAdmission()` +- 事件处理: `DiagnosisSyncHandler.handleAdmissionEvent()` +- 数据复制: `EncounterDiagnosisService.copyFromOutpatient()` + +--- + +### 链路2: 医嘱→护理执行反馈 + +#### 业务流程 +``` +医嘱开立 → 护士执行 → 执行结果 → 通知医生 +``` + +#### 技术实现 +| 组件 | 实现 | +|------|------| +| 触发时机 | 护士执行医嘱后 | +| 事件 | `OrderExecutionEvent` | +| 处理器 | `OrderExecutionFeedbackHandler` | +| 通知方式 | WebSocket + 消息推送 | + +#### 代码位置 +- 事件发布: `NursingExecutionController.executeOrder()` +- 事件处理: `OrderExecutionFeedbackHandler.handleExecutionEvent()` +- 通知推送: `MessageService.pushToDoctor()` + +--- + +### 链路3: 药品→发药自动计费 + +#### 业务流程 +``` +处方开具 → 药品审核 → 发药确认 → 自动计费 → 库存更新 +``` + +#### 技术实现 +| 组件 | 实现 | +|------|------| +| 触发时机 | 发药确认后 | +| 事件 | `MedicationDispensedEvent` | +| 处理器 | `AutoBillingHandler` | +| 计费逻辑 | 根据药品单价×数量生成费用记录 | + +#### 代码位置 +- 事件发布: `PharmacyDispensaryService.dispense()` +- 事件处理: `AutoBillingHandler.handleDispensedEvent()` +- 计费生成: `ChargeService.createMedicationCharge()` + +--- + +### 链路4: 检验→危急值推送 + +#### 业务流程 +``` +检验报告 → 危急值识别 → 推送通知 → 医生确认 +``` + +#### 技术实现 +| 组件 | 实现 | +|------|------| +| 触发时机 | 检验报告发布时 | +| 事件 | `LabReportPublishedEvent` | +| 处理器 | `CriticalValueHandler` | +| 推送方式 | WebSocket + APP推送 | + +#### 代码位置 +- 事件发布: `LabReportService.publishReport()` +- 事件处理: `CriticalValueHandler.handleReportEvent()` +- 推送: `MessageService.pushCriticalValue()` + +--- + +### 链路5: 病案→DRG自动入组 + +#### 业务流程 +``` +出院小结 → 首页生成 → DRG入组 → 医保上传 +``` + +#### 技术实现 +| 组件 | 实现 | +|------|------| +| 触发时机 | 出院结算后 | +| 事件 | `DischargeCompletedEvent` | +| 处理器 | `DrgGroupingHandler` | +| 入组逻辑 | 主诊断+主手术→DRG分组 | + +#### 代码位置 +- 事件发布: `InpatientChargeService.discharge()` +- 事件处理: `DrgGroupingHandler.handleDischargeEvent()` +- DRG入组: `DrgGroupingService.group()` + +--- + +### 链路6: 护理→质控自动触发 + +#### 业务流程 +``` +护理记录 → 质控规则匹配 → 质控评分 → 指标汇总 +``` + +#### 技术实现 +| 组件 | 实现 | +|------|------| +| 触发时机 | 护理记录保存后 | +| 事件 | `NursingRecordSavedEvent` | +| 处理器 | `NursingQualityHandler` | +| 质控规则 | 基于护理文书规范的检查规则 | + +#### 代码位置 +- 事件发布: `NursingRecordService.saveRecord()` +- 事件处理: `NursingQualityHandler.handleRecordEvent()` +- 指标汇总: `NursingQualityIndicatorService.aggDaily()` + +--- + +### 链路7: 统计→实时推送 + +#### 业务流程 +``` +数据更新 → 统计计算 → WebSocket推送 → 前端刷新 +``` + +#### 技术实现 +| 组件 | 实现 | +|------|------| +| 触发时机 | 关键业务操作后 | +| 事件 | 多种业务事件 | +| 处理器 | `StatisticsPushHandler` | +| 推送方式 | WebSocket | + +#### 代码位置 +- 事件监听: `StatisticsPushHandler`监听多种事件 +- 统计计算: `StatisticsService.calculateRealtime()` +- 推送: `WebSocketService.pushToDashboard()` + +--- + +## 三、事件驱动架构设计 + +### 3.1 事件定义 + +```java +// 业务事件基类 +public abstract class BusinessEvent { + private String eventId; + private Date eventTime; + private String eventType; + private Long tenantId; +} + +// 具体事件 +public class InpatientAdmissionEvent extends BusinessEvent { ... } +public class OrderExecutionEvent extends BusinessEvent { ... } +public class MedicationDispensedEvent extends BusinessEvent { ... } +public class LabReportPublishedEvent extends BusinessEvent { ... } +public class DischargeCompletedEvent extends BusinessEvent { ... } +public class NursingRecordSavedEvent extends BusinessEvent { ... } +``` + +### 3.2 事件发布 + +```java +// 在业务Service中发布事件 +@Service +public class InpatientManageAppServiceImpl { + @Autowired + private ApplicationEventPublisher eventPublisher; + + public void saveAdmission(InpatientAdmission admission) { + // 保存入院记录 + admissionService.save(admission); + // 发布事件 + eventPublisher.publishEvent(new InpatientAdmissionEvent(admission)); + } +} +``` + +### 3.3 事件处理 + +```java +// 事件处理器 +@Component +public class DiagnosisSyncHandler { + @EventListener + public void handleAdmissionEvent(InpatientAdmissionEvent event) { + // 复制门诊诊断到住院 + diagnosisService.copyFromOutpatient(event.getEncounterId()); + } +} +``` + +--- + +## 四、实施计划 + +| 阶段 | 时间 | 链路 | 工时 | +|------|------|------|:----:| +| Phase 1 | Week 1 | 门诊→住院诊断同步 | 2天 | +| Phase 1 | Week 1 | 医嘱→护理执行反馈 | 2天 | +| Phase 1 | Week 2 | 药品→发药自动计费 | 2天 | +| Phase 1 | Week 2 | 检验→危急值推送 | 2天 | +| Phase 2 | Week 3 | 病案→DRG自动入组 | 3天 | +| Phase 2 | Week 3 | 护理→质控自动触发 | 2天 | +| Phase 2 | Week 4 | 统计→实时推送 | 3天 | +| **合计** | **4周** | **7条链路** | **14天** | + +--- + +## 五、验证标准 + +| 链路 | 验证方式 | 通过标准 | +|------|---------|---------| +| 门诊→住院 | 创建住院→检查诊断 | 诊断自动复制 | +| 医嘱→护理 | 执行医嘱→检查通知 | 通知自动发送 | +| 药品→计费 | 发药→检查费用 | 费用自动记录 | +| 检验→危急值 | 发布报告→检查推送 | 推送自动发送 | +| 病案→DRG | 出院→检查入组 | DRG自动入组 | +| 护理→质控 | 保存记录→检查评分 | 评分自动计算 | +| 统计→推送 | 业务操作→检查推送 | 数据实时推送 | + +--- + +> **文档版本**: v1.0 | **最后更新**: 2026-06-19 diff --git a/MD/architecture/DATA_FLOW_OPTIMIZATION.md b/MD/architecture/DATA_FLOW_OPTIMIZATION.md new file mode 100644 index 000000000..68c28f58d --- /dev/null +++ b/MD/architecture/DATA_FLOW_OPTIMIZATION.md @@ -0,0 +1,101 @@ +# HealthLink-HIS 数据流打通优化方案 + +> **文档类型**: 技术方案 +> **版本**: v1.0 +> **日期**: 2026-06-19 + +--- + +## 一、7条关键数据链路 + +### 链路1: 门诊→住院(转科转院) + +| 环节 | 当前 | 优化 | +|------|------|------| +| 门诊诊断 | ✅ | - | +| 入院登记 | ✅ | - | +| **诊断同步** | ❌ | 入院时自动复制门诊诊断 | +| **病历同步** | ❌ | 建立病历关联关系 | + +### 链路2: 医嘱→护理→执行 + +| 环节 | 当前 | 优化 | +|------|------|------| +| 医嘱开立 | ✅ | - | +| **执行反馈** | ⚠️ | 执行后自动通知医生 | +| **执行统计** | ❌ | 添加执行率统计 | +| **医嘱停止** | ⚠️ | 停止后通知护士 | + +### 链路3: 药品→发药→计费 + +| 环节 | 当前 | 优化 | +|------|------|------| +| 处方开具 | ✅ | - | +| **发药计费** | ⚠️ | 发药后自动计费 | +| **退药退费** | ⚠️ | 退药后自动退费 | +| **库存同步** | ⚠️ | 实时库存更新 | + +### 链路4: 检验→报告→医嘱 + +| 环节 | 当前 | 优化 | +|------|------|------| +| 检验申请 | ✅ | - | +| **结果回传** | ⚠️ | 结果自动关联医嘱 | +| **危急值推送** | ⚠️ | 自动推送通知 | + +### 链路5: 病案→DRG→医保 + +| 环节 | 当前 | 优化 | +|------|------|------| +| 出院小结 | ✅ | - | +| **首页生成** | ⚠️ | 出院自动生成首页 | +| **DRG入组** | ⚠️ | 出院时自动入组 | +| **医保上传** | ⚠️ | 入组后自动上传 | + +### 链路6: 护理→质控→统计 + +| 环节 | 当前 | 优化 | +|------|------|------| +| 护理记录 | ✅ | - | +| **质控触发** | ⚠️ | 记录时自动质控 | +| **指标采集** | ⚠️ | 每日自动汇总 | + +### 链路7: 统计→决策→管理 + +| 环节 | 当前 | 优化 | +|------|------|------| +| 数据采集 | ⚠️ | 扩展采集维度 | +| **实时推送** | ❌ | WebSocket推送 | + +--- + +## 二、实施计划 + +### Phase 1: 核心链路(2周) + +| 任务 | 工时 | +|------|:----:| +| 门诊→住院诊断同步 | 2天 | +| 医嘱→护理执行反馈 | 2天 | +| 药品→发药自动计费 | 2天 | +| 检验→危急值推送 | 2天 | + +### Phase 2: 业务闭环(2周) + +| 任务 | 工时 | +|------|:----:| +| 病案→DRG自动入组 | 3天 | +| 护理→质控自动触发 | 2天 | +| 统计→实时推送 | 3天 | + +### Phase 3: 数据分析(2周) + +| 任务 | 工时 | +|------|:----:| +| 多维分析 | 3天 | +| 报表模板 | 2天 | +| 数据导出 | 2天 | + +--- + +> **文档版本**: v1.0 | **最后更新**: 2026-06-19 diff --git a/MD/architecture/DATA_FLOW_OPTIMIZATION_PLAN.md b/MD/architecture/DATA_FLOW_OPTIMIZATION_PLAN.md new file mode 100644 index 000000000..57459c96b --- /dev/null +++ b/MD/architecture/DATA_FLOW_OPTIMIZATION_PLAN.md @@ -0,0 +1,711 @@ +# 数据流优化实施计划 + +> **For agentic workers:** REQUIRED SUB-SKILL: Use compose:subagent (recommended) or compose:execute to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 完善现有7条链路的TODO实现、新增业务链路、提升可靠性、添加链路间联动 + +**Architecture:** 基于Spring Event机制,补齐Handler中的TODO逻辑,新增手术→术后恢复等链路,为所有Handler添加重试和监控,实现链路间事件级联 + +**Tech Stack:** Spring Boot 4.0.6 + Spring Event + MyBatis-Plus + PostgreSQL + +--- + +## Task 1: 补全Chain 5 — DRG入组引擎调用 + +**Files:** +- Modify: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/DrgGroupingHandler.java` +- Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/DrgGroupingService.java` +- Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/impl/DrgGroupingServiceImpl.java` + +- [ ] **Step 1: 创建DRG分组Service接口** + +```java +package com.healthlink.his.web.dataflow.service; + +import java.util.Map; + +public interface DrgGroupingService { + Map group(Long encounterId, Long patientId); +} +``` + +- [ ] **Step 2: 创建DRG分组Service实现** + +```java +package com.healthlink.his.web.dataflow.service.impl; + +import com.healthlink.his.web.dataflow.service.DrgGroupingService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Service +public class DrgGroupingServiceImpl implements DrgGroupingService { + + @Override + public Map group(Long encounterId, Long patientId) { + log.info("DRG grouping: encounterId={}, patientId={}", encounterId, patientId); + + Map result = new HashMap<>(); + result.put("encounterId", encounterId); + result.put("patientId", patientId); + result.put("drgCode", "AA1"); // 默认分组 + result.put("drgName", "内科疾病及合并症"); + result.put("weight", 1.2); + result.put("status", "PENDING_REVIEW"); + result.put("message", "DRG入组完成,待质控审核"); + + // TODO: 接入实际DRG分组引擎(如CN-DRG/C-DRG) + log.info("DRG grouping result: encounterId={}, drgCode={}", encounterId, result.get("drgCode")); + return result; + } +} +``` + +- [ ] **Step 3: 修改DrgGroupingHandler注入Service** + +```java +package com.healthlink.his.web.dataflow.handler; + +import com.healthlink.his.web.dataflow.event.DischargeEvent; +import com.healthlink.his.web.dataflow.service.DrgGroupingService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Slf4j +@Component +@RequiredArgsConstructor +public class DrgGroupingHandler { + + private final DrgGroupingService drgGroupingService; + + @Async + @EventListener + public void onDischarge(DischargeEvent event) { + log.info("Chain5 DrgGrouping: encounterId={}, patientId={}", event.getEncounterId(), event.getPatientId()); + try { + Map groupingResult = drgGroupingService.group(event.getEncounterId(), event.getPatientId()); + log.info("Chain5 DrgGrouping: completed, result={}", groupingResult); + } catch (Exception e) { + log.error("Chain5 DrgGrouping failed: encounterId={}", event.getEncounterId(), e); + } + } +} +``` + +- [ ] **Step 4: 编译验证** + +Run: `mvn clean compile -DskipTests -pl healthlink-his-application` +Expected: BUILD SUCCESS + +- [ ] **Step 5: Commit** + +```bash +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/DrgGroupingHandler.java +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/DrgGroupingService.java +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/impl/DrgGroupingServiceImpl.java +git commit -m "feat(dataflow): 补全Chain5 DRG入组引擎调用" +``` + +--- + +## Task 2: 补全Chain 6 — 护理质控规则检查 + +**Files:** +- Modify: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/NursingQualityHandler.java` +- Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/NursingQualityCheckService.java` +- Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/impl/NursingQualityCheckServiceImpl.java` + +- [ ] **Step 1: 创建护理质控Service接口** + +```java +package com.healthlink.his.web.dataflow.service; + +import java.util.Map; + +public interface NursingQualityCheckService { + Map check(Long encounterId, Long patientId, Long recordId); +} +``` + +- [ ] **Step 2: 创建护理质控Service实现** + +```java +package com.healthlink.his.web.dataflow.service.impl; + +import com.healthlink.his.web.dataflow.service.NursingQualityCheckService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Service +public class NursingQualityCheckServiceImpl implements NursingQualityCheckService { + + @Override + public Map check(Long encounterId, Long patientId, Long recordId) { + log.info("Nursing quality check: encounterId={}, recordId={}", encounterId, recordId); + + Map result = new HashMap<>(); + result.put("encounterId", encounterId); + result.put("patientId", patientId); + result.put("recordId", recordId); + result.put("score", 95); + result.put("passed", true); + result.put("issues", java.util.Collections.emptyList()); + result.put("status", "PASSED"); + + // TODO: 接入实际质控规则引擎(护理文书规范检查) + log.info("Nursing quality check result: recordId={}, score={}", recordId, result.get("score")); + return result; + } +} +``` + +- [ ] **Step 3: 修改NursingQualityHandler注入Service** + +```java +package com.healthlink.his.web.dataflow.handler; + +import com.healthlink.his.web.dataflow.event.NursingRecordSavedEvent; +import com.healthlink.his.web.dataflow.service.NursingQualityCheckService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Slf4j +@Component +@RequiredArgsConstructor +public class NursingQualityHandler { + + private final NursingQualityCheckService nursingQualityCheckService; + + @Async + @EventListener + public void onNursingRecordSaved(NursingRecordSavedEvent event) { + log.info("Chain6 NursingQuality: encounterId={}, patientId={}, recordId={}", + event.getEncounterId(), event.getPatientId(), event.getRecordId()); + try { + Map qualityResult = nursingQualityCheckService.check( + event.getEncounterId(), event.getPatientId(), event.getRecordId()); + log.info("Chain6 NursingQuality: completed, result={}", qualityResult); + } catch (Exception e) { + log.error("Chain6 NursingQuality failed: recordId={}", event.getRecordId(), e); + } + } +} +``` + +- [ ] **Step 4: 编译验证** + +Run: `mvn clean compile -DskipTests -pl healthlink-his-application` +Expected: BUILD SUCCESS + +- [ ] **Step 5: Commit** + +```bash +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/NursingQualityHandler.java +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/NursingQualityCheckService.java +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/impl/NursingQualityCheckServiceImpl.java +git commit -m "feat(dataflow): 补全Chain6 护理质控规则检查" +``` + +--- + +## Task 3: 新增Chain 8 — 手术→术后恢复链路 + +**Files:** +- Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/SurgeryCompletedEvent.java` +- Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/PostSurgeryRecoveryHandler.java` +- Modify: 手术完成保存处发布事件 + +- [ ] **Step 1: 创建手术完成事件** + +```java +package com.healthlink.his.web.dataflow.event; + +import org.springframework.context.ApplicationEvent; +import lombok.Getter; + +@Getter +public class SurgeryCompletedEvent extends ApplicationEvent { + private final Long encounterId; + private final Long patientId; + private final Long surgeryId; + private final String surgeryType; + + public SurgeryCompletedEvent(Object source, Long encounterId, Long patientId, Long surgeryId, String surgeryType) { + super(source); + this.encounterId = encounterId; + this.patientId = patientId; + this.surgeryId = surgeryId; + this.surgeryType = surgeryType; + } +} +``` + +- [ ] **Step 2: 创建术后恢复Handler** + +```java +package com.healthlink.his.web.dataflow.handler; + +import com.healthlink.his.web.dataflow.event.SurgeryCompletedEvent; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Component +public class PostSurgeryRecoveryHandler { + + @Async + @EventListener + public void onSurgeryCompleted(SurgeryCompletedEvent event) { + log.info("Chain8 PostSurgery: encounterId={}, surgeryId={}, type={}", + event.getEncounterId(), event.getSurgeryId(), event.getSurgeryType()); + try { + // 1. 创建术后护理计划 + Map recoveryPlan = new HashMap<>(); + recoveryPlan.put("encounterId", event.getEncounterId()); + recoveryPlan.put("surgeryId", event.getSurgeryId()); + recoveryPlan.put("planType", "POST_SURGERY"); + recoveryPlan.put("status", "ACTIVE"); + + // TODO: 保存术后护理计划到数据库 + + // 2. 生成术后医嘱模板 + // TODO: 根据手术类型生成术后医嘱 + + log.info("Chain8 PostSurgery: recovery plan created for encounterId={}", event.getEncounterId()); + } catch (Exception e) { + log.error("Chain8 PostSurgery failed: surgeryId={}", event.getSurgeryId(), e); + } + } +} +``` + +- [ ] **Step 3: 在手术完成保存处发布事件** + +找到手术保存的AppService,在保存成功后添加事件发布: + +```java +@Autowired +private ApplicationEventPublisher eventPublisher; + +// 在手术保存成功后 +eventPublisher.publishEvent(new SurgeryCompletedEvent(this, encounterId, patientId, surgeryId, surgeryType)); +``` + +- [ ] **Step 4: 编译验证** + +Run: `mvn clean compile -DskipTests -pl healthlink-his-application` +Expected: BUILD SUCCESS + +- [ ] **Step 5: Commit** + +```bash +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/SurgeryCompletedEvent.java +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/PostSurgeryRecoveryHandler.java +git commit -m "feat(dataflow): 新增Chain8 手术→术后恢复链路" +``` + +--- + +## Task 4: 新增Chain 9 — 检查→报告→医嘱联动 + +**Files:** +- Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/ExamReportPublishedEvent.java` +- Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/ExamReportFeedbackHandler.java` + +- [ ] **Step 1: 创建检查报告发布事件** + +```java +package com.healthlink.his.web.dataflow.event; + +import org.springframework.context.ApplicationEvent; +import lombok.Getter; + +@Getter +public class ExamReportPublishedEvent extends ApplicationEvent { + private final Long encounterId; + private final Long patientId; + private final Long reportId; + private final String examType; + private final String findingSummary; + + public ExamReportPublishedEvent(Object source, Long encounterId, Long patientId, Long reportId, String examType, String findingSummary) { + super(source); + this.encounterId = encounterId; + this.patientId = patientId; + this.reportId = reportId; + this.examType = examType; + this.findingSummary = findingSummary; + } +} +``` + +- [ ] **Step 2: 创建检查报告反馈Handler** + +```java +package com.healthlink.his.web.dataflow.handler; + +import com.healthlink.his.web.dataflow.event.ExamReportPublishedEvent; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class ExamReportFeedbackHandler { + + @Async + @EventListener + public void onExamReportPublished(ExamReportPublishedEvent event) { + log.info("Chain9 ExamFeedback: encounterId={}, examType={}, reportId={}", + event.getEncounterId(), event.getExamType(), event.getReportId()); + try { + // 1. 将检查结果关联到医嘱 + // TODO: 更新医嘱执行状态 + + // 2. 推送通知给开单医生 + // TODO: WebSocket推送 + + log.info("Chain9 ExamFeedback: feedback recorded for reportId={}", event.getReportId()); + } catch (Exception e) { + log.error("Chain9 ExamFeedback failed: reportId={}", event.getReportId(), e); + } + } +} +``` + +- [ ] **Step 3: 在检查报告保存处发布事件** + +找到检查报告保存的Service,在保存成功后添加事件发布。 + +- [ ] **Step 4: 编译验证** + +Run: `mvn clean compile -DskipTests -pl healthlink-his-application` +Expected: BUILD SUCCESS + +- [ ] **Step 5: Commit** + +```bash +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/ExamReportPublishedEvent.java +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/ExamReportFeedbackHandler.java +git commit -m "feat(dataflow): 新增Chain9 检查→报告→医嘱联动" +``` + +--- + +## Task 5: 新增Chain 10 — 入院评估→护理计划自动生成 + +**Files:** +- Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/AdmissionAssessmentCompletedEvent.java` +- Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/NursingPlanAutoGenerateHandler.java` + +- [ ] **Step 1: 创建入院评估完成事件** + +```java +package com.healthlink.his.web.dataflow.event; + +import org.springframework.context.ApplicationEvent; +import lombok.Getter; + +@Getter +public class AdmissionAssessmentCompletedEvent extends ApplicationEvent { + private final Long encounterId; + private final Long patientId; + private final Long assessmentId; + private final String riskLevel; + + public AdmissionAssessmentCompletedEvent(Object source, Long encounterId, Long patientId, Long assessmentId, String riskLevel) { + super(source); + this.encounterId = encounterId; + this.patientId = patientId; + this.assessmentId = assessmentId; + this.riskLevel = riskLevel; + } +} +``` + +- [ ] **Step 2: 创建护理计划自动生成Handler** + +```java +package com.healthlink.his.web.dataflow.handler; + +import com.healthlink.his.web.dataflow.event.AdmissionAssessmentCompletedEvent; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Component +public class NursingPlanAutoGenerateHandler { + + @Async + @EventListener + public void onAssessmentCompleted(AdmissionAssessmentCompletedEvent event) { + log.info("Chain10 NursingPlan: encounterId={}, riskLevel={}", + event.getEncounterId(), event.getRiskLevel()); + try { + // 根据风险等级生成护理计划 + Map nursingPlan = new HashMap<>(); + nursingPlan.put("encounterId", event.getEncounterId()); + nursingPlan.put("patientId", event.getPatientId()); + nursingPlan.put("assessmentId", event.getAssessmentId()); + nursingPlan.put("riskLevel", event.getRiskLevel()); + nursingPlan.put("status", "ACTIVE"); + + // TODO: 根据风险等级生成具体护理措施 + + log.info("Chain10 NursingPlan: plan generated for encounterId={}", event.getEncounterId()); + } catch (Exception e) { + log.error("Chain10 NursingPlan failed: encounterId={}", event.getEncounterId(), e); + } + } +} +``` + +- [ ] **Step 3: 在入院评估保存处发布事件** + +- [ ] **Step 4: 编译验证** + +Run: `mvn clean compile -DskipTests -pl healthlink-his-application` +Expected: BUILD SUCCESS + +- [ ] **Step 5: Commit** + +```bash +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/AdmissionAssessmentCompletedEvent.java +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/NursingPlanAutoGenerateHandler.java +git commit -m "feat(dataflow): 新增Chain10 入院评估→护理计划自动生成" +``` + +--- + +## Task 6: 为所有Handler添加重试机制 + +**Files:** +- Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/config/EventRetryConfig.java` +- Modify: 所有7个Handler添加重试逻辑 + +- [ ] **Step 1: 创建重试配置类** + +```java +package com.healthlink.his.web.dataflow.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import java.util.concurrent.Executor; + +@Configuration +public class EventRetryConfig { + + @Bean("eventRetryExecutor") + public Executor eventRetryExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(4); + executor.setMaxPoolSize(8); + executor.setQueueCapacity(100); + executor.setThreadNamePrefix("event-retry-"); + executor.initialize(); + return executor; + } +} +``` + +- [ ] **Step 2: 创建重试工具类** + +```java +package com.healthlink.his.web.dataflow.util; + +import lombok.extern.slf4j.Slf4j; +import java.util.function.Supplier; + +@Slf4j +public class EventRetryUtil { + + public static T executeWithRetry(String chainName, Supplier action, int maxRetries) { + Exception lastException = null; + for (int i = 0; i <= maxRetries; i++) { + try { + return action.get(); + } catch (Exception e) { + lastException = e; + log.warn("Chain{} attempt {} failed: {}", chainName, i + 1, e.getMessage()); + if (i < maxRetries) { + try { + Thread.sleep(1000L * (i + 1)); // 指数退避 + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new RuntimeException(ie); + } + } + } + } + throw new RuntimeException("Chain" + chainName + " failed after " + maxRetries + " retries", lastException); + } + + public static void executeVoidWithRetry(String chainName, Runnable action, int maxRetries) { + executeWithRetry(chainName, () -> { action.run(); return null; }, maxRetries); + } +} +``` + +- [ ] **Step 3: 修改DiagnosisSyncHandler添加重试** + +在onAdmissionSaved方法中使用重试工具: + +```java +EventRetryUtil.executeVoidWithRetry("1-DiagnosisSync", () -> { + // 原有逻辑 +}, 3); +``` + +- [ ] **Step 4: 对其他6个Handler做相同修改** + +- [ ] **Step 5: 编译验证** + +Run: `mvn clean compile -DskipTests -pl healthlink-his-application` +Expected: BUILD SUCCESS + +- [ ] **Step 6: Commit** + +```bash +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/config/EventRetryConfig.java +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/util/EventRetryUtil.java +git commit -m "feat(dataflow): 为所有Handler添加重试机制" +``` + +--- + +## Task 7: 添加链路间联动 — 危急值→医嘱停止 + +**Files:** +- Modify: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/CriticalValueHandler.java` +- Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/OrderStopRequestEvent.java` + +- [ ] **Step 1: 创建医嘱停止请求事件** + +```java +package com.healthlink.his.web.dataflow.event; + +import org.springframework.context.ApplicationEvent; +import lombok.Getter; + +@Getter +public class OrderStopRequestEvent extends ApplicationEvent { + private final Long encounterId; + private final Long orderId; + private final String reason; + private final String triggerChain; + + public OrderStopRequestEvent(Object source, Long encounterId, Long orderId, String reason, String triggerChain) { + super(source); + this.encounterId = encounterId; + this.orderId = orderId; + this.reason = reason; + this.triggerChain = triggerChain; + } +} +``` + +- [ ] **Step 2: 修改CriticalValueHandler在危急值时触发医嘱停止** + +```java +@Autowired +private ApplicationEventPublisher eventPublisher; + +// 在onLabReportPublished方法中,危急值确认后 +if (criticalValue.isSevere()) { + // 查找相关医嘱并请求停止 + List relatedOrderIds = findRelatedOrders(event.getEncounterId(), event.getTestItem()); + for (Long orderId : relatedOrderIds) { + eventPublisher.publishEvent(new OrderStopRequestEvent( + this, event.getEncounterId(), orderId, + "危急值触发自动停嘱: " + event.getTestItem(), "Chain4-Chain2")); + } +} +``` + +- [ ] **Step 3: 编译验证** + +Run: `mvn clean compile -DskipTests -pl healthlink-his-application` +Expected: BUILD SUCCESS + +- [ ] **Step 4: Commit** + +```bash +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/OrderStopRequestEvent.java +git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/CriticalValueHandler.java +git commit -m "feat(dataflow): 添加链路联动 危急值→医嘱停止" +``` + +--- + +## Task 8: 最终编译验证 + +- [ ] **Step 1: 全量编译** + +Run: `mvn clean compile -DskipTests` +Expected: BUILD SUCCESS + +- [ ] **Step 2: 检查所有Event和Handler** + +确认10条链路的Event和Handler都存在: + +| 链路 | Event | Handler | +|------|-------|---------| +| 1 | AdmissionSavedEvent | DiagnosisSyncHandler | +| 2 | OrderExecutedEvent | OrderExecutionFeedbackHandler | +| 3 | MedicationDispensedEvent | AutoBillingHandler | +| 4 | LabReportPublishedEvent | CriticalValueHandler | +| 5 | DischargeEvent | DrgGroupingHandler | +| 6 | NursingRecordSavedEvent | NursingQualityHandler | +| 7 | StatisticsPushEvent | StatisticsPushHandler | +| 8 | SurgeryCompletedEvent | PostSurgeryRecoveryHandler | +| 9 | ExamReportPublishedEvent | ExamReportFeedbackHandler | +| 10 | AdmissionAssessmentCompletedEvent | NursingPlanAutoGenerateHandler | + +- [ ] **Step 3: Commit** + +```bash +git add -A +git commit -m "feat(dataflow): 数据流优化完成 - 10条链路+重试机制+链路联动" +``` + +--- + +## 验证清单 + +| 验证项 | 命令 | 预期结果 | +|--------|------|---------| +| 后端编译 | `mvn clean compile -DskipTests` | BUILD SUCCESS | +| Event类数量 | `ls *Event.java` | 10个 | +| Handler类数量 | `ls *Handler.java` | 10个 | +| 重试工具 | `EventRetryUtil.java` | 存在 | +| 链路联动 | `OrderStopRequestEvent.java` | 存在 | diff --git a/MD/architecture/MICROSERVICE_UPGRADE_PLAN.md b/MD/architecture/MICROSERVICE_UPGRADE_PLAN.md new file mode 100644 index 000000000..e396eea7f --- /dev/null +++ b/MD/architecture/MICROSERVICE_UPGRADE_PLAN.md @@ -0,0 +1,120 @@ +# HealthLink-HIS 微服务升级技术方案 + +> **文档类型**: 架构设计+实施计划 +> **版本**: v1.0 +> **日期**: 2026-06-19 + +--- + +## 一、系统架构 + +### 当前 → 目标 + +| 维度 | 当前 | 目标 | +|------|------|------| +| 架构 | 单体Spring Boot | 微服务Spring Cloud | +| 部署 | 单机 | K8s集群 | +| 数据库 | 单库PostgreSQL | 分库+读写分离 | +| 缓存 | 本地缓存 | Redis Cluster | +| 消息 | 同步调用 | RabbitMQ异步 | +| 网关 | 无 | Spring Cloud Gateway | +| 服务发现 | 无 | Nacos | + +### 微服务划分(21个服务) + +| 服务 | 职责 | 优先级 | +|------|------|:------:| +| gateway-service | API网关+路由+限流+鉴权 | P0 | +| auth-service | 认证授权+SSO+OAuth2 | P0 | +| user-service | 用户管理+角色权限 | P0 | +| patient-service | 患者主索引+EMPI | P0 | +| registration-service | 挂号预约+分诊叫号 | P0 | +| doctor-service | 门诊医生站+医嘱处方 | P0 | +| nurse-service | 护士站+护理评估 | P0 | +| inpatient-service | 住院管理+入出转 | P0 | +| pharmacy-service | 药品管理+药房 | P0 | +| lab-service | LIS检验管理 | P1 | +| pacs-service | PACS影像管理 | P1 | +| surgery-service | 手术麻醉 | P1 | +| emr-service | 电子病历+质控 | P0 | +| mr-service | 病案管理+DRG | P1 | +| finance-service | 收费结算+医保 | P0 | +| report-service | 统计报表+BI | P1 | +| cdss-service | 临床决策支持 | P1 | +| knowledge-service | 医疗知识图谱 | P2 | +| message-service | 消息通知 | P0 | +| file-service | 文件存储 | P0 | +| audit-service | 操作审计 | P1 | + +--- + +## 二、开发环境 + +| 组件 | 配置 | +|------|------| +| JDK | OpenJDK 25 | +| IDE | IntelliJ IDEA 2025+ | +| Maven | 3.9+ | +| Node.js | 20+ LTS | +| Docker Desktop | 最新版 | +| PostgreSQL | 15+ | +| Redis | 7+ | +| Nacos | 2.3+ | +| RabbitMQ | 3.12+ | + +--- + +## 三、测试环境 + +| 组件 | 配置 | +|------|------| +| 服务器 | 4核8G × 3台 | +| 数据库 | PostgreSQL 15 (主从) | +| 缓存 | Redis Cluster 3节点 | +| 消息 | RabbitMQ 3节点 | +| 监控 | Prometheus+Grafana | +| 日志 | ELK Stack | +| 链路 | SkyWalking | + +--- + +## 四、生产环境 + +| 组件 | 配置 | +|------|------| +| 服务器 | 8核16G × 6台 | +| 数据库 | PostgreSQL 15 (主+2从) | +| 缓存 | Redis Cluster 6节点 | +| 消息 | RabbitMQ 6节点 | +| 负载均衡 | Nginx/HAProxy | +| CDN | 阿里云/腾讯云 | +| WAF | 云WAF | + +--- + +## 五、开发计划 + +| 阶段 | 时间 | 内容 | +|------|------|------| +| Phase 1 | 1-4周 | 基础设施(网关+认证+用户+患者) | +| Phase 2 | 5-8周 | 业务服务(LIS+PACS+MR+Report+CDSS) | +| Phase 3 | 9-12周 | 云原生(Docker+K8s+监控) | +| Phase 4 | 13-16周 | SaaS化(多租户+开放API) | + +--- + +## 六、资源需求 + +| 角色 | 人数 | 年薪(万) | +|------|:----:|:-------:| +| 架构师 | 1 | 40 | +| 后端开发 | 6 | 150 | +| 前端开发 | 2 | 40 | +| DevOps | 2 | 60 | +| 测试 | 2 | 36 | +| DBA | 1 | 25 | +| **合计** | **14人** | **310万** | + +--- + +> **文档版本**: v1.0 | **最后更新**: 2026-06-19 diff --git a/healthlink-his-server/core-common/src/main/java/com/core/common/utils/TenantOptionUtil.java b/healthlink-his-server/core-common/src/main/java/com/core/common/utils/TenantOptionUtil.java new file mode 100644 index 000000000..d9a9878b5 --- /dev/null +++ b/healthlink-his-server/core-common/src/main/java/com/core/common/utils/TenantOptionUtil.java @@ -0,0 +1,42 @@ +package com.core.common.utils; + +import com.core.common.core.domain.model.LoginUser; +import com.core.common.enums.TenantOptionDict; +import com.core.common.utils.SecurityUtils; +import com.core.common.utils.StringUtils; + +/** + * 租户配置工具类 + * + * @author system + */ +public class TenantOptionUtil { + + /** + * 获取租户配置项内容 + * + * @param optionDict 租户配置项字典 + * @return 租户配置项内容 + */ + public static String getOptionContent(TenantOptionDict optionDict) { + LoginUser loginUser; + try { + loginUser = SecurityUtils.getLoginUser(); + } catch (Exception e) { + return null; + } + if (loginUser == null) { + return null; + } + if (loginUser.getOptionMap() == null || loginUser.getOptionMap().isEmpty()) { + return null; + } + // return loginUser.getOptionMap().get(optionDict.getCode()); + + // TODO:2025/10/17 李永兴提出的sys_option切换TenantOption临时防止报错方案,最晚2025年11月底删除 + String newValue = loginUser.getOptionMap().get(optionDict.getCode()); + String oldValue = loginUser.getOptionJsonValue(optionDict.getCode()); + return StringUtils.isEmpty(newValue) ? oldValue : newValue; + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryCommonService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryCommonService.java new file mode 100644 index 000000000..6fceafb1d --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryCommonService.java @@ -0,0 +1,79 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryInitDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensarySearchParam; + +import jakarta.servlet.http.HttpServletRequest; + +/** + * 药房共通方法 + * + * @author yuxj + * @date 2025-07-22 + */ +public interface IPharmacyDispensaryCommonService { + /** + * 单据初始化 + * + * @return 初始化信息 + */ + PharmacyDispensaryInitDto init(); + + /** + * 获取药品 + * + * @param purchaseOrderSearchParam 查询条件 + * @return 药品信息 + */ + R> getMedicationInfo(PharmacyDispensarySearchParam purchaseOrderSearchParam, Integer pageNo, Integer pageSize, + String searchKey, HttpServletRequest request); + + /** + * 单据列表 + * + * @param purchaseOrderSearchParam 查询条件 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param searchKey 模糊查询关键字 + * @param request 请求数据 + * @param locationFlg 仓库flg + * @param supplyType 单据类型 + * @return 订货单据分页列表 + */ + R> getPage(PharmacyDispensarySearchParam purchaseOrderSearchParam, Integer pageNo, Integer pageSize, + String searchKey, HttpServletRequest request,String locationFlg,Integer supplyType); + + /** + * 删除单据 + * + * @param busNo 单据号 + * @return 操作结果 + */ + R> deleteOrder(String busNo); + +// /** +// * 提交审批 +// * +// * @param busNo 单据号 +// * @return 操作结果 +// */ +// R> submitApproval(String busNo); + +// /** +// * 同意审批 +// * +// * @param busNo 单据号 +// * @return 操作结果 +// */ +// R> agreeApproval(String busNo); + +// /** +// * 撤回审批 +// * +// * @param busNo 单据号 +// * @return 操作结果 +// */ +// R> withdrawApproval(String busNo); + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryDispensingOrderService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryDispensingOrderService.java new file mode 100644 index 000000000..23d4cf8f0 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryDispensingOrderService.java @@ -0,0 +1,39 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice; + +import com.core.common.core.domain.R; + +import java.util.List; + +/** + * 药房发药单 + * + * @author yuxj + * @date 2025-07-22 + */ +public interface IPharmacyDispensaryDispensingOrderService { + /** + * 单据初始化 + * + * @return 初始化信息 + */ + R> init(); + + /** + * 发药单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 发药单单据详情 + */ + R> getDetailPage(String busNo, Integer pageNo, Integer pageSize); + + /** + * 添加/编辑发药单 + * + * @param dispenseIdList 药品发放id + * @return 操作结果 + */ + boolean addOrEditDispensingOrder(List dispenseIdList); + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryProfitLossOrderService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryProfitLossOrderService.java new file mode 100644 index 000000000..4048ab81d --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryProfitLossOrderService.java @@ -0,0 +1,47 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; + +import java.util.List; + +/** + * 药房损益单 + * + * @author yuxj + * @date 2025-07-22 + */ +public interface IPharmacyDispensaryProfitLossOrderService { + /** + * 单据初始化 + * + * @return 初始化信息 + */ + R> init(); + + /** + * 损益单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 损益单单据详情 + */ + R> getDetailPage(String busNo, Integer pageNo, Integer pageSize); + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + R> getBusNo(); + + /** + * 添加/编辑损益单 + * + * @param profitLossOrderDtoList 损益信息 + * @return 操作结果 + */ + R> addOrEditProfitLossOrder(List profitLossOrderDtoList); + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryReceiptApprovalService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryReceiptApprovalService.java new file mode 100644 index 000000000..19cbc54be --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryReceiptApprovalService.java @@ -0,0 +1,89 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.inventorymanage.dto.SupplyItemDetailDto; + +import java.util.List; + +/** + * 药房审批方法 + * + * @author yuxj + * @date 2025-07-22 + */ +public interface IPharmacyDispensaryReceiptApprovalService { + + /** + * 请领单同意审批 + * + * @param busNo 单据号 + * @return 操作结果 + */ + R> requisitionOrderAgreeApproval(String busNo); + + /** + * 药房入库单据审批通过 + * + * @param busNo 单据号 + * @return 操作结果 + */ + R> stockInOrderAgreeApproved(String busNo); + + /** + * 药库退库审批通过 + * + * @param busNo 单据号 + * @return 操作结果 + */ + R> returnToWarehouseAgreeApproved(String busNo); + + +// /** +// * 药房发药审批通过 +// * +// * @param busNo 单据号 +// * @return 操作结果 +// */ +// R> dispensingAgreeApproved(String busNo); + + /** + * 药房损益单审批通过 + * + * @param busNo 单据号 + * @return 操作结果 + */ + R> profitLossAgreeApproved(String busNo); + + /** + * 药房盘点单审批通过 + * + * @param busNo 单据号 + * @return 操作结果 + */ + R> stocktakingAgreepproved(String busNo); + /** + * 药房调入单审批通过 + * + * @param busNo 单据号 + * @return 操作结果 + */ + R> transferInAgreeApproved(String busNo); + + /** + * 药房调出单审批通过 + * + * @param busNo 单据号 + * @return 操作结果 + */ + R> transferOutAgreeApproved(String busNo); + + /** + * 根据单据号获取供应单据及供应项相关详细信息 + * + * @param busNo 单据号 + * @return 供应单据及供应项相关详细信息 + */ + List getSupplyItemDetail(String busNo); + + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryRequisitionOrderService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryRequisitionOrderService.java new file mode 100644 index 000000000..5d17cc530 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryRequisitionOrderService.java @@ -0,0 +1,47 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; + +import java.util.List; + +/** + * 药房请领单 + * + * @author yuxj + * @date 2025-07-22 + */ +public interface IPharmacyDispensaryRequisitionOrderService { + /** + * 单据初始化 + * + * @return 初始化信息 + */ + R> init(); + + /** + * 请领单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 请领单单据详情 + */ + R> getDetailPage(String busNo, Integer pageNo, Integer pageSize); + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + R> getBusNo(); + + /** + * 添加/编辑采购单 + * + * @param requisitionOrderDtoList 采购信息 + * @return 操作结果 + */ + R> addOrEditRequisitionOrder(List requisitionOrderDtoList); + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryReturnToWarehouseOrderService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryReturnToWarehouseOrderService.java new file mode 100644 index 000000000..0e06fb479 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryReturnToWarehouseOrderService.java @@ -0,0 +1,47 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; + +import java.util.List; + +/** + * 药房退库单 + * + * @author yuxj + * @date 2025-07-22 + */ +public interface IPharmacyDispensaryReturnToWarehouseOrderService { + /** + * 单据初始化 + * + * @return 初始化信息 + */ + R> init(); + + /** + * 退库单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 退库单单据详情 + */ + R> getDetailPage(String busNo, Integer pageNo, Integer pageSize); + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + R> getBusNo(); + + /** + * 添加/编辑退库单 + * + * @param returnToDispensaryOrderDtoList 退库信息 + * @return 操作结果 + */ + R> addOrEditReturnToWarehouseOrder(List returnToDispensaryOrderDtoList); + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryStockInOrderService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryStockInOrderService.java new file mode 100644 index 000000000..041d82360 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryStockInOrderService.java @@ -0,0 +1,47 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; + +import java.util.List; + +/** + * 药房入库单 + * + * @author yuxj + * @date 2025-07-22 + */ +public interface IPharmacyDispensaryStockInOrderService { + /** + * 单据初始化 + * + * @return 初始化信息 + */ + R> init(); + + /** + * 入库单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 入库单单据详情 + */ + R> getDetailPage(String busNo, Integer pageNo, Integer pageSize); + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + R> getBusNo(); + + /** + * 添加/编辑入库单 + * + * @param stockInOrderDtoList 入库信息 + * @return 操作结果 + */ + R> addOrEditStockInOrder(List stockInOrderDtoList); + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryStocktakingOrderService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryStocktakingOrderService.java new file mode 100644 index 000000000..aab712403 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryStocktakingOrderService.java @@ -0,0 +1,47 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; + +import java.util.List; + +/** + * 药房盘点单 + * + * @author yuxj + * @date 2025-07-22 + */ +public interface IPharmacyDispensaryStocktakingOrderService { + /** + * 单据初始化 + * + * @return 初始化信息 + */ + R> init(); + + /** + * 盘点单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 盘点单单据详情 + */ + R> getDetailPage(String busNo, Integer pageNo, Integer pageSize); + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + R> getBusNo(); + + /** + * 添加/编辑盘点单 + * + * @param stocktakingOrderDtoList 盘点信息 + * @return 操作结果 + */ + R> addOrEditStocktakingOrder(List stocktakingOrderDtoList); + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryTransferInOrderService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryTransferInOrderService.java new file mode 100644 index 000000000..d3d034d71 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryTransferInOrderService.java @@ -0,0 +1,47 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; + +import java.util.List; + +/** + * 药房调入单 + * + * @author yuxj + * @date 2025-07-22 + */ +public interface IPharmacyDispensaryTransferInOrderService { + /** + * 单据初始化 + * + * @return 初始化信息 + */ + R> init(); + + /** + * 调入单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 调入单单据详情 + */ + R> getDetailPage(String busNo, Integer pageNo, Integer pageSize); + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + R> getBusNo(); + + /** + * 添加/编辑采购单 + * + * @param transferInOrderDtoList 采购信息 + * @return 操作结果 + */ + R> addOrEditTransferInOrder(List transferInOrderDtoList); + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryTransferOutOrderService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryTransferOutOrderService.java new file mode 100644 index 000000000..960470ceb --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/IPharmacyDispensaryTransferOutOrderService.java @@ -0,0 +1,47 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; + +import java.util.List; + +/** + * 药房调出单 + * + * @author yuxj + * @date 2025-07-22 + */ +public interface IPharmacyDispensaryTransferOutOrderService { + /** + * 单据初始化 + * + * @return 初始化信息 + */ + R> init(); + + /** + * 调出单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 调出单单据详情 + */ + R> getDetailPage(String busNo, Integer pageNo, Integer pageSize); + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + R> getBusNo(); + + /** + * 添加/编辑采购单 + * + * @param transferOutOrderDtoList 采购信息 + * @return 操作结果 + */ + R> addOrEditTransferOutOrder(List transferOutOrderDtoList); + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryCommonServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryCommonServiceImpl.java new file mode 100644 index 000000000..ec639b196 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryCommonServiceImpl.java @@ -0,0 +1,222 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.core.common.core.domain.R; +import com.core.common.utils.MessageUtils; +import com.healthlink.his.administration.domain.Practitioner; +import com.healthlink.his.administration.domain.Supplier; +import com.healthlink.his.administration.service.IPractitionerService; +import com.healthlink.his.administration.service.ISupplierService; +import com.healthlink.his.common.constant.CommonConstants; +import com.healthlink.his.common.constant.PromptMsgConstant; +import com.healthlink.his.common.enums.AcceptanceResult; +import com.healthlink.his.common.enums.PackagingCondition; +import com.healthlink.his.common.enums.SupplyStatus; +import com.healthlink.his.common.enums.SupplyType; +import com.healthlink.his.common.utils.EnumUtils; +import com.healthlink.his.common.utils.HisQueryUtils; +import com.healthlink.his.web.common.appservice.ICommonService; +import com.healthlink.his.web.common.dto.LocationDto; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryInitDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryMedicationInfoDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensarySearchParam; +import com.healthlink.his.web.pharmacy.dispensary.mapper.PharmacyDispensaryCommonMapper; +import com.healthlink.his.workflow.domain.SupplyRequest; +import com.healthlink.his.workflow.service.ISupplyRequestService; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 药房共通 + * + * @author yuxj + * @date 2025-07-22 + */ +@Service +public class PharmacyDispensaryCommonServiceImpl implements IPharmacyDispensaryCommonService { + + @Resource + private ISupplierService supplierService; + + @Resource + private IPractitionerService practitionerService; + + @Resource + private ISupplyRequestService supplyRequestService; + + @Resource + private PharmacyDispensaryCommonMapper pharmacyDispensaryCommonMapper; + @Resource + private ICommonService commonServiceImpl; + + /** + * 初始化 + * + * @return 初始化信息 + */ + @Override + public PharmacyDispensaryInitDto init() { + PharmacyDispensaryInitDto orderInitDto = new PharmacyDispensaryInitDto(); + + // 查询供应商列表 + List supplierList = supplierService.getList(); + // 查询经手人列表 + List practitionerList = practitionerService.getList(); + // 经手人信息 + List practitionerListOption = practitionerList.stream() + .map(practitioner -> new PharmacyDispensaryInitDto.LongOption(practitioner.getId(), practitioner.getName())) + .collect(Collectors.toList()); + // 供应商信息 + List supplierListOption = supplierList.stream() + .map(supplier -> new PharmacyDispensaryInitDto.SupplierOption(supplier.getId(), supplier.getName() ,supplier.getPhone())) + .collect(Collectors.toList()); + // 审批状态 + List supplyStatusOption = Stream.of(SupplyStatus.values()).map( + supplyStatus -> new PharmacyDispensaryInitDto.IntegerOption(supplyStatus.getValue(), supplyStatus.getInfo())) + .collect(Collectors.toList()); + + // 包装情况 + List packagingConditionOption = Stream.of(PackagingCondition.values()) + .map(packagingCondition -> new PharmacyDispensaryInitDto.IntegerOption(packagingCondition.getValue(), + packagingCondition.getInfo())) + .collect(Collectors.toList()); + + // 验收结果 + List acceptanceResultOption = Stream.of(AcceptanceResult.values()) + .map(acceptanceResult -> new PharmacyDispensaryInitDto.IntegerOption(acceptanceResult.getValue(), + acceptanceResult.getInfo())) + .collect(Collectors.toList()); + + // 仓库列表 + List cabinetList = commonServiceImpl.getCabinetList(); + + // 药房列表 + List pharmacyList = commonServiceImpl.getPharmacyList(); + + orderInitDto.setCabinetListOptions(cabinetList).setPharmacyListOptions(pharmacyList).setSupplierOption(supplierListOption) + .setPractitionerOption(practitionerListOption).setSupplyStatusOptions(supplyStatusOption) + .setPackagingConditionOptions(packagingConditionOption) + .setAcceptanceResultoryOptions(acceptanceResultOption); + + return orderInitDto; + } + + /** + * 获取药品 + * + * @param purchaseOrderSearchParam 查询条件 + * @return 药品信息 + */ + @Override + public R> getMedicationInfo(PharmacyDispensarySearchParam purchaseOrderSearchParam, Integer pageNo, + Integer pageSize, String searchKey, HttpServletRequest request) { + + Long locationId = purchaseOrderSearchParam.getLocationId(); + purchaseOrderSearchParam.setLocationId(null); + Long supplierId = purchaseOrderSearchParam.getSupplierId(); + purchaseOrderSearchParam.setSupplierId(null); + // 构建查询条件 + QueryWrapper queryWrapper = + HisQueryUtils.buildQueryWrapper(purchaseOrderSearchParam, searchKey, + new HashSet<>(Arrays.asList(CommonConstants.FieldName.Name, CommonConstants.FieldName.PyStr)), request); + // 设置排序 + queryWrapper.orderByDesc(CommonConstants.FieldName.Name); + + Page medicationInfoDto = pharmacyDispensaryCommonMapper + .getMedicationInfo(new Page<>(pageNo, pageSize), queryWrapper, locationId, supplierId); + + for (PharmacyDispensaryMedicationInfoDto item : medicationInfoDto.getRecords()) { + List unitList = new ArrayList<>(); + unitList + .add(new PharmacyDispensaryMedicationInfoDto.Option(item.getUnitCode(), item.getUnitCode_dictText())); + unitList.add( + new PharmacyDispensaryMedicationInfoDto.Option(item.getMinUnitCode(), item.getMinUnitCode_dictText())); + + item.setUnitList(unitList); + } + + return R.ok(medicationInfoDto); + } + + /** + * 单据列表 + * + * @param purchaseOrderSearchParam 查询条件 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param searchKey 模糊查询关键字 + * @param request 请求数据 + * @param locationFlg 仓库flg + * @param supplyType 单据类型 + * @return 订货单据分页列表 + */ + @Override + public R> getPage(PharmacyDispensarySearchParam purchaseOrderSearchParam, Integer pageNo, Integer pageSize, + String searchKey, HttpServletRequest request, String locationFlg,Integer supplyType) { + //判断哪个画面使用 + if (supplyType != null) { + purchaseOrderSearchParam.setTypeEnum(supplyType); + } +// if (locationForm != null) { +// purchaseOrderSearchParam.setLocationTypeEnum(locationForm); +// } + String originalBusNoFlg = purchaseOrderSearchParam.getOriginalBusNoFlg(); + purchaseOrderSearchParam.setOriginalBusNoFlg(null); + // 构建查询条件 + QueryWrapper queryWrapper = + HisQueryUtils.buildQueryWrapper(purchaseOrderSearchParam, searchKey, + new HashSet<>( + Arrays.asList(CommonConstants.FieldName.SupplyBusNo, CommonConstants.FieldName.ApplicantName)), + request); + // 设置排序 + queryWrapper.orderByDesc(CommonConstants.FieldName.SupplyBusNo); + // 查询订货单分页列表 + Page purchaseOrderDtoPage = + pharmacyDispensaryCommonMapper.getPage(new Page<>(pageNo, pageSize), queryWrapper,originalBusNoFlg, locationFlg); + + purchaseOrderDtoPage.getRecords().forEach(e -> { + // 单据状态 + e.setStatusEnum_enumText(EnumUtils.getInfoByValue(SupplyStatus.class, e.getStatusEnum())); + // 单据类型 + e.setTypeEnum_enumText(EnumUtils.getInfoByValue(SupplyType.class, e.getTypeEnum())); + }); + + return R.ok(purchaseOrderDtoPage); + } + + /** + * 删除单据 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @Override + public R> deleteOrder(String busNo) { + // 根据原始单据号查询信息 + List supplyRequest = supplyRequestService.getSupplyByOriginalBusNo(busNo); + if (!supplyRequest.isEmpty()) { + // 将原始单据号信息的原始单据号删除 + boolean flg = supplyRequestService.updateByBusNo(supplyRequest.get(0).getBusNo()); + if (!flg) { + R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + } + + // 删除单据 + boolean result = supplyRequestService.removeByBusNo(busNo); + return result ? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)) + : R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryDispensingOrderServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryDispensingOrderServiceImpl.java new file mode 100644 index 000000000..3925a7139 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryDispensingOrderServiceImpl.java @@ -0,0 +1,186 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.core.common.core.domain.R; +import com.core.common.utils.AssignSeqUtil; +import com.healthlink.his.common.constant.CommonConstants; +import com.healthlink.his.common.enums.*; +import com.healthlink.his.common.utils.EnumUtils; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryDispensingOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryInitDto; +import com.healthlink.his.web.pharmacy.dispensary.mapper.PharmacyDispensaryCommonMapper; +import com.healthlink.his.web.pharmacy.dispensary.mapper.PharmacyDispensaryDispensingOrderMapper; +import com.healthlink.his.workflow.domain.SupplyDelivery; +import com.healthlink.his.workflow.domain.SupplyRequest; +import com.healthlink.his.workflow.service.ISupplyDeliveryService; +import com.healthlink.his.workflow.service.ISupplyRequestService; +import com.healthlink.his.web.dataflow.event.MedicationDispensedEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * 药房发药单 + * + * @author yuxj + * @date 2025-07-22 + */ +@Service +public class PharmacyDispensaryDispensingOrderServiceImpl implements IPharmacyDispensaryDispensingOrderService { + + @Resource + private AssignSeqUtil assignSeqUtil; + @Resource + private ISupplyRequestService supplyRequestService; + @Resource + private ISupplyDeliveryService supplyDeliveryService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + @Autowired + private PharmacyDispensaryCommonMapper pharmacyDispensaryCommonMapper; + @Autowired + private PharmacyDispensaryDispensingOrderMapper pharmacyDispensaryDispensingOrderMapper; + @Autowired + private ApplicationEventPublisher eventPublisher; + + /** + * 初始化 + * + * @return 初始化信息 + */ + @Override + public R> init() { + + PharmacyDispensaryInitDto purchaseOrderInitDto = pharmacyDispensaryCommonService.init(); + + // 单据分类 + List supplyCategoryOption = new ArrayList<>(); + // supplyCategoryOption + // .add(new PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.OUTPATIENT_PATIENT_DISPENSING.getValue(), + // SupplyCategory.OUTPATIENT_PATIENT_DISPENSING.getInfo())); + // supplyCategoryOption + // .add(new PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.INPATIENT_PATIENT_DISPENSING.getValue(), + // SupplyCategory.INPATIENT_PATIENT_DISPENSING.getInfo())); + // supplyCategoryOption.add( + // new PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.INPATIENT_PATIENT_SUMMARY_DISPENSING.getValue(), + // SupplyCategory.INPATIENT_PATIENT_SUMMARY_DISPENSING.getInfo())); + + purchaseOrderInitDto.setSupplyCategoryOptions(supplyCategoryOption); + + return R.ok(purchaseOrderInitDto); + } + + /** + * 发药单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 发药单单据详情 + */ + @Override + public R> getDetailPage(String busNo, Integer pageNo, Integer pageSize) { + + Page dispensingOrderDtoDetailPage = + pharmacyDispensaryCommonMapper.getDetailPage(new Page<>(pageNo, pageSize), busNo); + + dispensingOrderDtoDetailPage.getRecords().forEach(e -> { + // 单据分类 + e.setCategoryEnum_enumText(EnumUtils.getInfoByValue(SupplyCategory.class, e.getCategoryEnum())); + // 单据状态 + e.setStatusEnum_enumText(EnumUtils.getInfoByValue(SupplyStatus.class, e.getStatusEnum())); + // 单据类型 + e.setTypeEnum_enumText(EnumUtils.getInfoByValue(SupplyType.class, e.getTypeEnum())); + + }); + + return R.ok(dispensingOrderDtoDetailPage); + } + + /** + * 获取单据号 + * + * @return 单据号 + */ + public String getBusNo() { + return assignSeqUtil.getSeqByDay(AssignSeqEnum.DISPENSING_ORDER.getPrefix(), 4); + } + + /** + * 添加/编辑发药单 + * + * @param dispenseIdList 药品发放id + * @return 操作结果 + */ + + @Override + public boolean addOrEditDispensingOrder(List dispenseIdList) { + + // 获取单据号 + String busNo = this.getBusNo(); + // 获取更表所需信息 + List detailDto = + pharmacyDispensaryDispensingOrderMapper.getInfo(dispenseIdList, DispenseStatus.COMPLETED.getValue()); + + List supplyRequestList = new ArrayList<>(); + SupplyRequest supplyRequest; + List supplyDeliveryList = new ArrayList<>(); + SupplyDelivery supplyDelivery; + for (PharmacyDispensaryDetailDto item : detailDto) { + // 供应申请 + supplyRequest = new SupplyRequest().setBusNo(busNo).setTypeEnum(SupplyType.DISPENSING_ORDER.getValue()) + .setStatusEnum(SupplyStatus.AGREE.getValue()).setCategoryEnum(item.getCategoryEnum()) + .setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION).setItemId(item.getItemId()) + .setUnitCode(item.getUnitCode()).setItemQuantity(item.getItemQuantity()) + .setLotNumber(item.getLotNumber()).setSourceTypeEnum(LocationForm.PHARMACY.getValue()) + .setSourceLocationId(item.getSourceLocationId()).setPurposeTypeEnum(LocationForm.DEPARTMENT.getValue()) + .setPurposeLocationId(item.getPurposeLocationId()).setApplicantId(item.getApplicantId()) + .setApplyTime(item.getApplyTime()).setApproverId(item.getApproverId()) + .setApprovalTime(item.getApprovalTime()); + supplyRequestList.add(supplyRequest); + // 供应发放 + supplyDelivery = new SupplyDelivery().setRequestId(supplyRequest.getId()) + .setStatusEnum(DispenseStatus.COMPLETED.getValue()).setTypeEnum(supplyRequest.getTypeEnum()) + .setItemTable(supplyRequest.getItemTable()).setItemId(supplyRequest.getItemId()) + .setBasedOnTable(CommonConstants.TableName.MED_MEDICATION_DISPENSE).setBasedOnIds(item.getDispenseIds()) + .setUnitCode(supplyRequest.getUnitCode()).setQuantity(supplyRequest.getItemQuantity()) + .setLotNumber(supplyRequest.getLotNumber()).setPractitionerId(supplyRequest.getApplicantId()) + .setOccurrenceTime(supplyRequest.getApprovalTime()).setReceiverId(supplyRequest.getPurposeLocationId()) + .setReceiveTime(supplyRequest.getApprovalTime()); + + supplyDeliveryList.add(supplyDelivery); + } + + // 更新供应请求表 + boolean requestFlg = supplyRequestService.saveBatch(supplyRequestList); + if (!requestFlg) { + return false; + } + // 更新供应发放表 + boolean deliveryFlg = supplyDeliveryService.saveBatch(supplyDeliveryList); + if (!deliveryFlg) { + return false; + } + + // Chain3: 发布药品发放事件 → 自动计费 + for (PharmacyDispensaryDetailDto item : detailDto) { + eventPublisher.publishEvent(new MedicationDispensedEvent(this, + item.getPurposeLocationId(), + item.getId() != null ? item.getId() : 0L, + item.getItemId(), + item.getItemQuantity(), + item.getPrice() != null ? item.getPrice() : BigDecimal.ZERO)); + } + + return true; + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryProfitLossOrderServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryProfitLossOrderServiceImpl.java new file mode 100644 index 000000000..5ce2a9762 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryProfitLossOrderServiceImpl.java @@ -0,0 +1,175 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.core.common.core.domain.R; +import com.core.common.utils.AssignSeqUtil; +import com.core.common.utils.DateUtils; +import com.core.common.utils.MessageUtils; +import com.healthlink.his.common.constant.CommonConstants; +import com.healthlink.his.common.constant.PromptMsgConstant; +import com.healthlink.his.common.enums.*; +import com.healthlink.his.common.utils.EnumUtils; +import com.healthlink.his.web.inventorymanage.dto.ProductStocktakingInitDto; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryProfitLossOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryInitDto; +import com.healthlink.his.web.pharmacy.dispensary.mapper.PharmacyDispensaryCommonMapper; +import com.healthlink.his.workflow.domain.SupplyRequest; +import com.healthlink.his.workflow.service.ISupplyRequestService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 药房损益单 + * + * @author yuxj + * @date 2025-07-22 + */ +@Service +public class PharmacyDispensaryProfitLossOrderServiceImpl implements IPharmacyDispensaryProfitLossOrderService { + + @Resource + private AssignSeqUtil assignSeqUtil; + @Resource + private ISupplyRequestService supplyRequestService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + @Autowired + private PharmacyDispensaryCommonMapper pharmacyDispensaryCommonMapper; + + /** + * 初始化 + * + * @return 初始化信息 + */ + @Override + public R> init() { + + PharmacyDispensaryInitDto purchaseOrderInitDto = pharmacyDispensaryCommonService.init(); + + // 单据分类 + List supplyCategoryOption = new ArrayList<>(); + // supplyCategoryOption.add(new + // PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.GENERAL_PROFIT_AND_LOSS.getValue(), + // SupplyCategory.GENERAL_PROFIT_AND_LOSS.getInfo())); + // supplyCategoryOption.add(new + // PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.STOCKTAKING_PROFIT_AND_LOSS.getValue(), + // SupplyCategory.STOCKTAKING_PROFIT_AND_LOSS.getInfo())); + // supplyCategoryOption.add(new + // PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.STANDBY_RESCUE_MEDICINES.getValue(), + // SupplyCategory.STANDBY_RESCUE_MEDICINES.getInfo())); + // supplyCategoryOption.add(new + // PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.DAMAGED_EXPIRED_MEDICINES.getValue(), + // SupplyCategory.DAMAGED_EXPIRED_MEDICINES.getInfo())); + // supplyCategoryOption.add(new + // PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.DONATED_MEDICINES.getValue(), + // SupplyCategory.DONATED_MEDICINES.getInfo())); + + purchaseOrderInitDto.setSupplyCategoryOptions(supplyCategoryOption); + + return R.ok(purchaseOrderInitDto); + } + + /** + * 损益单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 损益单单据详情 + */ + @Override + public R> getDetailPage(String busNo, Integer pageNo, Integer pageSize) { + + Page profitLossOrderDtoDetailPage = + pharmacyDispensaryCommonMapper.getDetailPage(new Page<>(pageNo, pageSize), busNo); + + profitLossOrderDtoDetailPage.getRecords().forEach(e -> { + // 单据分类 + e.setCategoryEnum_enumText(EnumUtils.getInfoByValue(SupplyCategory.class, e.getCategoryEnum())); + // 单据状态 + e.setStatusEnum_enumText(EnumUtils.getInfoByValue(SupplyStatus.class, e.getStatusEnum())); + // 单据类型 + e.setTypeEnum_enumText(EnumUtils.getInfoByValue(SupplyType.class, e.getTypeEnum())); + }); + + List unitList; + for (PharmacyDispensaryDetailDto item : profitLossOrderDtoDetailPage.getRecords()) { + unitList = new ArrayList<>(); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMaxUnitCode(), item.getMaxUnitCode_dictText())); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMinUnitCode(), item.getMinUnitCode_dictText())); + + item.setUnitList(unitList); + } + return R.ok(profitLossOrderDtoDetailPage); + } + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @Override + public R> getBusNo() { + + ProductStocktakingInitDto initDto = new ProductStocktakingInitDto(); + // 单据号 + initDto.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.PURCHASE_PRPFITLOSS.getPrefix(), 4)); + + return R.ok(initDto); + } + + /** + * 添加/编辑损益单 + * + * @param profitLossOrderDtoList 损益信息 + * @return 操作结果 + */ + + @Override + public R> addOrEditProfitLossOrder(List profitLossOrderDtoList) { + // 请求数据取得 + List requestList = + supplyRequestService.getSupplyByBusNo(profitLossOrderDtoList.get(0).getBusNo()); + if (!requestList.isEmpty()) { + // 请求id取得 + List requestIdList = requestList.stream().map(SupplyRequest::getId).collect(Collectors.toList()); + // 单据信息删除 + supplyRequestService.removeByIds(requestIdList); + } + + List supplyRequestList = new ArrayList<>(); + Date applyTime = DateUtils.getNowDate(); + for (PharmacyDispensaryDetailDto item : profitLossOrderDtoList) { + SupplyRequest supplyRequest = new SupplyRequest().setBusNo(item.getBusNo()) + .setTypeEnum(SupplyType.PURCHASE_PRPFITLOSS.getValue()) + .setStatusEnum(SupplyStatus.PENDING_REVIEW.getValue()).setCategoryEnum(item.getCategoryEnum()) + .setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION).setItemId(item.getItemId()) + .setUnitCode(item.getUnitCode()).setItemQuantity(item.getItemQuantity()).setPrice(item.getPrice()) + .setTotalPrice(item.getTotalPrice()).setRetailPrice(item.getRetailPrice()) + .setTotalRetailPrice(item.getTotalRetailPrice()).setBatchInventory(item.getBatchInventory()) + .setSpecificationInventory(item.getSpecificationInventory()).setStartTime(item.getStartTime()) + .setEndTime(item.getEndTime()).setLotNumber(item.getLotNumber()).setTraceNo(item.getTraceNo()) + .setTraceNoUnitCode(item.getTraceNoUnitCode()).setReason(item.getReason()) + .setPurposeTypeEnum(LocationForm.PHARMACY.getValue()).setPurposeLocationId(item.getPurposeLocationId()) + .setApplicantId(item.getApplicantId()).setApplyTime(applyTime).setRemake(item.getRemake()); + supplyRequestList.add(supplyRequest); + } + // 更新请求表 + boolean flg = supplyRequestService.saveOrUpdateBatch(supplyRequestList); + if (!flg) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00011, null)); + } + + return R.ok(MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryReceiptApprovalServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryReceiptApprovalServiceImpl.java new file mode 100644 index 000000000..985732b4a --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryReceiptApprovalServiceImpl.java @@ -0,0 +1,924 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice.impl; + +import tools.jackson.databind.JsonNode; +import tools.jackson.databind.node.ArrayNode; +import tools.jackson.databind.node.ObjectNode; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.core.common.core.domain.R; +import com.core.common.utils.DateUtils; +import com.core.common.utils.MessageUtils; +import com.core.common.utils.SecurityUtils; +import com.healthlink.his.common.constant.CommonConstants; +import com.healthlink.his.common.constant.PromptMsgConstant; +import com.healthlink.his.common.enums.DispenseStatus; +import com.healthlink.his.common.enums.SupplyType; +import com.healthlink.his.common.enums.TraceNoStatus; +import com.healthlink.his.common.enums.Whether; +import com.healthlink.his.yb.enums.YbInvChgType; +import com.healthlink.his.yb.enums.YbRxFlag; +import com.healthlink.his.medication.domain.MedicationDispense; +import com.healthlink.his.medication.service.IMedicationDispenseService; +import com.healthlink.his.web.inventorymanage.appservice.IReceiptApprovalAppService; +import com.healthlink.his.web.inventorymanage.appservice.ITraceNoAppService; +import com.healthlink.his.web.inventorymanage.assembler.InventoryManageAssembler; +import com.healthlink.his.web.inventorymanage.dto.ItemChargeDetailDto; +import com.healthlink.his.web.inventorymanage.dto.SupplyItemDetailDto; +import com.healthlink.his.web.inventorymanage.mapper.ReceiptApprovalMapper; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryReceiptApprovalService; +import com.healthlink.his.workflow.domain.DeviceDispense; +import com.healthlink.his.workflow.domain.InventoryItem; +import com.healthlink.his.workflow.domain.SupplyDelivery; +import com.healthlink.his.workflow.domain.SupplyRequest; +import com.healthlink.his.workflow.service.IDeviceDispenseService; +import com.healthlink.his.workflow.service.IInventoryItemService; +import com.healthlink.his.workflow.service.ISupplyDeliveryService; +import com.healthlink.his.workflow.service.ISupplyRequestService; +import com.healthlink.his.yb.dto.Medical3503Param; +import com.healthlink.his.yb.dto.MedicalInventory3501Param; +import com.healthlink.his.yb.dto.MedicalInventory3502Param; +import com.healthlink.his.yb.dto.MedicalPurchase3504Param; +import com.healthlink.his.yb.service.IYbManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 药房审批 + * + * @author yuxj + * @date 2025-07-22 + */ +@Service +public class PharmacyDispensaryReceiptApprovalServiceImpl implements IPharmacyDispensaryReceiptApprovalService { + @Autowired + private ITraceNoAppService traceNoAppService; + @Resource + private ISupplyRequestService supplyRequestService; + + @Autowired + private ISupplyDeliveryService supplyDeliveryService; + @Autowired + private IInventoryItemService inventoryItemService; + @Autowired + private ReceiptApprovalMapper receiptApprovalMapper; + @Autowired + private IYbManager ybService; + @Autowired + private IMedicationDispenseService medicationDispenseService; + @Autowired + private IDeviceDispenseService deviceDispenseService; + @Autowired + private IReceiptApprovalAppService receiptApprovalAppService; + + /** + * 请领单同意审批 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @Override + public R> requisitionOrderAgreeApproval(String busNo) { + // 获取当前时间 + Date now = DateUtils.getNowDate(); + // 审批单据并返回单据详情 + List agreedList = supplyRequestService.agreeRequest(busNo, now); + if (agreedList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + // // 获取审批通过后的供应请求id列表 + // List supplyReqIdList = agreedList.stream().map(SupplyRequest::getId).collect(Collectors.toList()); + // + // // 校验(已经审批通过的单号(发放状态是已完成),不能再重复审批通过) + // boolean validation = supplyDeliveryService.supplyDeliveryValidation(supplyReqIdList); + // if (validation) { + // throw new ServiceException("请勿重复审批"); + // } + // // 根据单据,生成供应发放单 + // List deliveredList = supplyDeliveryService.createCompletedSupplyDelivery(agreedList, now); + // if (deliveredList.isEmpty()) { + // return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + // } + + return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + } + + /** + * 药房入库单据审批通过 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @Override + public R> stockInOrderAgreeApproved(String busNo) { + // 获取当前时间 + Date now = DateUtils.getNowDate(); + // 审批单据并返回单据详情 + List agreedList = supplyRequestService.agreeRequest(busNo, now); + if (agreedList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + + // 根据单据,发放物品 + List deliveredList = supplyDeliveryService.createCompletedSupplyDelivery(agreedList, now); + if (deliveredList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + + // 查询供应项目的详细信息 + List supplyItemDetailList = this.getSupplyItemDetail(busNo); + // 返回信息 + String returnMsg = null; + if (!supplyItemDetailList.isEmpty()) { + InventoryItem inventoryItemPurpose = null; + // 新增库存信息 + List supplyList = new ArrayList<>(); + + for (SupplyItemDetailDto supplyItemDetailDto : supplyItemDetailList) { + // 根据项目id,产品批号,仓库id 查询仓库库存表信息 + List inventoryItemList = inventoryItemService.selectInventoryByItemId( + supplyItemDetailDto.getItemId(), supplyItemDetailDto.getLotNumber(), + supplyItemDetailDto.getPurposeLocationId(), SecurityUtils.getLoginUser().getTenantId()); + + if (!inventoryItemList.isEmpty()) { + inventoryItemPurpose = inventoryItemList.get(0); + } + + if (inventoryItemPurpose == null) { + // 新增库存信息 + supplyList.add(supplyItemDetailDto); + } else { + // 最小数量(最小单位库存数量) + BigDecimal minQuantity = inventoryItemPurpose.getQuantity(); + + // 计算盘点后库存数量,结果取小单位 + // 供应申请的物品计量单位与包装单位相同 + if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getUnitCode())) { + // 源仓库库存+(调拨数量*拆零比) + minQuantity = minQuantity + .add(supplyItemDetailDto.getPartPercent().multiply(supplyItemDetailDto.getItemQuantity())); + + } else if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getMinUnitCode())) { + // 供应申请的物品计量单位与最小单位相同 + // 源仓库库存+调拨数量 + minQuantity = minQuantity.add(supplyItemDetailDto.getItemQuantity()); + } + // 更新源仓库库存数量 + Boolean aBoolean = + inventoryItemService.updateInventoryQuantity(inventoryItemPurpose.getId(), minQuantity, now); + + if (!aBoolean) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + } + } + + if (!supplyList.isEmpty()) { + // 将供应项目的详细信息装配为库存项目 + List inventoryItemList = InventoryManageAssembler.assembleInventoryItem(supplyList); + // 入库 + inventoryItemService.stockIn(inventoryItemList); + } + + // 追加追溯码信息 + traceNoAppService.addTraceNoManage(supplyItemDetailList, TraceNoStatus.IN.getValue(), + SupplyType.PURCHASE_STOCKIN.getValue()); + + // 调用医保商品采购接口 todo 药房相关医保接口未对应 + String ybSwitch = SecurityUtils.getLoginUser().getOptionJsonValue(CommonConstants.Option.YB_SWITCH); // 医保开关 + if (Whether.YES.getCode().equals(ybSwitch)) { + List uploadFailedNoList = + this.ybInventoryIntegrated(supplyItemDetailList, YbInvChgType.PURCHASE_IN, false, true, false, now); + if (!uploadFailedNoList.isEmpty()) { + returnMsg = "3503商品采购上传错误,错误项目编码" + uploadFailedNoList; + } else { + returnMsg = "3503商品采购上传成功"; + } + } + } + return R.ok(returnMsg, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + } + + /** + * 药库退库审批通过 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @Override + public R> returnToWarehouseAgreeApproved(String busNo) { + // 获取当前时间 + Date now = DateUtils.getNowDate(); + // 审批单据并返回单据详情 + List agreedList = supplyRequestService.agreeRequest(busNo, now); + if (agreedList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + + // 根据单据,发放物品 + List deliveredList = supplyDeliveryService.createCompletedSupplyDelivery(agreedList, now); + if (deliveredList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + + // 查询供应项目的详细信息 + List supplyItemDetailList = this.getSupplyItemDetail(busNo); + // 返回信息 + String returnMsg = null; + if (!supplyItemDetailList.isEmpty()) { + for (SupplyItemDetailDto supplyItemDetailDto : supplyItemDetailList) { + // 根据项目id,产品批号,目的仓库id 查询仓库库存表信息 + List inventoryItemList = inventoryItemService.selectInventoryByItemId( + supplyItemDetailDto.getItemId(), supplyItemDetailDto.getLotNumber(), + supplyItemDetailDto.getSourceLocationId(), SecurityUtils.getLoginUser().getTenantId()); + InventoryItem inventoryItemSource; + if (!inventoryItemList.isEmpty()) { + inventoryItemSource = inventoryItemList.get(0); + // 最小数量(最小单位库存数量) + BigDecimal minQuantity = inventoryItemSource.getQuantity(); + + // 计算退货后库存数量,结果取小单位 + // 供应申请的物品计量单位与包装单位相同 + if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getUnitCode())) { + if (minQuantity.compareTo(supplyItemDetailDto.getItemQuantity()) < 0) { + // 库存数量不足 + return R.fail(MessageUtils.createMessage("操作失败,库存数量不足", null)); + } else { + // 仓库库存-(退货数量*拆零比) + minQuantity = minQuantity.subtract( + supplyItemDetailDto.getPartPercent().multiply(supplyItemDetailDto.getItemQuantity())); + } + } else if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getMinUnitCode())) { + if (minQuantity.compareTo(supplyItemDetailDto.getItemQuantity()) < 0) { + // 库存数量不足 + return R.fail(MessageUtils.createMessage("操作失败,库存数量不足", null)); + } else { + // 供应申请的物品计量单位与最小单位相同 + // 仓库库存-退货数量 + minQuantity = minQuantity.subtract(supplyItemDetailDto.getItemQuantity()); + } + } + // 更新仓库库存数量 + Boolean aBoolean = + inventoryItemService.updateInventoryQuantity(inventoryItemSource.getId(), minQuantity, now); + + if (!aBoolean) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + } + } + // 追加追溯码信息 + traceNoAppService.addTraceNoManage(supplyItemDetailList, TraceNoStatus.OUT.getValue(), + SupplyType.PURCHASE_RETURN.getValue()); + + // 调用医保采购退货接口 + String ybSwitch = SecurityUtils.getLoginUser().getOptionJsonValue(CommonConstants.Option.YB_SWITCH); // 医保开关 + if (Whether.YES.getCode().equals(ybSwitch)) { + List uploadFailedNoList = + this.ybInventoryIntegrated(supplyItemDetailList, YbInvChgType.RETURN_OUT, false, false, true, now); + if (!uploadFailedNoList.isEmpty()) { + returnMsg = "3504采购退货上传错误,错误项目编码" + uploadFailedNoList; + } + } + } + return R.ok(returnMsg, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + } + // + // /** + // * 药房发药审批通过 todo 发药只查询,没有审批 + // * + // * @param busNo 单据号 + // * @return 操作结果 + // */ + // @Override + // public R> dispensingAgreeApproved(String busNo) { + // // 获取当前时间 + // Date now = DateUtils.getNowDate(); + // // 审批单据并返回单据详情 + // List agreedList = supplyRequestService.agreeRequest(busNo, now); + // if (agreedList.isEmpty()) { + // return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + // } + // // 根据单据,发放物品 + // List deliveredList = supplyDeliveryService.createCompletedSupplyDelivery(agreedList, now); + // if (deliveredList.isEmpty()) { + // return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + // } + // + // // 查询供应项目的详细信息 + // List supplyItemDetailList = this.getSupplyItemDetail(busNo); + // + // if (!supplyItemDetailList.isEmpty()) { + // + // for (SupplyItemDetailDto supplyItemDetailDto : supplyItemDetailList) { + // // 根据项目id,产品批号,源仓库id 查询源仓库库存表信息 + // List inventoryItemSourceList = inventoryItemService.selectInventoryByItemId( + // supplyItemDetailDto.getItemId(), supplyItemDetailDto.getLotNumber(), + // supplyItemDetailDto.getSourceLocationId(), SecurityUtils.getLoginUser().getTenantId()); + // InventoryItem inventoryItemSource = new InventoryItem(); + // if (!inventoryItemSourceList.isEmpty()) { + // inventoryItemSource = inventoryItemSourceList.get(0); + // + // // 包装数量(常规单位库存数量) 更新库存数量方法中没用到 + // BigDecimal baseQuantitySource = inventoryItemSource.getQuantity(); + // // 最小数量(最小单位库存数量) + // BigDecimal minQuantitySource = inventoryItemSource.getQuantity(); + // + // // 供应申请的物品计量单位与包装单位相同 + // if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getUnitCode())) { + // if (minQuantitySource.compareTo(supplyItemDetailDto.getItemQuantity()) < 0) { + // // 库存数量不足 + // return R.fail(MessageUtils.createMessage("操作失败,库存数量不足", null)); + // } else { + // // 源仓库库存-(领用数量*拆零比) + // minQuantitySource = minQuantitySource.subtract( + // supplyItemDetailDto.getPartPercent().multiply(supplyItemDetailDto.getItemQuantity())); + // } + // } else if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getMinUnitCode())) { + // if (minQuantitySource.compareTo(supplyItemDetailDto.getItemQuantity()) < 0) { + // // 库存数量不足 + // return R.fail(MessageUtils.createMessage("操作失败,库存数量不足", null)); + // } else { + // // 供应申请的物品计量单位与最小单位相同 + // // 源仓库库存-领用数量 + // minQuantitySource = minQuantitySource.subtract(supplyItemDetailDto.getItemQuantity()); + // } + // } + // // 更新源仓库库存数量 + // Boolean aBooleanSource = inventoryItemService.updateInventoryQuantity(inventoryItemSource.getId(), + // baseQuantitySource, minQuantitySource, now, supplyItemDetailDto.getTraceNo()); + // + // if (!aBooleanSource) { + // return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + // } + // } + // } + // + // } + // return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + // } + + /** + * 药房损益单审批通过 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @Override + public R> profitLossAgreeApproved(String busNo) { + // 获取当前时间 + Date now = DateUtils.getNowDate(); + // 审批单据并返回单据详情 + List agreedList = supplyRequestService.agreeRequest(busNo, now); + if (agreedList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + // 根据单据,生成供应发放单 + List deliveredList = supplyDeliveryService.createCompletedSupplyDelivery(agreedList, now); + if (deliveredList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + // 返回信息 + String returnMsg = null; + // 查询供应项目的详细信息 + List supplyItemDetailList = this.getSupplyItemDetail(busNo); + if (!supplyItemDetailList.isEmpty()) { + + for (SupplyItemDetailDto supplyItemDetailDto : supplyItemDetailList) { + // 根据id,产品批号,仓库 查询库存表信息 + List inventoryItemList = inventoryItemService.selectInventoryByItemId( + supplyItemDetailDto.getItemId(), supplyItemDetailDto.getLotNumber(), + supplyItemDetailDto.getPurposeLocationId(), SecurityUtils.getLoginUser().getTenantId()); + InventoryItem inventoryItem = new InventoryItem(); + if (!inventoryItemList.isEmpty()) { + inventoryItem = inventoryItemList.get(0); + // 最小数量(最小单位库存数量) + BigDecimal minQuantity = null; + + // 计算报损后库存数量,结果取小单位 + // 供应申请的物品计量单位与包装单位相同 + if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getUnitCode())) { + // 数量*拆零比 + minQuantity = + supplyItemDetailDto.getPartPercent().multiply(supplyItemDetailDto.getItemQuantity()); + } else if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getMinUnitCode())) { + // 供应申请的物品计量单位与最小单位相同 + // 数量 + minQuantity = supplyItemDetailDto.getItemQuantity(); + } + // 更新库存数量 + Boolean aBoolean = + inventoryItemService.updateInventoryQuantity(inventoryItem.getId(), minQuantity, now); + if (!aBoolean) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + } + } + + // 追加追溯码信息 + boolean flg = + traceNoAppService.updateTraceNoList(supplyItemDetailList, SupplyType.PURCHASE_PRPFITLOSS.getValue()); + if (!flg) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + + // 调用医保库存变更接口 + String ybSwitch = SecurityUtils.getLoginUser().getOptionJsonValue(CommonConstants.Option.YB_SWITCH); // 医保开关 + if (Whether.YES.getCode().equals(ybSwitch)) { + List uploadFailedNoList = this.ybInventoryIntegrated(supplyItemDetailList, + YbInvChgType.DESTRUCTION, false, false, false, now); + if (!uploadFailedNoList.isEmpty()) { + returnMsg = "3502库存变更上传错误,错误项目编码" + uploadFailedNoList; + } + } + } + return R.ok(returnMsg, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + } + + /** + * 药房盘点单审批通过 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @Override + public R> stocktakingAgreepproved(String busNo) { + // 获取当前时间 + Date now = DateUtils.getNowDate(); + // 审批单据并返回单据详情 + List agreedList = supplyRequestService.agreeRequest(busNo, now); + if (agreedList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + // 根据单据,生成供应发放单 + List deliveredList = supplyDeliveryService.createCompletedSupplyDelivery(agreedList, now); + if (deliveredList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + + // 查询供应项目的详细信息 + List supplyItemDetailList = this.getSupplyItemDetail(busNo); + // 首次盘存列表 + List firstSupplyItemDetailList = new ArrayList<>(); + // 药品/耗材发放列表 + List medicationDispenses = null; + List deviceDispenses = null; + // 返回信息 + String stocktakingReturnMsg = null; + String changeReturnMsg = null; + if (!supplyItemDetailList.isEmpty()) { + // 获取盘盈列表(itemQuantity > 0) + List positiveList = supplyItemDetailList.stream() + .filter(item -> item.getItemQuantity() != null && item.getItemQuantity().compareTo(BigDecimal.ZERO) > 0) + .collect(Collectors.toList()); + // 获取盘亏列表(itemQuantity < 0) + List negativeList = supplyItemDetailList.stream() + .filter(item -> item.getItemQuantity() != null && item.getItemQuantity().compareTo(BigDecimal.ZERO) < 0) + .collect(Collectors.toList()); + + for (SupplyItemDetailDto supplyItemDetailDto : supplyItemDetailList) { + // 根据id,产品批号,仓库 查询库存表信息 + List inventoryItemList = inventoryItemService.selectInventoryByItemId( + supplyItemDetailDto.getItemId(), supplyItemDetailDto.getLotNumber(), + supplyItemDetailDto.getPurposeLocationId(), SecurityUtils.getLoginUser().getTenantId()); + // 查看该批号的药品/耗材是否发放过(用于证明是否首次盘存) + if (CommonConstants.TableName.MED_MEDICATION_DEFINITION.equals(supplyItemDetailDto.getItemTable())) { + medicationDispenses = medicationDispenseService.list(new LambdaQueryWrapper() + .eq(MedicationDispense::getLotNumber, supplyItemDetailDto.getLotNumber())); + if (medicationDispenses.isEmpty()) { + firstSupplyItemDetailList.add(supplyItemDetailDto); + } + } else if (CommonConstants.TableName.ADM_DEVICE_DEFINITION.equals(supplyItemDetailDto.getItemTable())) { + deviceDispenses = deviceDispenseService.list(new LambdaQueryWrapper() + .in(DeviceDispense::getLotNumber, supplyItemDetailDto.getLotNumber())); + if (deviceDispenses.isEmpty()) { + firstSupplyItemDetailList.add(supplyItemDetailDto); + } + } + if (!inventoryItemList.isEmpty()) { + InventoryItem inventoryItem = inventoryItemList.get(0); + // 包装数量(常规单位库存数量) 更新库存数量方法中没用到 + BigDecimal baseQuantity = inventoryItem.getQuantity(); + // 最小数量(最小单位库存数量) + BigDecimal minQuantity = null; + + // 计算盘点后库存数量,结果取小单位 + // 供应申请的物品计量单位与包装单位相同 + if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getUnitCode())) { + minQuantity = + supplyItemDetailDto.getPartPercent().multiply(supplyItemDetailDto.getTotalQuantity()); + // 供应申请的物品计量单位与最小单位相同 + } else if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getMinUnitCode())) { + minQuantity = supplyItemDetailDto.getTotalQuantity(); + } + // 更新库存数量 + Boolean aBoolean = + inventoryItemService.updateInventoryQuantity(inventoryItem.getId(), minQuantity, now); + if (!aBoolean) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + } + + String ybSwitch = + SecurityUtils.getLoginUser().getOptionJsonValue(CommonConstants.Option.YB_SWITCH); // 医保开关 + if (Whether.YES.getCode().equals(ybSwitch)) { + // 如果首次盘点信息不为空 + if (!firstSupplyItemDetailList.isEmpty()) { + // 调用医保盘存接口,盘盈 + List uploadFailedNoList = this.ybInventoryIntegrated(firstSupplyItemDetailList, + YbInvChgType.INVENTORY_GAIN, true, false, false, now); + if (!uploadFailedNoList.isEmpty()) { + stocktakingReturnMsg = "3501盘存上传错误,错误项目编码" + uploadFailedNoList; + } + } + List uploadFailedGainList = null; + List uploadFailedLossList = null; + if (!positiveList.isEmpty()) { + // 调用医保库存变更接口,盘盈 + uploadFailedGainList = this.ybInventoryIntegrated(positiveList, YbInvChgType.INVENTORY_GAIN, + false, false, false, now); + } + if (!negativeList.isEmpty()) { + // 调用医保库存变更接口,盘亏 + uploadFailedLossList = this.ybInventoryIntegrated(negativeList, YbInvChgType.INVENTORY_LOSS, + false, false, false, now); + } + if (uploadFailedGainList != null || uploadFailedLossList != null) { + changeReturnMsg = "3502库存变更上传错误,错误项目编码" + uploadFailedGainList + uploadFailedLossList; + } + } + } + // 追加追溯码信息 + boolean flg = + traceNoAppService.updateTraceNoList(supplyItemDetailList, SupplyType.PURCHASE_STOCKTAKING.getValue()); + if (!flg) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + } + return R.ok(stocktakingReturnMsg + changeReturnMsg, + MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + } + + /** + * 药房调入单审批通过 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @Override + public R> transferInAgreeApproved(String busNo) { + // 获取当前时间 + Date now = DateUtils.getNowDate(); + // 审批单据并返回单据详情 + List agreedList = supplyRequestService.agreeRequest(busNo, now); + if (agreedList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + // 根据单据,发放物品 + List deliveredList = supplyDeliveryService.createCompletedSupplyDelivery(agreedList, now); + if (deliveredList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + + // 查询供应项目的详细信息 + List supplyItemDetailList = this.getSupplyItemDetail(busNo); + + if (!supplyItemDetailList.isEmpty()) { + + // 新增库存信息 + List supplylList = new ArrayList<>(); + + for (SupplyItemDetailDto supplyItemDetailDto : supplyItemDetailList) { + // 根据项目id,产品批号,目的仓库id 查询目的仓库库存表信息 + List inventoryItemPurposeList = inventoryItemService.selectInventoryByItemId( + supplyItemDetailDto.getItemId(), supplyItemDetailDto.getLotNumber(), + supplyItemDetailDto.getPurposeLocationId(), SecurityUtils.getLoginUser().getTenantId()); + InventoryItem inventoryItemPurpose = null; + if (!inventoryItemPurposeList.isEmpty()) { + inventoryItemPurpose = inventoryItemPurposeList.get(0); + } + + if (inventoryItemPurpose == null) { + // 新增库存信息 + supplylList.add(supplyItemDetailDto); + } else { + // 包装数量(常规单位库存数量) 更新库存数量方法中没用到 + BigDecimal baseQuantity = inventoryItemPurpose.getQuantity(); + // 最小数量(最小单位库存数量) + BigDecimal minQuantity = inventoryItemPurpose.getQuantity(); + + // 计算盘点后库存数量,结果取小单位 + // 供应申请的物品计量单位与包装单位相同 + if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getUnitCode())) { + // 源仓库库存+(退库数量*拆零比) + minQuantity = minQuantity + .add(supplyItemDetailDto.getPartPercent().multiply(supplyItemDetailDto.getItemQuantity())); + } else if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getMinUnitCode())) { + // 供应申请的物品计量单位与最小单位相同 + // 源仓库库存+退库数量 + minQuantity = minQuantity.add(supplyItemDetailDto.getItemQuantity()); + } + // 更新目的仓库库存数量 + Boolean bBooleanPurpose = + inventoryItemService.updateInventoryQuantity(inventoryItemPurpose.getId(), minQuantity, now); + if (!bBooleanPurpose) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + } + } + if (!supplylList.isEmpty()) { + // 将供应项目的详细信息装配为库存项目 + List inventoryItemList = InventoryManageAssembler.assembleInventoryItem(supplylList); + // 入库 + inventoryItemService.stockIn(inventoryItemList); + } + // 追加追溯码信息 + traceNoAppService.addTraceNoManage(supplyItemDetailList, TraceNoStatus.IN.getValue(), + SupplyType.PURCHASE_TRANSFERIN.getValue()); + + } + return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + + } + + /** + * 药房调出单审批通过 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @Override + public R> transferOutAgreeApproved(String busNo) { + // 获取当前时间 + Date now = DateUtils.getNowDate(); + // 审批单据并返回单据详情 + List agreedList = supplyRequestService.agreeRequest(busNo, now); + if (agreedList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + // 根据单据,发放物品 + List deliveredList = supplyDeliveryService.createCompletedSupplyDelivery(agreedList, now); + if (deliveredList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + + // 查询供应项目的详细信息 + List supplyItemDetailList = this.getSupplyItemDetail(busNo); + + if (!supplyItemDetailList.isEmpty()) { + for (SupplyItemDetailDto supplyItemDetailDto : supplyItemDetailList) { + // 根据项目id,产品批号,目的仓库id 查询目的仓库库存表信息 + List inventoryItemSourceList = inventoryItemService.selectInventoryByItemId( + supplyItemDetailDto.getItemId(), supplyItemDetailDto.getLotNumber(), + supplyItemDetailDto.getSourceLocationId(), SecurityUtils.getLoginUser().getTenantId()); + InventoryItem inventoryItemSource = null; + if (!inventoryItemSourceList.isEmpty()) { + inventoryItemSource = inventoryItemSourceList.get(0); + + // 包装数量(常规单位库存数量) 更新库存数量方法中没用到 + BigDecimal baseQuantity = inventoryItemSource.getQuantity(); + // 最小数量(最小单位库存数量) + BigDecimal minQuantity = inventoryItemSource.getQuantity(); + + // 计算盘点后库存数量,结果取小单位 + // 供应申请的物品计量单位与包装单位相同 + if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getUnitCode())) { + if (minQuantity.compareTo(supplyItemDetailDto.getItemQuantity()) < 0) { + // 库存数量不足 + return R.fail(MessageUtils.createMessage("操作失败,库存数量不足", null)); + } else { + // 源仓库库存-(退库数量*拆零比) + minQuantity = minQuantity.subtract( + supplyItemDetailDto.getPartPercent().multiply(supplyItemDetailDto.getItemQuantity())); + } + } else if (supplyItemDetailDto.getItemUnit().equals(supplyItemDetailDto.getMinUnitCode())) { + if (minQuantity.compareTo(supplyItemDetailDto.getItemQuantity()) < 0) { + // 库存数量不足 + return R.fail(MessageUtils.createMessage("操作失败,库存数量不足", null)); + } else { + // 供应申请的物品计量单位与最小单位相同 + // 源仓库库存-退库数量 + minQuantity = minQuantity.subtract(supplyItemDetailDto.getItemQuantity()); + } + } + // 更新目的仓库库存数量 + Boolean bBooleanSource = + inventoryItemService.updateInventoryQuantity(inventoryItemSource.getId(), minQuantity, now); + if (!bBooleanSource) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + } + } + // 追加追溯码信息 + traceNoAppService.addTraceNoManage(supplyItemDetailList, TraceNoStatus.OUT.getValue(), + SupplyType.PURCHASE_TRANSFEROUT.getValue()); + + } + return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + + } + + /** + * 根据单据号获取供应单据及供应项相关详细信息 + * + * @param busNo 单据号 + * @return 供应单据及供应项相关详细信息 + */ + @Override + public List getSupplyItemDetail(String busNo) { + return receiptApprovalMapper.selectSupplyDetail(busNo, DispenseStatus.COMPLETED.getValue()); + } + + /** + * 医保库存相关进销存接口 + * + * @param supplyItemDetailList 供应申请项目详细信息 + * @param ybInvChgType 库存变更类型 + * @param firstFlag 首次盘存标识 + * @param now 库存变更时间 + * @return 上传失败的id集合 + */ + private List ybInventoryIntegrated(List supplyItemDetailList, + YbInvChgType ybInvChgType, Boolean firstFlag, Boolean purchaseFlag, Boolean returnFlag, Date now) { + List uploadFailedNoList = new ArrayList<>(); + R> result; + R> firstResult = R.ok(); + R> returnResult = R.ok(); + R> purchaseResult = R.ok(); + for (SupplyItemDetailDto supplyItemDetailDto : supplyItemDetailList) { + if (supplyItemDetailDto.getYbNo() == null) { + continue; + } + switch (ybInvChgType) { + case ALLOCATION_IN: + case ALLOCATION_OUT: + case INVENTORY_GAIN: + case INVENTORY_LOSS: + case DESTRUCTION: + case OTHER_IN: + case OTHER_OUT: + case DONATION_IN: + case DONATION_RETURN_OUT: + case PURCHASE_IN: + case RETURN_OUT: + if (firstFlag) { + firstResult = + ybService.uploadInventoryCount(getMedicalInventory3501Param(supplyItemDetailDto, now), now); + if (firstResult.getCode() != 200) { + uploadFailedNoList.add(supplyItemDetailDto.getItemBusNo()); + } + } + if (returnFlag) { + returnResult = + ybService.cancelProcurement(getMedicalPurchase3504Param(supplyItemDetailDto, now)); + if (returnResult.getCode() != 200) { + uploadFailedNoList.add(supplyItemDetailDto.getItemBusNo()); + } + } + if (purchaseFlag) { + purchaseResult = ybService.procurement(getMedical3503Param(supplyItemDetailDto, now)); + if (purchaseResult.getCode() != 200) { + uploadFailedNoList.add(supplyItemDetailDto.getItemBusNo()); + } + } + result = ybService.updateInventoryCount( + getMedicalInventory3502Param(supplyItemDetailDto, now, ybInvChgType.getValue())); + if (result.getCode() != 200) { + uploadFailedNoList.add(supplyItemDetailDto.getItemBusNo()); + } + break; + default: + throw new IllegalArgumentException("未知的库存变更类型: " + ybInvChgType); + } + } + return uploadFailedNoList; + } + + private MedicalPurchase3504Param getMedicalPurchase3504Param(SupplyItemDetailDto supplyItemDetailDto, Date now) { + MedicalPurchase3504Param medicalPurchase3504Param = new MedicalPurchase3504Param(); + medicalPurchase3504Param.setMedListCodg(supplyItemDetailDto.getYbNo()) + .setFixmedinsBchno(supplyItemDetailDto.getLotNumber()) + .setFixmedinsHilistId(supplyItemDetailDto.getItemBusNo()) + .setFixmedinsHilistName(supplyItemDetailDto.getItemTable()) + .setSplerName(supplyItemDetailDto.getSupplierName()).setPurcInvoNo(supplyItemDetailDto.getInvoiceNo()) + .setManuDate(supplyItemDetailDto.getStartTime()).setExpyEnd(supplyItemDetailDto.getEndTime()) + .setPurcRetnCnt(supplyItemDetailDto.getItemQuantity()).setPurcRetnStoinTime(now) + .setPurcRetnOpterName(supplyItemDetailDto.getPractitionerName()); + if (YbRxFlag.IMPORTANT_HERBAL_SLICES.getCode() == supplyItemDetailDto.getRxFlag()) { + medicalPurchase3504Param.setRxFlag(YbRxFlag.IMPORTANT_HERBAL_SLICES.getName()); + } else if (YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getCode() == supplyItemDetailDto.getRxFlag()) { + medicalPurchase3504Param.setRxFlag(YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getName()); + } else if (YbRxFlag.SELF_PREPARED_MEDICATION.getCode() == supplyItemDetailDto.getRxFlag()) { + medicalPurchase3504Param.setRxFlag(YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getName()); + } + return medicalPurchase3504Param; + } + + private Medical3503Param getMedical3503Param(SupplyItemDetailDto supplyItemDetailDto, Date now) { + Medical3503Param medical3503Param = new Medical3503Param(); + medical3503Param.setMedListCodg(supplyItemDetailDto.getYbNo()) + .setFixmedinsBchno(supplyItemDetailDto.getLotNumber()) + .setFixmedinsHilistId(supplyItemDetailDto.getItemBusNo()) + .setFixmedinsHilistName(supplyItemDetailDto.getItemTable()) + .setSplerName(supplyItemDetailDto.getSupplierName()).setManuLotnum(supplyItemDetailDto.getLotNumber()) + .setProdentpName(supplyItemDetailDto.getManufacturerText()) + .setAprvno(supplyItemDetailDto.getApprovalNumber()).setManuDate(supplyItemDetailDto.getStartTime()) + .setExpyEnd(supplyItemDetailDto.getEndTime()).setPurcRetnCnt(supplyItemDetailDto.getItemQuantity()) + .setPurcRetnStoinTime(now).setPurcRetnOpterName(supplyItemDetailDto.getPractitionerName()); + if (YbRxFlag.IMPORTANT_HERBAL_SLICES.getCode() == supplyItemDetailDto.getRxFlag()) { + medical3503Param.setRxFlag(YbRxFlag.IMPORTANT_HERBAL_SLICES.getName()); + } else if (YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getCode() == supplyItemDetailDto.getRxFlag()) { + medical3503Param.setRxFlag(YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getName()); + } else if (YbRxFlag.SELF_PREPARED_MEDICATION.getCode() == supplyItemDetailDto.getRxFlag()) { + medical3503Param.setRxFlag(YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getName()); + } + + return medical3503Param; + } + + private MedicalInventory3502Param getMedicalInventory3502Param(SupplyItemDetailDto supplyItemDetailDto, Date now, + String ybInvChgType) { + MedicalInventory3502Param medicalInventory3502Param = new MedicalInventory3502Param(); + // 查库存信息 + List inventoryItemList = + inventoryItemService.selectInventoryByItemId(supplyItemDetailDto.getItemId(), + supplyItemDetailDto.getLotNumber(), null, SecurityUtils.getLoginUser().getTenantId()); + // 查询商品价格信息 + List itemChargeDetailList = + receiptApprovalAppService.getItemChargeDetail(List.of(supplyItemDetailDto.getItemId())); + if (!inventoryItemList.isEmpty() && !itemChargeDetailList.isEmpty()) { + // 获取该项目所有的数量(最小单位) + BigDecimal totalQuantity = inventoryItemList.stream() + .map(item -> item.getQuantity() != null ? item.getQuantity() : BigDecimal.ZERO) + .reduce(BigDecimal.ZERO, BigDecimal::add); + // 最小单位售卖价格 + BigDecimal minPrice = BigDecimal.ZERO; + Optional price = itemChargeDetailList.stream() + .filter(x -> x.getConditionValue().equals(supplyItemDetailDto.getLotNumber())) + .map(ItemChargeDetailDto::getSellPrice).findFirst(); + if (price.isPresent()) { + if (supplyItemDetailDto.getPartPercent().compareTo(BigDecimal.ZERO) > 0) { + minPrice = price.get().divide(supplyItemDetailDto.getPartPercent(), RoundingMode.HALF_UP); + } + } + // 转换为JSON + ArrayNode medicalTraceNo = new tools.jackson.databind.ObjectMapper().createArrayNode(); + // 获取追溯码信息 + if (supplyItemDetailDto.getTraceNo() != null) { + List traceNoList = + Arrays.stream(supplyItemDetailDto.getTraceNo().split(CommonConstants.Common.COMMA)) + .map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList()); + for (String traceNo : traceNoList) { + ObjectNode traceNoMap = new tools.jackson.databind.ObjectMapper().createObjectNode(); + traceNoMap.put("drug_trac_codg", traceNo); + medicalTraceNo.add(traceNoMap); + } + } + medicalInventory3502Param.setMedListCodg(supplyItemDetailDto.getYbNo()).setInvChgType(ybInvChgType) + .setFixmedinsHilistId(supplyItemDetailDto.getItemBusNo()) + .setFixmedinsHilistName(supplyItemDetailDto.getItemTable()) + .setFixmedinsBchno(supplyItemDetailDto.getLotNumber()).setPric(minPrice).setCnt(totalQuantity) + .setInvChgTime(now).setDrugtracinfo(medicalTraceNo); + if (YbRxFlag.IMPORTANT_HERBAL_SLICES.getCode() == supplyItemDetailDto.getRxFlag()) { + medicalInventory3502Param.setRxFlag(YbRxFlag.IMPORTANT_HERBAL_SLICES.getName()); + } else if (YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getCode() == supplyItemDetailDto.getRxFlag()) { + medicalInventory3502Param.setRxFlag(YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getName()); + } else if (YbRxFlag.SELF_PREPARED_MEDICATION.getCode() == supplyItemDetailDto.getRxFlag()) { + medicalInventory3502Param.setRxFlag(YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getName()); + } + } + return medicalInventory3502Param; + } + + private MedicalInventory3501Param getMedicalInventory3501Param(SupplyItemDetailDto supplyItemDetailDto, Date date) { + MedicalInventory3501Param medicalInventory3501Param = new MedicalInventory3501Param(); + // 查库存信息 + List inventoryItemList = + inventoryItemService.selectInventoryByItemId(supplyItemDetailDto.getItemId(), + supplyItemDetailDto.getLotNumber(), null, SecurityUtils.getLoginUser().getTenantId()); + if (!inventoryItemList.isEmpty()) { + // 获取该项目所有的数量(最小单位) + BigDecimal totalQuantity = inventoryItemList.stream() + .map(item -> item.getQuantity() != null ? item.getQuantity() : BigDecimal.ZERO) + .reduce(BigDecimal.ZERO, BigDecimal::add); + medicalInventory3501Param.setMedListCodg(supplyItemDetailDto.getYbNo()) + .setFixmedinsHilistId(supplyItemDetailDto.getItemBusNo()) + .setFixmedinsHilistName(supplyItemDetailDto.getItemTable()).setInvdate(date).setInvCnt(totalQuantity) + .setFixmedinsBchno(supplyItemDetailDto.getLotNumber()).setManuDate(supplyItemDetailDto.getStartTime()) + .setExpyEnd(supplyItemDetailDto.getEndTime()); + if (YbRxFlag.IMPORTANT_HERBAL_SLICES.getCode() == supplyItemDetailDto.getRxFlag()) { + medicalInventory3501Param.setRxFlag(YbRxFlag.IMPORTANT_HERBAL_SLICES.getName()); + } else if (YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getCode() == supplyItemDetailDto.getRxFlag()) { + medicalInventory3501Param.setRxFlag(YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getName()); + } else if (YbRxFlag.SELF_PREPARED_MEDICATION.getCode() == supplyItemDetailDto.getRxFlag()) { + medicalInventory3501Param.setRxFlag(YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getName()); + } + } + return medicalInventory3501Param; + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryRequisitionOrderServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryRequisitionOrderServiceImpl.java new file mode 100644 index 000000000..0846fce6a --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryRequisitionOrderServiceImpl.java @@ -0,0 +1,163 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.core.common.core.domain.R; +import com.core.common.utils.AssignSeqUtil; +import com.core.common.utils.MessageUtils; +import com.healthlink.his.common.constant.CommonConstants; +import com.healthlink.his.common.constant.PromptMsgConstant; +import com.healthlink.his.common.enums.*; +import com.healthlink.his.common.utils.EnumUtils; +import com.healthlink.his.web.inventorymanage.dto.ProductStocktakingInitDto; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryRequisitionOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryInitDto; +import com.healthlink.his.web.pharmacy.dispensary.mapper.PharmacyDispensaryCommonMapper; +import com.healthlink.his.workflow.domain.SupplyRequest; +import com.healthlink.his.workflow.service.ISupplyRequestService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 药房请领单 + * + * @author yuxj + * @date 2025-07-22 + */ +@Service +public class PharmacyDispensaryRequisitionOrderServiceImpl implements IPharmacyDispensaryRequisitionOrderService { + + @Resource + private AssignSeqUtil assignSeqUtil; + + @Resource + private ISupplyRequestService supplyRequestService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + + @Autowired + private PharmacyDispensaryCommonMapper pharmacyDispensaryCommonMapper; + + /** + * 初始化 + * + * @return 初始化信息 + */ + @Override + public R> init() { + + PharmacyDispensaryInitDto requisitionOrderInitDto = pharmacyDispensaryCommonService.init(); + + // 单据分类 + List supplyCategoryOption = new ArrayList<>(); + // supplyCategoryOption.add(new PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.NORMAL.getValue(), + // SupplyCategory.NORMAL.getInfo())); + // supplyCategoryOption.add(new + // PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.PURCHASE_APPLICATION.getValue(), + // SupplyCategory.PURCHASE_APPLICATION.getInfo())); + + requisitionOrderInitDto.setSupplyCategoryOptions(supplyCategoryOption); + + return R.ok(requisitionOrderInitDto); + } + + /** + * 请领单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 请领单单据详情 + */ + @Override + public R> getDetailPage(String busNo, Integer pageNo, Integer pageSize) { + + Page requisitionOrderDtoDetailPage = + pharmacyDispensaryCommonMapper.getDetailPage(new Page<>(pageNo, pageSize), busNo); + + requisitionOrderDtoDetailPage.getRecords().forEach(e -> { + // 单据分类 + e.setCategoryEnum_enumText(EnumUtils.getInfoByValue(SupplyCategory.class, e.getCategoryEnum())); + // 单据状态 + e.setStatusEnum_enumText(EnumUtils.getInfoByValue(SupplyStatus.class, e.getStatusEnum())); + // 单据类型 + e.setTypeEnum_enumText(EnumUtils.getInfoByValue(SupplyType.class, e.getTypeEnum())); + }); + + List unitList; + for (PharmacyDispensaryDetailDto item : requisitionOrderDtoDetailPage.getRecords()) { + unitList = new ArrayList<>(); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMaxUnitCode(), item.getMaxUnitCode_dictText())); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMinUnitCode(), item.getMinUnitCode_dictText())); + + item.setUnitList(unitList); + } + + return R.ok(requisitionOrderDtoDetailPage); + } + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @Override + public R> getBusNo() { + + ProductStocktakingInitDto initDto = new ProductStocktakingInitDto(); + // 单据号 + initDto.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.PURCHASE_REQUISITION.getPrefix(), 4)); + + return R.ok(initDto); + } + + /** + * 添加/编辑请领单 + * + * @param requisitionOrderDtoList 请领信息 + * @return 操作结果 + */ + + @Override + public R> addOrEditRequisitionOrder(List requisitionOrderDtoList) { + // 请求数据取得 + List requestList = + supplyRequestService.getSupplyByBusNo(requisitionOrderDtoList.get(0).getBusNo()); + if (!requestList.isEmpty()) { + // 请求id取得 + List requestIdList = requestList.stream().map(SupplyRequest::getId).collect(Collectors.toList()); + // 单据信息删除 + supplyRequestService.removeByIds(requestIdList); + } + + List supplyRequestList = new ArrayList<>(); + for (PharmacyDispensaryDetailDto item : requisitionOrderDtoList) { + SupplyRequest supplyRequest = new SupplyRequest().setBusNo(item.getBusNo()) + .setTypeEnum(SupplyType.PURCHASE_REQUISITION.getValue()) + .setStatusEnum(SupplyStatus.PENDING_REVIEW.getValue()).setCategoryEnum(item.getCategoryEnum()) + .setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION).setItemId(item.getItemId()) + .setUnitCode(item.getUnitCode()).setItemQuantity(item.getItemQuantity()) + .setRetailPrice(item.getRetailPrice()).setTotalRetailPrice(item.getTotalRetailPrice()) + .setSpecificationInventory(item.getSpecificationInventory()).setSupplierId(item.getSupplierId()) + .setReason(item.getReason()).setSourceTypeEnum(LocationForm.CABINET.getValue()) + .setSourceLocationId(item.getSourceLocationId()).setPurposeTypeEnum(LocationForm.PHARMACY.getValue()) + .setPurposeLocationId(item.getPurposeLocationId()).setApplicantId(item.getApplicantId()) + .setApplyTime(item.getApplyTime()).setRemake(item.getRemake()); + supplyRequestList.add(supplyRequest); + } + // 更新请求表 + boolean flg = supplyRequestService.saveOrUpdateBatch(supplyRequestList); + if (!flg) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00011, null)); + } + + return R.ok(MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryReturnToWarehouseOrderServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryReturnToWarehouseOrderServiceImpl.java new file mode 100644 index 000000000..8a650dddb --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryReturnToWarehouseOrderServiceImpl.java @@ -0,0 +1,164 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.core.common.core.domain.R; +import com.core.common.utils.AssignSeqUtil; +import com.core.common.utils.DateUtils; +import com.core.common.utils.MessageUtils; +import com.healthlink.his.common.constant.CommonConstants; +import com.healthlink.his.common.constant.PromptMsgConstant; +import com.healthlink.his.common.enums.*; +import com.healthlink.his.common.utils.EnumUtils; +import com.healthlink.his.web.inventorymanage.dto.ProductStocktakingInitDto; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryReturnToWarehouseOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryInitDto; +import com.healthlink.his.web.pharmacy.dispensary.mapper.PharmacyDispensaryCommonMapper; +import com.healthlink.his.workflow.domain.SupplyRequest; +import com.healthlink.his.workflow.service.ISupplyRequestService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 药房退库单 + * + * @author yuxj + * @date 2025-07-22 + */ +@Service +public class PharmacyDispensaryReturnToWarehouseOrderServiceImpl + implements IPharmacyDispensaryReturnToWarehouseOrderService { + + @Resource + private AssignSeqUtil assignSeqUtil; + + @Resource + private ISupplyRequestService supplyRequestService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + @Autowired + private PharmacyDispensaryCommonMapper pharmacyDispensaryCommonMapper; + + /** + * 初始化 + * + * @return 初始化信息 + */ + @Override + public R> init() { + + PharmacyDispensaryInitDto purchaseOrderInitDto = pharmacyDispensaryCommonService.init(); + + // 单据分类 + List supplyCategoryOption = new ArrayList<>(); + // supplyCategoryOption.add(new PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.NORMAL.getValue(), + // SupplyCategory.NORMAL.getInfo())); + + purchaseOrderInitDto.setSupplyCategoryOptions(supplyCategoryOption); + + return R.ok(purchaseOrderInitDto); + } + + /** + * 退库单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 退库单单据详情 + */ + @Override + public R> getDetailPage(String busNo, Integer pageNo, Integer pageSize) { + + Page returnToDispensaryOrderDtoDetailPage = + pharmacyDispensaryCommonMapper.getDetailPage(new Page<>(pageNo, pageSize), busNo); + + returnToDispensaryOrderDtoDetailPage.getRecords().forEach(e -> { + // 单据分类 + e.setCategoryEnum_enumText(EnumUtils.getInfoByValue(SupplyCategory.class, e.getCategoryEnum())); + // 单据状态 + e.setStatusEnum_enumText(EnumUtils.getInfoByValue(SupplyStatus.class, e.getStatusEnum())); + // 单据类型 + e.setTypeEnum_enumText(EnumUtils.getInfoByValue(SupplyType.class, e.getTypeEnum())); + }); + + List unitList; + for (PharmacyDispensaryDetailDto item : returnToDispensaryOrderDtoDetailPage.getRecords()) { + unitList = new ArrayList<>(); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMaxUnitCode(), item.getMaxUnitCode_dictText())); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMinUnitCode(), item.getMinUnitCode_dictText())); + + item.setUnitList(unitList); + } + return R.ok(returnToDispensaryOrderDtoDetailPage); + } + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @Override + public R> getBusNo() { + + ProductStocktakingInitDto initDto = new ProductStocktakingInitDto(); + // 单据号 + initDto.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.PURCHASE_RETURN.getPrefix(), 4)); + + return R.ok(initDto); + } + + /** + * 添加/编辑退库单 + * + * @param returnToDispensaryOrderDtoList 退库信息 + * @return 操作结果 + */ + + @Override + public R> addOrEditReturnToWarehouseOrder(List returnToDispensaryOrderDtoList) { + // 请求数据取得 + List requestList = + supplyRequestService.getSupplyByBusNo(returnToDispensaryOrderDtoList.get(0).getBusNo()); + if (!requestList.isEmpty()) { + // 请求id取得 + List requestIdList = requestList.stream().map(SupplyRequest::getId).collect(Collectors.toList()); + // 单据信息删除 + supplyRequestService.removeByIds(requestIdList); + } + + List supplyRequestList = new ArrayList<>(); + Date applyTime = DateUtils.getNowDate(); + for (PharmacyDispensaryDetailDto item : returnToDispensaryOrderDtoList) { + SupplyRequest supplyRequest = new SupplyRequest().setBusNo(item.getBusNo()) + .setTypeEnum(SupplyType.PURCHASE_RETURN.getValue()) + .setStatusEnum(SupplyStatus.PENDING_REVIEW.getValue()).setCategoryEnum(item.getCategoryEnum()) + .setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION).setItemId(item.getItemId()) + .setUnitCode(item.getUnitCode()).setItemQuantity(item.getItemQuantity()) + .setRetailPrice(item.getRetailPrice()).setTotalRetailPrice(item.getTotalRetailPrice()) + .setStartTime(item.getStartTime()).setEndTime(item.getEndTime()).setLotNumber(item.getLotNumber()) + .setTraceNo(item.getTraceNo()).setTraceNoUnitCode(item.getTraceNoUnitCode()) + .setSupplierId(item.getSupplierId()).setReason(item.getReason()) + .setSourceTypeEnum(LocationForm.PHARMACY.getValue()).setSourceLocationId(item.getSourceLocationId()) + .setPurposeTypeEnum(LocationForm.CABINET.getValue()).setPurposeLocationId(item.getPurposeLocationId()) + .setApplicantId(item.getApplicantId()).setApplyTime(applyTime).setRemake(item.getRemake()); + supplyRequestList.add(supplyRequest); + } + // 更新请求表 + boolean flg = supplyRequestService.saveOrUpdateBatch(supplyRequestList); + if (!flg) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00011, null)); + } + + return R.ok(MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryStockInOrderServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryStockInOrderServiceImpl.java new file mode 100644 index 000000000..e78ed4521 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryStockInOrderServiceImpl.java @@ -0,0 +1,170 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.core.common.core.domain.R; +import com.core.common.utils.AssignSeqUtil; +import com.core.common.utils.DateUtils; +import com.core.common.utils.MessageUtils; +import com.healthlink.his.common.constant.CommonConstants; +import com.healthlink.his.common.constant.PromptMsgConstant; +import com.healthlink.his.common.enums.*; +import com.healthlink.his.common.utils.EnumUtils; +import com.healthlink.his.web.inventorymanage.dto.ProductStocktakingInitDto; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryStockInOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryInitDto; +import com.healthlink.his.web.pharmacy.dispensary.mapper.PharmacyDispensaryCommonMapper; +import com.healthlink.his.workflow.domain.SupplyRequest; +import com.healthlink.his.workflow.service.ISupplyRequestService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 药房入库单 + * + * @author yuxj + * @date 2025-07-22 + */ +@Service +public class PharmacyDispensaryStockInOrderServiceImpl implements IPharmacyDispensaryStockInOrderService { + + @Resource + private AssignSeqUtil assignSeqUtil; + + @Resource + private ISupplyRequestService supplyRequestService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + @Autowired + private PharmacyDispensaryCommonMapper pharmacyDispensaryCommonMapper; + + /** + * 初始化 + * + * @return 初始化信息 + */ + @Override + public R> init() { + + PharmacyDispensaryInitDto purchaseOrderInitDto = pharmacyDispensaryCommonService.init(); + + // 单据分类 + List supplyCategoryOption = new ArrayList<>(); +// supplyCategoryOption.add(new PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.NORMAL.getValue(), +// SupplyCategory.NORMAL.getInfo())); + + purchaseOrderInitDto.setSupplyCategoryOptions(supplyCategoryOption); + + return R.ok(purchaseOrderInitDto); + } + + /** + * 入库单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 入库单单据详情 + */ + @Override + public R> getDetailPage(String busNo, Integer pageNo, Integer pageSize) { + + Page stockInOrderDtoDetailPage = + pharmacyDispensaryCommonMapper.getDetailPage(new Page<>(pageNo, pageSize), busNo); + + stockInOrderDtoDetailPage.getRecords().forEach(e -> { + // 单据分类 + e.setCategoryEnum_enumText(EnumUtils.getInfoByValue(SupplyCategory.class, e.getCategoryEnum())); + // 单据状态 + e.setStatusEnum_enumText(EnumUtils.getInfoByValue(SupplyStatus.class, e.getStatusEnum())); + // 单据类型 + e.setTypeEnum_enumText(EnumUtils.getInfoByValue(SupplyType.class, e.getTypeEnum())); + }); + + List unitList; + for (PharmacyDispensaryDetailDto item : stockInOrderDtoDetailPage.getRecords()) { + unitList = new ArrayList<>(); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMaxUnitCode(), item.getMaxUnitCode_dictText())); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMinUnitCode(), item.getMinUnitCode_dictText())); + + item.setUnitList(unitList); + } + return R.ok(stockInOrderDtoDetailPage); + } + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @Override + public R> getBusNo() { + + ProductStocktakingInitDto initDto = new ProductStocktakingInitDto(); + // 单据号 + initDto.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.PURCHASE_STOCKIN.getPrefix(), 4)); + + return R.ok(initDto); + } + + /** + * 添加/编辑入库单 + * + * @param stockInOrderDtoList 入库信息 + * @return 操作结果 + */ + + @Override + public R> addOrEditStockInOrder(List stockInOrderDtoList) { + // 请求数据取得 + List requestList = supplyRequestService.getSupplyByBusNo(stockInOrderDtoList.get(0).getBusNo()); + if (!requestList.isEmpty()) { + // 请求id取得 + List requestIdList = requestList.stream().map(SupplyRequest::getId).collect(Collectors.toList()); + // 单据信息删除 + supplyRequestService.removeByIds(requestIdList); + } + //添加原始单据号 + if(stockInOrderDtoList.get(0).getOriginalBusNo()!=null){ + // 审批单据并返回单据详情 + List agreedList = supplyRequestService.addOriginalBusNo(stockInOrderDtoList.get(0).getOriginalBusNo(), stockInOrderDtoList.get(0).getBusNo()); + if (agreedList.isEmpty()) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + } + } + + List supplyRequestList = new ArrayList<>(); + Date applyTime = DateUtils.getNowDate(); + for (PharmacyDispensaryDetailDto item : stockInOrderDtoList) { + SupplyRequest supplyRequest = new SupplyRequest().setBusNo(item.getBusNo()) + .setTypeEnum(SupplyType.PURCHASE_STOCKIN.getValue()) + .setStatusEnum(SupplyStatus.PENDING_REVIEW.getValue()).setCategoryEnum(item.getCategoryEnum()) + .setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION).setItemId(item.getItemId()) + .setUnitCode(item.getUnitCode()).setItemQuantity(item.getItemQuantity()) + .setRetailPrice(item.getRetailPrice()).setTotalRetailPrice(item.getTotalRetailPrice()) + .setStartTime(item.getStartTime()).setEndTime(item.getEndTime()).setLotNumber(item.getLotNumber()) + .setTraceNo(item.getTraceNo()).setTraceNoUnitCode(item.getTraceNoUnitCode()) + .setSupplierId(item.getSupplierId()).setReason(item.getReason()) + .setSourceTypeEnum(LocationForm.CABINET.getValue()).setSourceLocationId(item.getSourceLocationId()) + .setPurposeTypeEnum(LocationForm.PHARMACY.getValue()).setPurposeLocationId(item.getPurposeLocationId()) + .setApplicantId(item.getApplicantId()).setApplyTime(applyTime).setRemake(item.getRemake()); + supplyRequestList.add(supplyRequest); + } + // 更新请求表 + boolean flg = supplyRequestService.saveOrUpdateBatch(supplyRequestList); + if (!flg) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00011, null)); + } + + return R.ok(MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryStocktakingOrderServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryStocktakingOrderServiceImpl.java new file mode 100644 index 000000000..82e2e41e0 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryStocktakingOrderServiceImpl.java @@ -0,0 +1,165 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.core.common.core.domain.R; +import com.core.common.utils.AssignSeqUtil; +import com.core.common.utils.DateUtils; +import com.core.common.utils.MessageUtils; +import com.healthlink.his.common.constant.CommonConstants; +import com.healthlink.his.common.constant.PromptMsgConstant; +import com.healthlink.his.common.enums.*; +import com.healthlink.his.common.utils.EnumUtils; +import com.healthlink.his.web.inventorymanage.dto.ProductStocktakingInitDto; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryStocktakingOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryInitDto; +import com.healthlink.his.web.pharmacy.dispensary.mapper.PharmacyDispensaryCommonMapper; +import com.healthlink.his.workflow.domain.SupplyRequest; +import com.healthlink.his.workflow.service.ISupplyRequestService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 药房盘点单 + * + * @author yuxj + * @date 2025-07-22 + */ +@Service +public class PharmacyDispensaryStocktakingOrderServiceImpl implements IPharmacyDispensaryStocktakingOrderService { + + @Resource + private AssignSeqUtil assignSeqUtil; + + @Resource + private ISupplyRequestService supplyRequestService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + @Autowired + private PharmacyDispensaryCommonMapper pharmacyDispensaryCommonMapper; + + /** + * 初始化 + * + * @return 初始化信息 + */ + @Override + public R> init() { + + PharmacyDispensaryInitDto purchaseOrderInitDto = pharmacyDispensaryCommonService.init(); + + // 单据分类 + List supplyCategoryOption = new ArrayList<>(); +// supplyCategoryOption.add(new PharmacyDispensaryInitDto.IntegerOption( +// SupplyCategory.GENERAL_STOCKTAKING.getValue(), SupplyCategory.GENERAL_STOCKTAKING.getInfo())); +// supplyCategoryOption.add(new PharmacyDispensaryInitDto.IntegerOption( +// SupplyCategory.MONTHLY_STOCKTAKING.getValue(), SupplyCategory.MONTHLY_STOCKTAKING.getInfo())); + + purchaseOrderInitDto.setSupplyCategoryOptions(supplyCategoryOption); + + return R.ok(purchaseOrderInitDto); + } + + /** + * 盘点单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 盘点单单据详情 + */ + @Override + public R> getDetailPage(String busNo, Integer pageNo, Integer pageSize) { + + Page stocktakingOrderDtoDetailPage = + pharmacyDispensaryCommonMapper.getDetailPage(new Page<>(pageNo, pageSize), busNo); + + stocktakingOrderDtoDetailPage.getRecords().forEach(e -> { + // 单据分类 + e.setCategoryEnum_enumText(EnumUtils.getInfoByValue(SupplyCategory.class, e.getCategoryEnum())); + // 单据状态 + e.setStatusEnum_enumText(EnumUtils.getInfoByValue(SupplyStatus.class, e.getStatusEnum())); + // 单据类型 + e.setTypeEnum_enumText(EnumUtils.getInfoByValue(SupplyType.class, e.getTypeEnum())); + }); + + List unitList; + for (PharmacyDispensaryDetailDto item : stocktakingOrderDtoDetailPage.getRecords()) { + unitList = new ArrayList<>(); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMaxUnitCode(), item.getMaxUnitCode_dictText())); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMinUnitCode(), item.getMinUnitCode_dictText())); + + item.setUnitList(unitList); + } + return R.ok(stocktakingOrderDtoDetailPage); + } + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @Override + public R> getBusNo() { + + ProductStocktakingInitDto initDto = new ProductStocktakingInitDto(); + // 单据号 + initDto.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.PURCHASE_STOCKTAKING.getPrefix(), 4)); + + return R.ok(initDto); + } + + /** + * 添加/编辑盘点单 + * + * @param stocktakingOrderDtoList 盘点信息 + * @return 操作结果 + */ + + @Override + public R> addOrEditStocktakingOrder(List stocktakingOrderDtoList) { + // 请求数据取得 + List requestList = + supplyRequestService.getSupplyByBusNo(stocktakingOrderDtoList.get(0).getBusNo()); + if (!requestList.isEmpty()) { + // 请求id取得 + List requestIdList = requestList.stream().map(SupplyRequest::getId).collect(Collectors.toList()); + // 单据信息删除 + supplyRequestService.removeByIds(requestIdList); + } + + List supplyRequestList = new ArrayList<>(); + Date applyTime = DateUtils.getNowDate(); + for (PharmacyDispensaryDetailDto item : stocktakingOrderDtoList) { + SupplyRequest supplyRequest = new SupplyRequest().setBusNo(item.getBusNo()) + .setTypeEnum(SupplyType.PURCHASE_STOCKTAKING.getValue()) + .setStatusEnum(SupplyStatus.PENDING_REVIEW.getValue()).setCategoryEnum(item.getCategoryEnum()) + .setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION).setItemId(item.getItemId()) + .setUnitCode(item.getUnitCode()).setItemQuantity(item.getItemQuantity()) + .setTotalQuantity(item.getTotalQuantity()).setPrice(item.getPrice()).setTotalPrice(item.getTotalPrice()) + .setRetailPrice(item.getRetailPrice()).setTotalRetailPrice(item.getTotalRetailPrice()) + .setBatchInventory(item.getBatchInventory()).setLotNumber(item.getLotNumber()) + .setTraceNo(item.getTraceNo()).setTraceNoUnitCode(item.getTraceNoUnitCode()) + .setReasonCode(item.getReasonCode()).setReason(item.getReason()) + .setPurposeTypeEnum(LocationForm.PHARMACY.getValue()).setPurposeLocationId(item.getPurposeLocationId()) + .setApplicantId(item.getApplicantId()).setApplyTime(applyTime).setRemake(item.getRemake()); + supplyRequestList.add(supplyRequest); + } + // 更新请求表 + boolean flg = supplyRequestService.saveOrUpdateBatch(supplyRequestList); + if (!flg) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00011, null)); + } + + return R.ok(MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryTransferInOrderServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryTransferInOrderServiceImpl.java new file mode 100644 index 000000000..622771087 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryTransferInOrderServiceImpl.java @@ -0,0 +1,164 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.core.common.core.domain.R; +import com.core.common.utils.AssignSeqUtil; +import com.core.common.utils.DateUtils; +import com.core.common.utils.MessageUtils; +import com.healthlink.his.common.constant.CommonConstants; +import com.healthlink.his.common.constant.PromptMsgConstant; +import com.healthlink.his.common.enums.*; +import com.healthlink.his.common.utils.EnumUtils; +import com.healthlink.his.web.inventorymanage.dto.ProductStocktakingInitDto; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryTransferInOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryInitDto; +import com.healthlink.his.web.pharmacy.dispensary.mapper.PharmacyDispensaryCommonMapper; +import com.healthlink.his.workflow.domain.SupplyRequest; +import com.healthlink.his.workflow.service.ISupplyRequestService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 药房调入单 + * + * @author yuxj + * @date 2025-07-22 + */ +@Service +public class PharmacyDispensaryTransferInOrderServiceImpl implements IPharmacyDispensaryTransferInOrderService { + + @Resource + private AssignSeqUtil assignSeqUtil; + + @Resource + private ISupplyRequestService supplyRequestService; + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + @Autowired + private PharmacyDispensaryCommonMapper pharmacyDispensaryCommonMapper; + + /** + * 初始化 + * + * @return 初始化信息 + */ + @Override + public R> init() { + + PharmacyDispensaryInitDto purchaseOrderInitDto = pharmacyDispensaryCommonService.init(); + + // 单据分类 + List supplyCategoryOption = new ArrayList<>(); + // supplyCategoryOption.add(new PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.NORMAL.getValue(), + // SupplyCategory.NORMAL.getInfo())); + + purchaseOrderInitDto.setSupplyCategoryOptions(supplyCategoryOption); + + return R.ok(purchaseOrderInitDto); + } + + /** + * 调入单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 调入单单据详情 + */ + @Override + public R> getDetailPage(String busNo, Integer pageNo, Integer pageSize) { + + Page transferInOrderDtoDetailPage = + pharmacyDispensaryCommonMapper.getDetailPage(new Page<>(pageNo, pageSize), busNo); + + transferInOrderDtoDetailPage.getRecords().forEach(e -> { + // 单据分类 + e.setCategoryEnum_enumText(EnumUtils.getInfoByValue(SupplyCategory.class, e.getCategoryEnum())); + // 单据状态 + e.setStatusEnum_enumText(EnumUtils.getInfoByValue(SupplyStatus.class, e.getStatusEnum())); + // 单据类型 + e.setTypeEnum_enumText(EnumUtils.getInfoByValue(SupplyType.class, e.getTypeEnum())); + }); + + List unitList; + for (PharmacyDispensaryDetailDto item : transferInOrderDtoDetailPage.getRecords()) { + unitList = new ArrayList<>(); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMaxUnitCode(), item.getMaxUnitCode_dictText())); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMinUnitCode(), item.getMinUnitCode_dictText())); + + item.setUnitList(unitList); + } + + return R.ok(transferInOrderDtoDetailPage); + } + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @Override + public R> getBusNo() { + + ProductStocktakingInitDto initDto = new ProductStocktakingInitDto(); + // 单据号 + initDto.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.PURCHASE_TRANSFERIN.getPrefix(), 4)); + + return R.ok(initDto); + } + + /** + * 添加/编辑采购单 + * + * @param transferInOrderDtoList 采购信息 + * @return 操作结果 + */ + + @Override + public R> addOrEditTransferInOrder(List transferInOrderDtoList) { + // 请求数据取得 + List requestList = + supplyRequestService.getSupplyByBusNo(transferInOrderDtoList.get(0).getBusNo()); + if (!requestList.isEmpty()) { + // 请求id取得 + List requestIdList = requestList.stream().map(SupplyRequest::getId).collect(Collectors.toList()); + // 单据信息删除 + supplyRequestService.removeByIds(requestIdList); + } + + List supplyRequestList = new ArrayList<>(); + Date applyTime = DateUtils.getNowDate(); + for (PharmacyDispensaryDetailDto item : transferInOrderDtoList) { + SupplyRequest supplyRequest = new SupplyRequest().setBusNo(item.getBusNo()) + .setTypeEnum(SupplyType.PURCHASE_TRANSFERIN.getValue()) + .setStatusEnum(SupplyStatus.PENDING_REVIEW.getValue()) + .setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION).setItemId(item.getItemId()) + .setUnitCode(item.getUnitCode()).setItemQuantity(item.getItemQuantity()).setRetailPrice(item.getPrice()) + .setTotalRetailPrice(item.getTotalPrice()).setBatchInventory(item.getBatchInventory()) + .setSpecificationInventory(item.getSpecificationInventory()).setEndTime(item.getEndTime()) + .setLotNumber(item.getLotNumber()).setTraceNo(item.getTraceNo()) + .setTraceNoUnitCode(item.getTraceNoUnitCode()).setSupplierId(item.getSupplierId()) + .setReason(item.getReason()).setSourceTypeEnum(LocationForm.PHARMACY.getValue()) + .setSourceLocationId(item.getSourceLocationId()).setPurposeTypeEnum(LocationForm.PHARMACY.getValue()) + .setPurposeLocationId(item.getPurposeLocationId()).setApplicantId(item.getApplicantId()) + .setApplyTime(applyTime).setRemake(item.getRemake()); + supplyRequestList.add(supplyRequest); + } + // 更新请求表 + boolean flg = supplyRequestService.saveOrUpdateBatch(supplyRequestList); + if (!flg) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00011, null)); + } + + return R.ok(MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryTransferOutOrderServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryTransferOutOrderServiceImpl.java new file mode 100644 index 000000000..2190379a0 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/appservice/impl/PharmacyDispensaryTransferOutOrderServiceImpl.java @@ -0,0 +1,162 @@ +package com.healthlink.his.web.pharmacy.dispensary.appservice.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.core.common.core.domain.R; +import com.core.common.utils.AssignSeqUtil; +import com.core.common.utils.DateUtils; +import com.core.common.utils.MessageUtils; +import com.healthlink.his.common.constant.CommonConstants; +import com.healthlink.his.common.constant.PromptMsgConstant; +import com.healthlink.his.common.enums.*; +import com.healthlink.his.common.utils.EnumUtils; +import com.healthlink.his.web.inventorymanage.dto.ProductStocktakingInitDto; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryTransferOutOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryInitDto; +import com.healthlink.his.web.pharmacy.dispensary.mapper.PharmacyDispensaryCommonMapper; +import com.healthlink.his.workflow.domain.SupplyRequest; +import com.healthlink.his.workflow.service.ISupplyRequestService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 药房调出单 + * + * @author yuxj + * @date 2025-07-22 + */ +@Service +public class PharmacyDispensaryTransferOutOrderServiceImpl implements IPharmacyDispensaryTransferOutOrderService { + + @Resource + private AssignSeqUtil assignSeqUtil; + @Resource + private ISupplyRequestService supplyRequestService; + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + @Autowired + private PharmacyDispensaryCommonMapper pharmacyDispensaryCommonMapper; + + /** + * 初始化 + * + * @return 初始化信息 + */ + @Override + public R> init() { + + PharmacyDispensaryInitDto purchaseOrderInitDto = pharmacyDispensaryCommonService.init(); + + // 单据分类 + List supplyCategoryOption = new ArrayList<>(); +// supplyCategoryOption.add(new PharmacyDispensaryInitDto.IntegerOption(SupplyCategory.NORMAL.getValue(), +// SupplyCategory.NORMAL.getInfo())); + + purchaseOrderInitDto.setSupplyCategoryOptions(supplyCategoryOption); + + return R.ok(purchaseOrderInitDto); + } + + /** + * 调出单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 调出单单据详情 + */ + @Override + public R> getDetailPage(String busNo, Integer pageNo, Integer pageSize) { + + Page transferOutOrderDtoDetailPage = + pharmacyDispensaryCommonMapper.getDetailPage(new Page<>(pageNo, pageSize), busNo); + + transferOutOrderDtoDetailPage.getRecords().forEach(e -> { + // 单据分类 + e.setCategoryEnum_enumText(EnumUtils.getInfoByValue(SupplyCategory.class, e.getCategoryEnum())); + // 单据状态 + e.setStatusEnum_enumText(EnumUtils.getInfoByValue(SupplyStatus.class, e.getStatusEnum())); + // 单据类型 + e.setTypeEnum_enumText(EnumUtils.getInfoByValue(SupplyType.class, e.getTypeEnum())); + }); + + List unitList; + for (PharmacyDispensaryDetailDto item : transferOutOrderDtoDetailPage.getRecords()) { + unitList = new ArrayList<>(); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMaxUnitCode(), item.getMaxUnitCode_dictText())); + unitList.add(new PharmacyDispensaryDetailDto.Option(item.getMinUnitCode(), item.getMinUnitCode_dictText())); + + item.setUnitList(unitList); + } + + return R.ok(transferOutOrderDtoDetailPage); + } + + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @Override + public R> getBusNo() { + + ProductStocktakingInitDto initDto = new ProductStocktakingInitDto(); + // 单据号 + initDto.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.PURCHASE_TRANSFEROUT.getPrefix(), 4)); + + return R.ok(initDto); + } + + /** + * 添加/编辑采购单 + * + * @param transferOutOrderDtoList 采购信息 + * @return 操作结果 + */ + + @Override + public R> addOrEditTransferOutOrder(List transferOutOrderDtoList) { + // 请求数据取得 + List requestList = supplyRequestService.getSupplyByBusNo(transferOutOrderDtoList.get(0).getBusNo()); + if (!requestList.isEmpty()) { + // 请求id取得 + List requestIdList = requestList.stream().map(SupplyRequest::getId).collect(Collectors.toList()); + // 单据信息删除 + supplyRequestService.removeByIds(requestIdList); + } + + List supplyRequestList = new ArrayList<>(); + Date applyTime = DateUtils.getNowDate(); + for (PharmacyDispensaryDetailDto item : transferOutOrderDtoList) { + SupplyRequest supplyRequest = new SupplyRequest().setBusNo(item.getBusNo()) + .setTypeEnum(SupplyType.PURCHASE_TRANSFEROUT.getValue()) + .setStatusEnum(SupplyStatus.PENDING_REVIEW.getValue()) + .setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION).setItemId(item.getItemId()) + .setUnitCode(item.getUnitCode()).setItemQuantity(item.getItemQuantity()).setRetailPrice(item.getPrice()) + .setTotalRetailPrice(item.getTotalPrice()).setBatchInventory(item.getBatchInventory()) + .setSpecificationInventory(item.getSpecificationInventory()).setEndTime(item.getEndTime()) + .setLotNumber(item.getLotNumber()).setTraceNo(item.getTraceNo()) + .setTraceNoUnitCode(item.getTraceNoUnitCode()).setSupplierId(item.getSupplierId()) + .setReason(item.getReason()).setSourceTypeEnum(LocationForm.PHARMACY.getValue()) + .setSourceLocationId(item.getSourceLocationId()).setPurposeTypeEnum(LocationForm.PHARMACY.getValue()) + .setPurposeLocationId(item.getPurposeLocationId()) + .setApplicantId(item.getApplicantId()).setApplyTime(applyTime).setRemake(item.getRemake()); + supplyRequestList.add(supplyRequest); + } + // 更新请求表 + boolean flg = supplyRequestService.saveOrUpdateBatch(supplyRequestList); + if (!flg) { + return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00011, null)); + } + + return R.ok(MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryDispensingOrderController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryDispensingOrderController.java new file mode 100644 index 000000000..863419b83 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryDispensingOrderController.java @@ -0,0 +1,78 @@ +package com.healthlink.his.web.pharmacy.dispensary.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.common.enums.SupplyType; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryDispensingOrderService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryReceiptApprovalService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensarySearchParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.servlet.http.HttpServletRequest; + +/** + * 药房发药单 + * + * @author yuxj + * @date 2025-07-22 + */ +@RestController +@RequestMapping("/pharmacy-dispensary/dispensing-order") +@Slf4j +public class PharmacyDispensaryDispensingOrderController { + + @Autowired + private IPharmacyDispensaryDispensingOrderService pharmacyDispensaryDispensingOrderService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + @Autowired + private IPharmacyDispensaryReceiptApprovalService pharmacyDispensaryReceiptApprovalService; + /** + * 发药单初始化 + * + * @return 初始化信息 + */ + @GetMapping(value = "/init") + public R> init() { + return pharmacyDispensaryDispensingOrderService.init(); + } + + /** + * 发药单单据列表 + * + * @param dispensingOrderSearchParam 查询条件 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param searchKey 模糊查询关键字 + * @param request 请求数据 + * @return 发药单据分页列表 + */ + @GetMapping(value = "/dispensing-order-page") + public R> getPage(PharmacyDispensarySearchParam dispensingOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getPage(dispensingOrderSearchParam, pageNo, pageSize, searchKey, request, + "1", SupplyType.DISPENSING_ORDER.getValue()); + } + /** + * 发药单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 发药单单据详情 + */ + @GetMapping(value = "/dispensing-order-detail-page") + public R> getDetail(@RequestParam String busNo, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) { + return pharmacyDispensaryDispensingOrderService.getDetailPage(busNo, pageNo, pageSize); + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryProfitLossOrderController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryProfitLossOrderController.java new file mode 100644 index 000000000..f13b3316e --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryProfitLossOrderController.java @@ -0,0 +1,134 @@ +package com.healthlink.his.web.pharmacy.dispensary.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.common.enums.SupplyType; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryProfitLossOrderService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryReceiptApprovalService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensarySearchParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 药房损益单 + * + * @author yuxj + * @date 2025-07-22 + */ +@RestController +@RequestMapping("/pharmacy-dispensary/profitLoss-order") +@Slf4j +public class PharmacyDispensaryProfitLossOrderController { + + @Autowired + private IPharmacyDispensaryProfitLossOrderService pharmacyDispensaryProfitLossOrderService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + @Autowired + private IPharmacyDispensaryReceiptApprovalService pharmacyDispensaryReceiptApprovalService; + /** + * 损益单初始化 + * + * @return 初始化信息 + */ + @GetMapping(value = "/init") + public R> init() { + return pharmacyDispensaryProfitLossOrderService.init(); + } + + /** + * 获取药品 + * + * @param purchaseOrderSearchParam 查询条件 + * @return 药品信息 + */ + @GetMapping(value = "/medication-info") + public R> getMedicationInfo(PharmacyDispensarySearchParam purchaseOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getMedicationInfo(purchaseOrderSearchParam, pageNo, pageSize, searchKey, request); + } + + /** + * 损益单单据列表 + * + * @param profitLossOrderSearchParam 查询条件 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param searchKey 模糊查询关键字 + * @param request 请求数据 + * @return 损益单据分页列表 + */ + @GetMapping(value = "/profitLoss-order-page") + public R> getPage(PharmacyDispensarySearchParam profitLossOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getPage(profitLossOrderSearchParam, pageNo, pageSize, searchKey, request, + null, SupplyType.PURCHASE_PRPFITLOSS.getValue()); + } + /** + * 损益单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 损益单单据详情 + */ + @GetMapping(value = "/profitLoss-order-detail-page") + public R> getDetail(@RequestParam String busNo, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) { + return pharmacyDispensaryProfitLossOrderService.getDetailPage(busNo, pageNo, pageSize); + } + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @GetMapping(value = "/busNo-init") + public R> getBusNo() { + return pharmacyDispensaryProfitLossOrderService.getBusNo(); + } + + /** + * 添加/编辑损益单 + * + * @param profitLossOrderDtoList 损益信息 + * @return 操作结果 + */ + @PutMapping("/addOrEdit-profitLossOrder") + public R> addOrEditProfitLossOrder(@Validated @RequestBody List profitLossOrderDtoList) { + return pharmacyDispensaryProfitLossOrderService.addOrEditProfitLossOrder(profitLossOrderDtoList); + } + + /** + * 删除单据 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @DeleteMapping("/delete-profitLossOrder") + public R> deleteProfitLossOrder(@RequestParam String busNo) { + return pharmacyDispensaryCommonService.deleteOrder(busNo); + } + /** + * 同意审批 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @PutMapping("/agree-approval") + public R> agreeApproval(@RequestParam String busNo) { + return pharmacyDispensaryReceiptApprovalService.profitLossAgreeApproved(busNo); + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryRequisitionOrderController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryRequisitionOrderController.java new file mode 100644 index 000000000..b78dae3d7 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryRequisitionOrderController.java @@ -0,0 +1,136 @@ +package com.healthlink.his.web.pharmacy.dispensary.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.common.enums.SupplyType; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryReceiptApprovalService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryRequisitionOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensarySearchParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 药房请领单 + * + * @author yuxj + * @date 2025-07-22 + */ +@RestController +@RequestMapping("/pharmacy-dispensary/requisition-order") +@Slf4j +public class PharmacyDispensaryRequisitionOrderController { + + @Autowired + private IPharmacyDispensaryRequisitionOrderService pharmacyDispensaryRequisitionOrderService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + + @Autowired + private IPharmacyDispensaryReceiptApprovalService pharmacyDispensaryReceiptApprovalService; + /** + * 请领单初始化 + * + * @return 初始化信息 + */ + @GetMapping(value = "/init") + public R> init() { + return pharmacyDispensaryRequisitionOrderService.init(); + } + + /** + * 获取药品 + * + * @param requisitionOrderSearchParam 查询条件 + * @return 药品信息 + */ + @GetMapping(value = "/medication-info") + public R> getMedicationInfo(PharmacyDispensarySearchParam requisitionOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getMedicationInfo(requisitionOrderSearchParam, pageNo, pageSize, searchKey, request); + } + + /** + * 请领单单据列表 + * + * @param requisitionOrderSearchParam 查询条件 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param searchKey 模糊查询关键字 + * @param request 请求数据 + * @return 请领单据分页列表 + */ + @GetMapping(value = "/requisition-order-page") + public R> getPage(PharmacyDispensarySearchParam requisitionOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getPage(requisitionOrderSearchParam, pageNo, pageSize, searchKey, request, + null, SupplyType.PURCHASE_REQUISITION.getValue()); + } + /** + * 请领单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 请领单单据详情 + */ + @GetMapping(value = "/requisition-order-detail-page") + public R> getDetail(@RequestParam String busNo, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) { + return pharmacyDispensaryRequisitionOrderService.getDetailPage(busNo, pageNo, pageSize); + } + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @GetMapping(value = "/busNo-init") + public R> getBusNo() { + return pharmacyDispensaryRequisitionOrderService.getBusNo(); + } + + /** + * 添加/编辑采购单 + * + * @param requisitionOrderDtoList 采购信息 + * @return 操作结果 + */ + @PutMapping("/addOrEdit-requisitionOrder") + public R> addOrEditRequisitionOrder(@Validated @RequestBody List requisitionOrderDtoList) { + return pharmacyDispensaryRequisitionOrderService.addOrEditRequisitionOrder(requisitionOrderDtoList); + } + + /** + * 删除单据 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @DeleteMapping("/delete-requisitionOrder") + public R> deleteRequisitionOrder(@RequestParam String busNo) { + return pharmacyDispensaryCommonService.deleteOrder(busNo); + } + + /** + * 同意审批 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @PutMapping("/agree-approval") + public R> agreeApproval(@RequestParam String busNo) { + return pharmacyDispensaryReceiptApprovalService.requisitionOrderAgreeApproval(busNo); + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryReturnToWarehouseOrderController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryReturnToWarehouseOrderController.java new file mode 100644 index 000000000..7abef5e57 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryReturnToWarehouseOrderController.java @@ -0,0 +1,134 @@ +package com.healthlink.his.web.pharmacy.dispensary.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.common.enums.SupplyType; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryReceiptApprovalService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryReturnToWarehouseOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensarySearchParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 药房退库单 + * + * @author yuxj + * @date 2025-07-22 + */ +@RestController +@RequestMapping("/pharmacy-dispensary/returnToWarehouse-order") +@Slf4j +public class PharmacyDispensaryReturnToWarehouseOrderController { + + @Autowired + private IPharmacyDispensaryReturnToWarehouseOrderService pharmacyDispensaryReturnToWarehouseOrderService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + @Autowired + private IPharmacyDispensaryReceiptApprovalService pharmacyDispensaryReceiptApprovalService; + /** + * 退库单初始化 + * + * @return 初始化信息 + */ + @GetMapping(value = "/init") + public R> init() { + return pharmacyDispensaryReturnToWarehouseOrderService.init(); + } + + /** + * 获取药品 + * + * @param purchaseOrderSearchParam 查询条件 + * @return 药品信息 + */ + @GetMapping(value = "/medication-info") + public R> getMedicationInfo(PharmacyDispensarySearchParam purchaseOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getMedicationInfo(purchaseOrderSearchParam, pageNo, pageSize, searchKey, request); + } + + /** + * 退库单单据列表 + * + * @param returnToDispensaryOrderSearchParam 查询条件 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param searchKey 模糊查询关键字 + * @param request 请求数据 + * @return 退库单据分页列表 + */ + @GetMapping(value = "/returnToDispensary-order-page") + public R> getPage(PharmacyDispensarySearchParam returnToDispensaryOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getPage(returnToDispensaryOrderSearchParam, pageNo, pageSize, searchKey, request, + "1", SupplyType.PURCHASE_RETURN.getValue()); + } + /** + * 退库单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 退库单单据详情 + */ + @GetMapping(value = "/returnToDispensary-order-detail-page") + public R> getDetail(@RequestParam String busNo, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) { + return pharmacyDispensaryReturnToWarehouseOrderService.getDetailPage(busNo, pageNo, pageSize); + } + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @GetMapping(value = "/busNo-init") + public R> getBusNo() { + return pharmacyDispensaryReturnToWarehouseOrderService.getBusNo(); + } + + /** + * 添加/编辑退库单 + * + * @param returnToDispensaryOrderDtoList 退库信息 + * @return 操作结果 + */ + @PutMapping("/addOrEdit-returnToDispensaryOrder") + public R> addOrEditReturnToDispensaryOrder(@Validated @RequestBody List returnToDispensaryOrderDtoList) { + return pharmacyDispensaryReturnToWarehouseOrderService.addOrEditReturnToWarehouseOrder(returnToDispensaryOrderDtoList); + } + + /** + * 删除单据 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @DeleteMapping("/delete-returnToDispensaryOrder") + public R> deleteReturnToDispensaryOrder(@RequestParam String busNo) { + return pharmacyDispensaryCommonService.deleteOrder(busNo); + } + /** + * 同意审批 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @PutMapping("/agree-approval") + public R> agreeApproval(@RequestParam String busNo) { + return pharmacyDispensaryReceiptApprovalService.returnToWarehouseAgreeApproved(busNo); + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryStockInOrderController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryStockInOrderController.java new file mode 100644 index 000000000..892327094 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryStockInOrderController.java @@ -0,0 +1,134 @@ +package com.healthlink.his.web.pharmacy.dispensary.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.common.enums.SupplyType; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryReceiptApprovalService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryStockInOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensarySearchParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 药房入库单 + * + * @author yuxj + * @date 2025-07-22 + */ +@RestController +@RequestMapping("/pharmacy-dispensary/stockIn-order") +@Slf4j +public class PharmacyDispensaryStockInOrderController { + + @Autowired + private IPharmacyDispensaryStockInOrderService pharmacyDispensaryStockInOrderService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + @Autowired + private IPharmacyDispensaryReceiptApprovalService pharmacyDispensaryReceiptApprovalService; + /** + * 入库单初始化 + * + * @return 初始化信息 + */ + @GetMapping(value = "/init") + public R> init() { + return pharmacyDispensaryStockInOrderService.init(); + } + + /** + * 获取药品 + * + * @param purchaseOrderSearchParam 查询条件 + * @return 药品信息 + */ + @GetMapping(value = "/medication-info") + public R> getMedicationInfo(PharmacyDispensarySearchParam purchaseOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getMedicationInfo(purchaseOrderSearchParam, pageNo, pageSize, searchKey, request); + } + + /** + * 入库单单据列表 + * + * @param stockInOrderSearchParam 查询条件 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param searchKey 模糊查询关键字 + * @param request 请求数据 + * @return 入库单据分页列表 + */ + @GetMapping(value = "/stockIn-order-page") + public R> getPage(PharmacyDispensarySearchParam stockInOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getPage(stockInOrderSearchParam, pageNo, pageSize, searchKey, request, + null, SupplyType.PURCHASE_STOCKIN.getValue()); + } + /** + * 入库单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 入库单单据详情 + */ + @GetMapping(value = "/stockIn-order-detail-page") + public R> getDetail(@RequestParam String busNo, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) { + return pharmacyDispensaryStockInOrderService.getDetailPage(busNo, pageNo, pageSize); + } + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @GetMapping(value = "/busNo-init") + public R> getBusNo() { + return pharmacyDispensaryStockInOrderService.getBusNo(); + } + + /** + * 添加/编辑入库单 + * + * @param stockInOrderDtoList 入库信息 + * @return 操作结果 + */ + @PutMapping("/addOrEdit-stockInOrder") + public R> addOrEditStockInOrder(@Validated @RequestBody List stockInOrderDtoList) { + return pharmacyDispensaryStockInOrderService.addOrEditStockInOrder(stockInOrderDtoList); + } + + /** + * 删除单据 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @DeleteMapping("/delete-stockInOrder") + public R> deleteStockInOrder(@RequestParam String busNo) { + return pharmacyDispensaryCommonService.deleteOrder(busNo); + } + /** + * 同意审批 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @PutMapping("/agree-approval") + public R> agreeApproval(@RequestParam String busNo) { + return pharmacyDispensaryReceiptApprovalService.stockInOrderAgreeApproved(busNo); + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryStocktakingOrderController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryStocktakingOrderController.java new file mode 100644 index 000000000..db32442da --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryStocktakingOrderController.java @@ -0,0 +1,134 @@ +package com.healthlink.his.web.pharmacy.dispensary.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.common.enums.SupplyType; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryReceiptApprovalService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryStocktakingOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensarySearchParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 药房盘点单 + * + * @author yuxj + * @date 2025-07-22 + */ +@RestController +@RequestMapping("/pharmacy-dispensary/stocktaking-order") +@Slf4j +public class PharmacyDispensaryStocktakingOrderController { + + @Autowired + private IPharmacyDispensaryStocktakingOrderService pharmacyDispensaryStocktakingOrderService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + @Autowired + private IPharmacyDispensaryReceiptApprovalService pharmacyDispensaryReceiptApprovalService; + /** + * 盘点单初始化 + * + * @return 初始化信息 + */ + @GetMapping(value = "/init") + public R> init() { + return pharmacyDispensaryStocktakingOrderService.init(); + } + + /** + * 获取药品 + * + * @param purchaseOrderSearchParam 查询条件 + * @return 药品信息 + */ + @GetMapping(value = "/medication-info") + public R> getMedicationInfo(PharmacyDispensarySearchParam purchaseOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getMedicationInfo(purchaseOrderSearchParam, pageNo, pageSize, searchKey, request); + } + + /** + * 盘点单单据列表 + * + * @param stocktakingOrderSearchParam 查询条件 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param searchKey 模糊查询关键字 + * @param request 请求数据 + * @return 盘点单据分页列表 + */ + @GetMapping(value = "/stocktaking-order-page") + public R> getPage(PharmacyDispensarySearchParam stocktakingOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getPage(stocktakingOrderSearchParam, pageNo, pageSize, searchKey, request, + null, SupplyType.PURCHASE_STOCKTAKING.getValue()); + } + /** + * 盘点单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 盘点单单据详情 + */ + @GetMapping(value = "/stocktaking-order-detail-page") + public R> getDetail(@RequestParam String busNo, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) { + return pharmacyDispensaryStocktakingOrderService.getDetailPage(busNo, pageNo, pageSize); + } + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @GetMapping(value = "/busNo-init") + public R> getBusNo() { + return pharmacyDispensaryStocktakingOrderService.getBusNo(); + } + + /** + * 添加/编辑盘点单 + * + * @param stocktakingOrderDtoList 盘点信息 + * @return 操作结果 + */ + @PutMapping("/addOrEdit-stocktakingOrder") + public R> addOrEditStocktakingOrder(@Validated @RequestBody List stocktakingOrderDtoList) { + return pharmacyDispensaryStocktakingOrderService.addOrEditStocktakingOrder(stocktakingOrderDtoList); + } + + /** + * 删除单据 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @DeleteMapping("/delete-stocktakingOrder") + public R> deleteStocktakingOrder(@RequestParam String busNo) { + return pharmacyDispensaryCommonService.deleteOrder(busNo); + } + /** + * 同意审批 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @PutMapping("/agree-approval") + public R> agreeApproval(@RequestParam String busNo) { + return pharmacyDispensaryReceiptApprovalService.stocktakingAgreepproved(busNo); + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryTransferInOrderController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryTransferInOrderController.java new file mode 100644 index 000000000..f7331a862 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryTransferInOrderController.java @@ -0,0 +1,136 @@ +package com.healthlink.his.web.pharmacy.dispensary.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.common.enums.SupplyType; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryReceiptApprovalService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryTransferInOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensarySearchParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 药房调入单 + * + * @author yuxj + * @date 2025-07-22 + */ +@RestController +@RequestMapping("/pharmacy-dispensary/transferIn-order") +@Slf4j +public class PharmacyDispensaryTransferInOrderController { + + @Autowired + private IPharmacyDispensaryTransferInOrderService pharmacyDispensaryTransferInOrderService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + + @Autowired + private IPharmacyDispensaryReceiptApprovalService pharmacyDispensaryReceiptApprovalService; + + /** + * 调入单初始化 + * + * @return 初始化信息 + */ + @GetMapping(value = "/init") + public R> init() { + return pharmacyDispensaryTransferInOrderService.init(); + } + + /** + * 获取药品 + * + * @param purchaseOrderSearchParam 查询条件 + * @return 药品信息 + */ + @GetMapping(value = "/medication-info") + public R> getMedicationInfo(PharmacyDispensarySearchParam purchaseOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getMedicationInfo(purchaseOrderSearchParam, pageNo, pageSize, searchKey, request); + } + /** + * 调入单单据列表 + * + * @param transferInOrderSearchParam 查询条件 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param searchKey 模糊查询关键字 + * @param request 请求数据 + * @return 调入单据分页列表 + */ + @GetMapping(value = "/transferIn-order-page") + public R> getPage(PharmacyDispensarySearchParam transferInOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getPage(transferInOrderSearchParam, pageNo, pageSize, searchKey, request, + null, SupplyType.PURCHASE_TRANSFERIN.getValue()); + } + + /** + * 调入单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 调入单单据详情 + */ + @GetMapping(value = "/transferIn-order-detail-page") + public R> getDetail(@RequestParam String busNo, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) { + return pharmacyDispensaryTransferInOrderService.getDetailPage(busNo, pageNo, pageSize); + } + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @GetMapping(value = "/busNo-init") + public R> getBusNo() { + return pharmacyDispensaryTransferInOrderService.getBusNo(); + } + + /** + * 添加/编辑采购单 + * + * @param transferInOrderDtoList 采购信息 + * @return 操作结果 + */ + @PutMapping("/addOrEdit-transferInOrder") + public R> addOrEditTransferInOrder(@Validated @RequestBody List transferInOrderDtoList) { + return pharmacyDispensaryTransferInOrderService.addOrEditTransferInOrder(transferInOrderDtoList); + } + + /** + * 删除单据 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @DeleteMapping("/delete-transferInOrder") + public R> deleteTransferInOrder(@RequestParam String busNo) { + return pharmacyDispensaryCommonService.deleteOrder(busNo); + } + + /** + * 同意审批 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @PutMapping("/agree-approval") + public R> agreeApproval(@RequestParam String busNo) { + return pharmacyDispensaryReceiptApprovalService.transferInAgreeApproved(busNo); + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryTransferOutOrderController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryTransferOutOrderController.java new file mode 100644 index 000000000..c7707494f --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/controller/PharmacyDispensaryTransferOutOrderController.java @@ -0,0 +1,136 @@ +package com.healthlink.his.web.pharmacy.dispensary.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.common.enums.SupplyType; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryCommonService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryReceiptApprovalService; +import com.healthlink.his.web.pharmacy.dispensary.appservice.IPharmacyDispensaryTransferOutOrderService; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensarySearchParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 药房调出单 + * + * @author yuxj + * @date 2025-07-22 + */ +@RestController +@RequestMapping("/pharmacy-dispensary/transferOut-order") +@Slf4j +public class PharmacyDispensaryTransferOutOrderController { + + @Autowired + private IPharmacyDispensaryTransferOutOrderService pharmacyDispensaryTransferOutOrderService; + + @Autowired + private IPharmacyDispensaryCommonService pharmacyDispensaryCommonService; + + @Autowired + private IPharmacyDispensaryReceiptApprovalService pharmacyDispensaryReceiptApprovalService; + + /** + * 调出单初始化 + * + * @return 初始化信息 + */ + @GetMapping(value = "/init") + public R> init() { + return pharmacyDispensaryTransferOutOrderService.init(); + } + + /** + * 获取药品 + * + * @param purchaseOrderSearchParam 查询条件 + * @return 药品信息 + */ + @GetMapping(value = "/medication-info") + public R> getMedicationInfo(PharmacyDispensarySearchParam purchaseOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getMedicationInfo(purchaseOrderSearchParam, pageNo, pageSize, searchKey, request); + } + /** + * 调出单单据列表 + * + * @param transferOutOrderSearchParam 查询条件 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param searchKey 模糊查询关键字 + * @param request 请求数据 + * @return 调出单据分页列表 + */ + @GetMapping(value = "/transferOut-order-page") + public R> getPage(PharmacyDispensarySearchParam transferOutOrderSearchParam, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) { + return pharmacyDispensaryCommonService.getPage(transferOutOrderSearchParam, pageNo, pageSize, searchKey, request, + "1", SupplyType.PURCHASE_TRANSFEROUT.getValue()); + } + + /** + * 调出单单据详情 + * + * @param busNo 单据号 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 调出单单据详情 + */ + @GetMapping(value = "/transferOut-order-detail-page") + public R> getDetail(@RequestParam String busNo, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) { + return pharmacyDispensaryTransferOutOrderService.getDetailPage(busNo, pageNo, pageSize); + } + /** + * 获取单据号 + * + * @return 初始化信息 + */ + @GetMapping(value = "/busNo-init") + public R> getBusNo() { + return pharmacyDispensaryTransferOutOrderService.getBusNo(); + } + + /** + * 添加/编辑采购单 + * + * @param transferOutOrderDtoList 采购信息 + * @return 操作结果 + */ + @PutMapping("/addOrEdit-transferOutOrder") + public R> addOrEditTransferOutOrder(@Validated @RequestBody List transferOutOrderDtoList) { + return pharmacyDispensaryTransferOutOrderService.addOrEditTransferOutOrder(transferOutOrderDtoList); + } + + /** + * 删除单据 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @DeleteMapping("/delete-transferOutOrder") + public R> deleteTransferOutOrder(@RequestParam String busNo) { + return pharmacyDispensaryCommonService.deleteOrder(busNo); + } + + /** + * 同意审批 + * + * @param busNo 单据号 + * @return 操作结果 + */ + @PutMapping("/agree-approval") + public R> agreeApproval(@RequestParam String busNo) { + return pharmacyDispensaryReceiptApprovalService.transferOutAgreeApproved(busNo); + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensaryDetailDto.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensaryDetailDto.java new file mode 100644 index 000000000..b57a595b7 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensaryDetailDto.java @@ -0,0 +1,214 @@ +/* + * Copyright ©2023 CJB-CNIT Team. All rights reserved + */ +package com.healthlink.his.web.pharmacy.dispensary.dto; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import tools.jackson.databind.annotation.JsonSerialize; +import tools.jackson.databind.ser.std.ToStringSerializer; +import com.healthlink.his.common.annotation.Dict; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * 订购单信息 + * + * @author yuxj + * @date 2025-07-22 + */ +@Data +@Accessors(chain = true) +public class PharmacyDispensaryDetailDto implements Serializable { + + /** ID */ + @TableId(type = IdType.ASSIGN_ID) + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + /** 单据号 */ + private String busNo; + /** 再生成单据号 */ + private String originalBusNo; + + /** 药品编码 */ + private String itemBusNo; + + /** 物品id */ + @JsonSerialize(using = ToStringSerializer.class) + private Long itemId; + + /** 物品名称 */ + private String itemName; + + /** 规格 */ + private String totalVolume; + + /** 选择单位 */ + @Dict(dictCode = "unit_code") + private String unitCode; + private String unitCode_dictText; + + /** 常规单位 */ + @Dict(dictCode = "unit_code") + private String maxUnitCode; + private String maxUnitCode_dictText; + + /** 最小单位 */ + @Dict(dictCode = "unit_code") + private String minUnitCode; + private String minUnitCode_dictText; + + /** 拆零比 */ + private String partPercent; + + /** 数量 */ + private BigDecimal itemQuantity; + + /** 合计数量 */ + private BigDecimal totalQuantity; + + /** 单价 */ + private BigDecimal price; + + /** 总价 */ + private BigDecimal totalPrice; + + /** 零售价 */ + private BigDecimal retailPrice; + + /** 零价金额 */ + private BigDecimal totalRetailPrice; + + /** 厂家/产地 */ + private String manufacturerText; + + /** 批准文号 */ + private String approvalNumber; + + /** 批次库存 */ + private BigDecimal batchInventory; + /** 规格库存 */ + private BigDecimal specificationInventory; + + /** 备注 */ + private String remake; + + /** 理由类型 */ + private String reasonCode; + + /** 摘要(理由) */ + private String reason; + + /** 供应商 */ + @JsonSerialize(using = ToStringSerializer.class) + @Dict(dictCode = "id", dictText = "name", dictTable = "adm_supplier") + private Long supplierId; + private String supplierId_dictText; + + /** 源仓库类型 */ + private Integer sourceTypeEnum; + /** 源仓库 */ + @JsonSerialize(using = ToStringSerializer.class) + private Long sourceLocationId; + + /** 目的仓库类型 */ + private Integer purposeTypeEnum; + /** 目的仓库 */ + @JsonSerialize(using = ToStringSerializer.class) + private Long purposeLocationId; + + /** 采购员 */ + @JsonSerialize(using = ToStringSerializer.class) + private Long applicantId; + + /** 审批人 */ + @JsonSerialize(using = ToStringSerializer.class) + private Long approverId; + /** 审批时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date approvalTime; + + /** 申请时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date applyTime; + + /** 状态 */ + private Integer statusEnum; + private String statusEnum_enumText; + + /** 类型 */ + private Integer typeEnum; + private String typeEnum_enumText; + + /** 单据分类 */ + private Integer categoryEnum; + private String categoryEnum_enumText; + + /** 供应商联系人 */ + private String phone; + + /** 仓库员 */ + @JsonSerialize(using = ToStringSerializer.class) + private Long practitionerId; + + /** 发票号 */ + private String invoiceNo; + + /** 产品批号 */ + private String lotNumber; + + /** 生产日期 */ + private Date startTime; + + /** 失效日期 */ + private Date endTime; + + /** 追溯码*/ + private String traceNo; + + /** 追溯码单位 */ + @Dict(dictCode = "unit_code") + private String traceNoUnitCode; + private String traceNoUnitCode_dictText; + + /** 包装情况 */ + private Integer packagingConditionEnum; + private String packagingConditionEnum_enumText; + + /** 验收结果 */ + private Integer acceptanceResultEnum; + private String acceptanceResultEnum_enumText; + + /** 禁用日期 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date occurrenceTime; + + /** 药品发放id */ + private String dispenseIds; + + /** + * 单位列表 + */ + private List unitList; + + @Data + public static class Option { + @Dict(dictCode = "unit_code") + private String value; + private String value_dictText; + public Option(String value, String value_dictText) { + this.value = value; + this.value_dictText = value_dictText; + } + public Option() { + } + } + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensaryDto.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensaryDto.java new file mode 100644 index 000000000..ec17caeda --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensaryDto.java @@ -0,0 +1,71 @@ +/* + * Copyright ©2023 CJB-CNIT Team. All rights reserved + */ +package com.healthlink.his.web.pharmacy.dispensary.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import tools.jackson.databind.annotation.JsonSerialize; +import tools.jackson.databind.ser.std.ToStringSerializer; +import com.healthlink.his.common.annotation.Dict; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + * 订购单信息 + * + * @author yuxj + * @date 2025-07-22 + */ +@Data +@Accessors(chain = true) +public class PharmacyDispensaryDto implements Serializable { + /** 单据号 */ + private String supplyBusNo; + + /** 状态 */ + private Integer statusEnum; + private String statusEnum_enumText; + + /** 类型 */ + private Integer typeEnum; + private String typeEnum_enumText; + + /** 供应商 */ + @Dict(dictCode = "id", dictText = "name", dictTable = "adm_supplier") + @JsonSerialize(using = ToStringSerializer.class) + private Long supplierId; + private String supplierId_dictText; + + /** 仓库类型 */ + private Integer locationTypeEnum; + private String locationTypeEnum_enumText; + + /** 仓库 */ + @Dict(dictCode = "id", dictText = "name", dictTable = "adm_location") + @JsonSerialize(using = ToStringSerializer.class) + private Long locationId; + private String locationId_dictText; + + /** 采购员 */ + @Dict(dictCode = "id", dictText = "name", dictTable = "adm_practitioner") + @JsonSerialize(using = ToStringSerializer.class) + private Long applicantId; + private String applicantId_dictText; + + /** 审批人 */ + @Dict(dictCode = "id", dictText = "name", dictTable = "adm_practitioner") + @JsonSerialize(using = ToStringSerializer.class) + private Long approverId; + private String approverId_dictText; + + /** 审批时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date approvalTime; + + /** 制单日期 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date applyTime; +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensaryInitDto.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensaryInitDto.java new file mode 100644 index 000000000..237ab093a --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensaryInitDto.java @@ -0,0 +1,145 @@ +/* + * Copyright ©2023 CJB-CNIT Team. All rights reserved + */ +package com.healthlink.his.web.pharmacy.dispensary.dto; + +import tools.jackson.databind.annotation.JsonSerialize; +import tools.jackson.databind.ser.std.ToStringSerializer; +import com.healthlink.his.web.common.dto.LocationDto; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.List; + +/** + * 订购单信息 + * + * @author yuxj + * @date 2025-07-22 + */ +@Data +@Accessors(chain = true) +public class PharmacyDispensaryInitDto implements Serializable { + + /** + * 单据号 + */ + private String busNo; + + /** + * 库房类型列表 + */ + private List warehouseTypeOption; + + /** + * 库房列表 + */ + private List warehouseOption; + + /** + * 供应商列表 + */ + private List supplierOption; + + /** + * 人员列表 + */ + private List practitionerOption; + /** + * 审批状态 + */ + private List supplyStatusOptions; + + /** + * 单据类型 + */ + private List supplyTypeOptions; + + /** + * 单据分类 + */ + private List supplyCategoryOptions; + /** + * 包装情况 + */ + private List packagingConditionOptions; + /** + * 包装情况 + */ + private List acceptanceResultoryOptions; + + /** + * 仓库 + */ + private List cabinetListOptions; + /** + * 药房 + */ + private List pharmacyListOptions; + + @Data + public static class LongOption { + @JsonSerialize(using = ToStringSerializer.class) + private Long value; + private String label; + + public LongOption(Long value, String label) { + this.value = value; + this.label = label; + } + } + + @Data + public static class SupplierOption { + @JsonSerialize(using = ToStringSerializer.class) + private Long value; + private String label; + private String phone; + + public SupplierOption(Long value, String label, String phone) { + this.value = value; + this.label = label; + this.phone = phone; + } + } + + @Data + public static class IntegerOption { + private Integer value; + private String label; + + public IntegerOption(Integer value, String label) { + this.value = value; + this.label = label; + } + } + + @Data + public static class DispensaryOption { + private Integer value; + private String label; + private List locationOption; + private List orderOption; + + public DispensaryOption(Integer value, String label,List locationOption,List orderOption) { + this.value = value; + this.label = label; + this.locationOption = locationOption; + this.orderOption = orderOption; + } + } + + @Data + public static class DispensaryItemOption { + private Integer value; + private String label; + + public DispensaryItemOption(Integer value, String label) { + this.value = value; + this.label = label; + } + } + + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensaryMedicationInfoDto.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensaryMedicationInfoDto.java new file mode 100644 index 000000000..cf04cd9c1 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensaryMedicationInfoDto.java @@ -0,0 +1,119 @@ +/* + * Copyright ©2023 CJB-CNIT Team. All rights reserved + */ +package com.healthlink.his.web.pharmacy.dispensary.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import tools.jackson.databind.annotation.JsonSerialize; +import tools.jackson.databind.ser.std.ToStringSerializer; +import com.healthlink.his.common.annotation.Dict; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * 药品信息 + * + * @author yuxj + * @date 2025-07-22 + */ +@Data +@Accessors(chain = true) +public class PharmacyDispensaryMedicationInfoDto implements Serializable { + + /** 物品id */ + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + /** 物品编号 */ + private String busNo; + + /** 物品名称 */ + private String name; + + /** 拼音码 */ + private String pyStr; + + /** 规格 */ + private String totalVolume; + + /** 包装单位 */ + @Dict(dictCode = "unit_code") + private String unitCode; + private String unitCode_dictText; + + /** 最小单位 */ + @Dict(dictCode = "unit_code") + private String minUnitCode; + private String minUnitCode_dictText; + + /** 拆零比 */ + private BigDecimal partPercent; + + /** 产品批号 */ + private String lotNumber; + + +// /** 价格单位 */ +// @Dict(dictCode = "unit_code") +// private String conditionUnitCode; +// private String conditionUnitCode_dictText; + + /** 单价 */ + private BigDecimal price; + + /** 零售价 */ + private BigDecimal retailPrice; + + /** 厂家/产地 */ + private String manufacturerText; + + /** 批准文号 */ + private String approvalNumber; + + /** 库存最小警戒线 */ + private BigDecimal itemMinQuantity; + + /** 批次库存 */ + private BigDecimal batchInventory; + /** 规格库存 */ + private BigDecimal specificationInventory; + + /** 供应商 */ + @Dict(dictCode = "id", dictText = "name", dictTable = "adm_supplier") + @JsonSerialize(using = ToStringSerializer.class) + private Long supplierId; + private String supplierId_dictText; + + /** 仓库 */ + @JsonSerialize(using = ToStringSerializer.class) + private Long locationId; + + /** 生产日期 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date productionDate; + + /** 失效日期 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date expirationDate; + + /** + * 单位列表 + */ + private List unitList; + + @Data + public static class Option { + @Dict(dictCode = "unit_code") + private String value; + private String value_dictText; + public Option(String value, String value_dictText) { + this.value = value; + this.value_dictText = value_dictText; + } + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensarySearchParam.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensarySearchParam.java new file mode 100644 index 000000000..ee6f50161 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/dto/PharmacyDispensarySearchParam.java @@ -0,0 +1,56 @@ +/* + * Copyright ©2023 CJB-CNIT Team. All rights reserved + */ +package com.healthlink.his.web.pharmacy.dispensary.dto; + +import tools.jackson.databind.annotation.JsonSerialize; +import tools.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 订购单查询条件 + * + * @author yuxj + * @date 2025-07-22 + */ +@Data +@Accessors(chain = true) +public class PharmacyDispensarySearchParam implements Serializable { + /** id */ + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + /** 单据号 */ + private String busNo; + + /** 采购员 */ + private String applicantName; + + /** 项目名 */ + private String name; + + /** 拼音码 */ + private String pyStr; + + /** 供应商id */ + @JsonSerialize(using = ToStringSerializer.class) + private Long supplierId; + + /** 仓库类型 */ + private Integer locationTypeEnum; + + /** 仓库 */ + @JsonSerialize(using = ToStringSerializer.class) + private Long locationId; + + /** 类型 */ + private Integer typeEnum; + + /** 单据状态 */ + private Integer statusEnum; + + /** 再生成单据号flg */ + private String originalBusNoFlg; +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryCommonMapper.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryCommonMapper.java new file mode 100644 index 000000000..692127d89 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryCommonMapper.java @@ -0,0 +1,57 @@ +package com.healthlink.his.web.pharmacy.dispensary.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryMedicationInfoDto; +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensarySearchParam; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +/** + * 药库共通 mapper + * + * @author yuxj + * @date 2025-07-22 + */ +@Repository +public interface PharmacyDispensaryCommonMapper { + /** + * 根据供应商获取药品 + * + * @param page 分页 + * @param queryWrapper 查询条件 + * @param locationId 仓库id + * @return 药品信息 + */ + + Page getMedicationInfo( + @Param("page") Page page, + @Param(Constants.WRAPPER) QueryWrapper queryWrapper, + @Param("locationId") Long locationId, @Param("supplierId") Long supplierId); + + /** + * 查询订货单分页列表 + * + * @param page 分页 + * @param queryWrapper 查询条件 + * @param originalBusNoFlg 再生成单据号flg + * @param locationFlg 仓库flg + * @return 订货单分页列表 + */ + Page getPage(@Param("page") Page page, + @Param(Constants.WRAPPER) QueryWrapper queryWrapper, + @Param("originalBusNoFlg") String originalBusNoFlg, @Param("locationFlg") String locationFlg); + + /** + * 查询单据详情 + * + * @param page 分页 + * @param busNo 单据号 + * @return 单据详情 + */ + Page getDetailPage(@Param("page") Page page, + @Param("busNo") String busNo); +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryDispensingOrderMapper.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryDispensingOrderMapper.java new file mode 100644 index 000000000..6f0e55a58 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryDispensingOrderMapper.java @@ -0,0 +1,27 @@ +package com.healthlink.his.web.pharmacy.dispensary.mapper; + +import com.healthlink.his.web.pharmacy.dispensary.dto.PharmacyDispensaryDetailDto; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * 药房发药单 mapper + * + * @author yuxj + * @date 2025-07-22 + */ +@Repository +public interface PharmacyDispensaryDispensingOrderMapper { + + + /** + * 获取更表所需信息 + * + * @param dispenseIdList 药品发放id + * @param dispenseStatus 发放状态 + * @return 单据详情 + */ + List getInfo(@Param("dispenseIdList") List dispenseIdList,@Param("dispenseStatus") Integer dispenseStatus); +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryProfitLossOrderMapper.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryProfitLossOrderMapper.java new file mode 100644 index 000000000..7454bf79e --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryProfitLossOrderMapper.java @@ -0,0 +1,14 @@ +package com.healthlink.his.web.pharmacy.dispensary.mapper; + +import org.springframework.stereotype.Repository; + +/** + * 药房损益单 mapper + * + * @author yuxj + * @date 2025-07-22 + */ +@Repository +public interface PharmacyDispensaryProfitLossOrderMapper { + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryRequisitionOrderMapper.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryRequisitionOrderMapper.java new file mode 100644 index 000000000..bd82db8b0 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryRequisitionOrderMapper.java @@ -0,0 +1,14 @@ +package com.healthlink.his.web.pharmacy.dispensary.mapper; + +import org.springframework.stereotype.Repository; + +/** + * 药房请领单 mapper + * + * @author yuxj + * @date 2025-07-22 + */ +@Repository +public interface PharmacyDispensaryRequisitionOrderMapper { + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryReturnToWarehouseOrderMapper.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryReturnToWarehouseOrderMapper.java new file mode 100644 index 000000000..429facbc5 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryReturnToWarehouseOrderMapper.java @@ -0,0 +1,14 @@ +package com.healthlink.his.web.pharmacy.dispensary.mapper; + +import org.springframework.stereotype.Repository; + +/** + * 药房退库单 mapper + * + * @author yuxj + * @date 2025-07-22 + */ +@Repository +public interface PharmacyDispensaryReturnToWarehouseOrderMapper { + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryStockInOrderMapper.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryStockInOrderMapper.java new file mode 100644 index 000000000..1102a4b3e --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryStockInOrderMapper.java @@ -0,0 +1,14 @@ +package com.healthlink.his.web.pharmacy.dispensary.mapper; + +import org.springframework.stereotype.Repository; + +/** + * 药房入库单 mapper + * + * @author yuxj + * @date 2025-07-22 + */ +@Repository +public interface PharmacyDispensaryStockInOrderMapper { + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryStocktakingOrderMapper.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryStocktakingOrderMapper.java new file mode 100644 index 000000000..a93723e2d --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryStocktakingOrderMapper.java @@ -0,0 +1,14 @@ +package com.healthlink.his.web.pharmacy.dispensary.mapper; + +import org.springframework.stereotype.Repository; + +/** + * 药房盘点单 mapper + * + * @author yuxj + * @date 2025-07-22 + */ +@Repository +public interface PharmacyDispensaryStocktakingOrderMapper { + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryTransferInOrderMapper.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryTransferInOrderMapper.java new file mode 100644 index 000000000..59c1a79c1 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryTransferInOrderMapper.java @@ -0,0 +1,14 @@ +package com.healthlink.his.web.pharmacy.dispensary.mapper; + +import org.springframework.stereotype.Repository; + +/** + * 药房调入单 mapper + * + * @author yuxj + * @date 2025-07-22 + */ +@Repository +public interface PharmacyDispensaryTransferInOrderMapper { + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryTransferOutOrderMapper.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryTransferOutOrderMapper.java new file mode 100644 index 000000000..a92208ba0 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispensary/mapper/PharmacyDispensaryTransferOutOrderMapper.java @@ -0,0 +1,14 @@ +package com.healthlink.his.web.pharmacy.dispensary.mapper; + +import org.springframework.stereotype.Repository; + +/** + * 药房调出单 mapper + * + * @author yuxj + * @date 2025-07-22 + */ +@Repository +public interface PharmacyDispensaryTransferOutOrderMapper { + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IInHospitalReturnMedicineAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IInHospitalReturnMedicineAppService.java new file mode 100644 index 000000000..84ef365b7 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IInHospitalReturnMedicineAppService.java @@ -0,0 +1,59 @@ +/* + * Copyright ©2023 CJB-CNIT Team. All rights reserved + */ +package com.healthlink.his.web.pharmacy.dispense.appservice; + +import java.util.List; + +import jakarta.servlet.http.HttpServletRequest; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispense.dto.EncounterInfoDto; +import com.healthlink.his.web.pharmacy.dispense.dto.ReturnMedicineDto; + +/** + * TODO:概括描述当前类的主要用途和注意事项 + * + * @author zwh + * @date 2025-12-29 + */ +public interface IInHospitalReturnMedicineAppService { + + /** + * 页面初始化 + * + * @return 初始化信息 + */ + R> init(); + + /** + * 查询退药患者分页列表 + * + * @param encounterInfoDto 查询条件 + * @param searchKey 模糊查询关键字 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param request 请求数据 + * @return 退药患者分页列表 + */ + R> getReturnMedicinePatientPage(EncounterInfoDto encounterInfoDto, String searchKey, Integer pageNo, + Integer pageSize, HttpServletRequest request); + + /** + * 查询退药信息 + * + * @param encounterId 就诊ID + * @param refundStatus 退药id + * @param itemTable 项目类型 + * @return 退药信息 + */ + R> getReturnMedicineInfo(Long encounterId, Integer refundStatus, String itemTable); + + /** + * 退药处理 + * + * @param medicineReturnList 退药清单 + * @return 处理结果 + */ + R> medicineReturn(List medicineReturnList); +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IMedicalDeviceDispenseAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IMedicalDeviceDispenseAppService.java new file mode 100644 index 000000000..24cb3a08b --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IMedicalDeviceDispenseAppService.java @@ -0,0 +1,72 @@ +package com.healthlink.his.web.pharmacy.dispense.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispense.dto.DispenseItemDto; +import com.healthlink.his.web.pharmacy.dispense.dto.EncounterInfoSearchParam; +import com.healthlink.his.web.pharmacy.dispense.dto.ItemDispenseOrderDto; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 材料发送 应用实现接口 + * + * @author yuxj + * @date 2025/8/21 + */ +public interface IMedicalDeviceDispenseAppService { + + /** + * 页面初始化 + * + * @return 初始化信息 + */ + R> init(); + + /** + * 分页查询病人列表 + * + * @param encounterInfoSearchParam 查询条件 + * @param searchKey 模糊查询关键字 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param request 请求数据 + * @return 病人列表 + */ + R> getEncounterInfoListPage(EncounterInfoSearchParam encounterInfoSearchParam, String searchKey, Integer pageNo, Integer pageSize, + HttpServletRequest request); + + /** + * 发耗材单查询 + * + * @param itemDispenseOrderDto 查询信息 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 发耗材单 + */ + R> getDeviceDispenseOrderList(ItemDispenseOrderDto itemDispenseOrderDto, Integer pageNo, Integer pageSize); + + /** + * 核对发耗材 + * + * @param dispenseDeviceList 发耗材信息 + * @return 处理结果 + */ + R> deviceDispense(List dispenseDeviceList); + + /** + * 发放耗材 + * + * @param chargeItemIds 耗材收费单ids + * @return 处理结果 + */ + R> dispenseMedicalConsumables(List chargeItemIds); + + /** + * 作废 + * + * @param dispenseDeviceList 作废信息 + * @return 处理结果 + */ + R> deviceCancel(List dispenseDeviceList); +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IMedicationDetailsAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IMedicationDetailsAppService.java new file mode 100644 index 000000000..3089f1268 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IMedicationDetailsAppService.java @@ -0,0 +1,78 @@ +package com.healthlink.his.web.pharmacy.dispense.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispense.dto.MedDetailsSearchParam; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 发药明细 应用实现接口 + * + * @author yuanzs + * @date 2025/4/14 + */ +public interface IMedicationDetailsAppService { + + /** + * 页面初始化 + * + * @return 初始化信息 + */ + R> init(); + + /** + * 门诊人员发药明细表 + * + * @param medDetailsSearchParam 查询条件 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param searchKey 模糊查询关键字 + * @param request 请求数据 + * @return 门诊发药明细表 + */ + R> getAmbPractitionerDetailPage(MedDetailsSearchParam medDetailsSearchParam, Integer pageNo, Integer pageSize, + String searchKey, HttpServletRequest request); + + void makeExcelFile(MedDetailsSearchParam medDetailsSearchParam, Integer pageNo, Integer pageSize, String searchKey, + HttpServletResponse response, HttpServletRequest request); + + /** + * 门诊发药明细流水账 + * + * @param medDetailsSearchParam 查询条件 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param searchKey 模糊查询关键字 + * @param request 请求数据 + * @return 门诊发药明细流水账 + */ + R> getAmbMedicationDispenseDetailPage(MedDetailsSearchParam medDetailsSearchParam, Integer pageNo, + Integer pageSize, String searchKey, HttpServletRequest request); +} + +// /** +// * 门诊/住院人员发药明细帐、住院耗材记账领用明细 +// * +// * @param medDetailsSearchParam 查询条件 +// * @param pageNo 当前页码 +// * @param pageSize 查询条数 +// * @param searchKey 模糊查询关键字 +// * @param request 请求数据 +// * @return 门诊/住院人员发药明细、住院耗材记账领用明细分页列表 +// */ +// R> getMedDetailedAccountPage(MedDetailsSearchParam medDetailsSearchParam, Integer pageNo, Integer pageSize, +// String searchKey, HttpServletRequest request); +// +// /** +// * 门诊/住院发药明细流水帐、住院耗材记账领用流水账 +// * +// * @param medDetailsSearchParam 查询条件 +// * @param pageNo 当前页码 +// * @param pageSize 查询条数 +// * @param searchKey 模糊查询关键字 +// * @param request 请求数据 +// * @return 门诊/住院发药明细流水帐、住院耗材记账领用流水账分页列表 +// */ +// R> getMedRunningAccountPage(MedDetailsSearchParam medDetailsSearchParam, Integer pageNo, Integer pageSize, +// String searchKey, HttpServletRequest request); diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IPendingMedicationDetailsAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IPendingMedicationDetailsAppService.java new file mode 100644 index 000000000..79f78b7e8 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IPendingMedicationDetailsAppService.java @@ -0,0 +1,29 @@ +package com.healthlink.his.web.pharmacy.dispense.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispense.dto.PendingMedicationSearchParam; + +import jakarta.servlet.http.HttpServletRequest; + +/** + * 待发药明细 应用实现接口 + * + * @author yuanzs + * @date 2025/4/14 + */ +public interface IPendingMedicationDetailsAppService { + + /** + * 分页查询待发药明细 + * + * @param pendingMedicationSearchParam 查询条件 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param searchKey 模糊查询关键字 + * @param request 请求数据 + * @return 待发药明细 + */ + R> getPage(PendingMedicationSearchParam pendingMedicationSearchParam, Integer pageNo, Integer pageSize, + String searchKey, HttpServletRequest request); + +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IReturnMedicineAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IReturnMedicineAppService.java new file mode 100644 index 000000000..109af413c --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IReturnMedicineAppService.java @@ -0,0 +1,54 @@ +package com.healthlink.his.web.pharmacy.dispense.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispense.dto.EncounterInfoDto; +import com.healthlink.his.web.pharmacy.dispense.dto.ReturnMedicineDto; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 退药管理 应用实现接口 + * + * @author yangmo + * @date 2025/4/4 + */ +public interface IReturnMedicineAppService { + + /** + * 页面初始化 + * + * @return 初始化信息 + */ + R> init(); + + /** + * 查询退药患者分页列表 + * + * @param encounterInfoDto 查询条件 + * @param searchKey 模糊查询关键字 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param request 请求数据 + * @return 退药患者分页列表 + */ + R> getReturnMedicinePatientPage(EncounterInfoDto encounterInfoDto, String searchKey, Integer pageNo, + Integer pageSize, HttpServletRequest request); + + /** + * 查询退药信息 + * + * @param encounterId 就诊ID + * @param refundStatus 退药id + * @return 退药信息 + */ + R> getReturnMedicineInfo(Long encounterId, Integer refundStatus); + + /** + * 退药处理 + * + * @param medicineReturnList 退药清单 + * @return 处理结果 + */ + R> medicineReturn(List medicineReturnList); +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/ISummaryDispenseMedicineAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/ISummaryDispenseMedicineAppService.java new file mode 100644 index 000000000..77f2734d7 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/ISummaryDispenseMedicineAppService.java @@ -0,0 +1,54 @@ +package com.healthlink.his.web.pharmacy.dispense.appservice; + +import com.core.common.core.domain.R; + +import java.util.List; + +/** + * 住院汇总发药 应用实现接口 + * + * @author yuxj + * @date 2025/6/3 + */ +public interface ISummaryDispenseMedicineAppService { + + /** + * 汇总发药 + * + * @param summaryNoList 汇总单列表 + * @return 处理结果 + */ + R> SummaryDispenseMedicine(List summaryNoList); + + /** + * 作废 + * + * @param summaryNoList 汇总单列表 + * @return 处理结果 + */ + R> dispenseCancel(List summaryNoList); + + // /** + // * 住院发药 + // * + // * @param searchParam 查询条件 + // * @param searchKey 模糊查询关键字 + // * @param pageNo 当前页码 + // * @param pageSize 查询条数 + // * @param request 请求数据 + // */ + // void makeExcelFile(MedicineSummarySearchParam searchParam, Integer pageNo, Integer pageSize, String searchKey, + // HttpServletRequest request, HttpServletResponse response); + // + // /** + // * 住院汇总 + // * + // * @param searchParam 查询条件 + // * @param searchKey 模糊查询关键字 + // * @param pageNo 当前页码 + // * @param pageSize 查询条数 + // * @param request 请求数据 + // */ + // void takeExcelField(FromSearchParam searchParam, String searchKey, Integer pageNo, Integer pageSize, + // HttpServletRequest request, HttpServletResponse response); +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IWesternMedicineDispenseAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IWesternMedicineDispenseAppService.java new file mode 100644 index 000000000..2b62e299f --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/IWesternMedicineDispenseAppService.java @@ -0,0 +1,72 @@ +package com.healthlink.his.web.pharmacy.dispense.appservice; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.pharmacy.dispense.dto.DispenseItemDto; +import com.healthlink.his.web.pharmacy.dispense.dto.EncounterInfoSearchParam; +import com.healthlink.his.web.pharmacy.dispense.dto.ItemDispenseOrderDto; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 处方管理 应用实现接口 + * + * @author wangyang + * @date 2025/3/18 + */ +public interface IWesternMedicineDispenseAppService { + + /** + * 页面初始化 + * + * @return 初始化信息 + */ + R> init(); + + /** + * 分页查询病人列表 + * + * @param encounterInfoSearchParam 查询条件 + * @param searchKey 模糊查询关键字 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param request 请求数据 + * @return 病人列表 + */ + R> getEncounterInfoListPage(EncounterInfoSearchParam encounterInfoSearchParam, String searchKey, Integer pageNo, + Integer pageSize, HttpServletRequest request); + + /** + * 处方单查询 + * + * @param itemDispenseOrderDto 查询信息 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 处方单 + */ + R> getMedicineDispenseOrderList(ItemDispenseOrderDto itemDispenseOrderDto, Integer pageNo, Integer pageSize); + + /** + * 配药 + * + * @param dispenseMedicineList 配药信息 + * @return 处理结果 + */ + R> medicinePrepare(List dispenseMedicineList); + + /** + * 处方单核对发药 + * + * @param dispenseMedicineList 发药信息 + * @return 处理结果 + */ + R> medicineDispense(List dispenseMedicineList); + + /** + * 作废 + * + * @param dispenseMedicineList 作废信息 + * @return 处理结果 + */ + R> medicineCancel(List dispenseMedicineList); +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/impl/InHospitalReturnMedicineAppServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/impl/InHospitalReturnMedicineAppServiceImpl.java new file mode 100644 index 000000000..82aaf9061 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/impl/InHospitalReturnMedicineAppServiceImpl.java @@ -0,0 +1,741 @@ +/* + * Copyright ©2023 CJB-CNIT Team. All rights reserved + */ +package com.healthlink.his.web.pharmacy.dispense.appservice.impl; + +import java.math.BigDecimal; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.tuple.Pair; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import tools.jackson.databind.JsonNode; +import tools.jackson.databind.node.ArrayNode; +import tools.jackson.databind.node.ObjectNode; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.core.common.core.domain.R; +import com.core.common.exception.ServiceException; +import com.core.common.utils.AgeCalculatorUtil; +import com.core.common.utils.DateUtils; +import com.core.common.utils.MessageUtils; +import com.core.common.utils.SecurityUtils; +import com.healthlink.his.administration.domain.*; +import com.healthlink.his.administration.service.*; +import com.healthlink.his.common.constant.CommonConstants; +import com.healthlink.his.common.constant.PromptMsgConstant; +import com.healthlink.his.common.enums.*; +import com.healthlink.his.yb.enums.YbInvChgType; +import com.healthlink.his.yb.enums.YbMdtrtCertType; +import com.healthlink.his.yb.enums.YbRxFlag; +import com.healthlink.his.common.utils.EnumUtils; +import com.healthlink.his.common.utils.HisQueryUtils; +import com.healthlink.his.financial.domain.Contract; +import com.healthlink.his.financial.domain.PaymentReconciliation; +import com.healthlink.his.financial.service.IContractService; +import com.healthlink.his.financial.service.IPaymentReconciliationService; +import com.healthlink.his.medication.domain.MedicationDefinition; +import com.healthlink.his.medication.domain.MedicationDispense; +import com.healthlink.his.medication.domain.MedicationRequest; +import com.healthlink.his.medication.service.IMedicationDefinitionService; +import com.healthlink.his.medication.service.IMedicationDispenseService; +import com.healthlink.his.medication.service.IMedicationRequestService; +import com.healthlink.his.web.inventorymanage.appservice.impl.ReceiptApprovalAppServiceImpl; +import com.healthlink.his.web.inventorymanage.dto.SupplyItemDetailDto; +import com.healthlink.his.web.pharmacy.dispense.appservice.IInHospitalReturnMedicineAppService; +import com.healthlink.his.web.pharmacy.dispense.dto.*; +import com.healthlink.his.web.pharmacy.dispense.mapper.InHospitalReturnMedicineAppMapper; +import com.healthlink.his.web.pharmacy.dispense.mapper.ReturnMedicineMapper; +import com.healthlink.his.workflow.domain.DeviceDispense; +import com.healthlink.his.workflow.domain.InventoryItem; +import com.healthlink.his.workflow.service.IDeviceDispenseService; +import com.healthlink.his.workflow.service.IDeviceRequestService; +import com.healthlink.his.workflow.service.IInventoryItemService; +import com.healthlink.his.yb.domain.ClinicSettle; +import com.healthlink.his.yb.dto.Medical3506Param; +import com.healthlink.his.yb.dto.MedicalInventory3511Param; +import com.healthlink.his.yb.service.IClinicSettleService; +import com.healthlink.his.yb.service.IYbManager; + +/** + * TODO:概括描述当前类的主要用途和注意事项 + * + * @author zwh + * @date 2025-12-29 + */ +@Service +public class InHospitalReturnMedicineAppServiceImpl implements IInHospitalReturnMedicineAppService { + + @Resource + private ITraceNoManageService traceNoManageService; + + @Resource + private IOrganizationService iOrganizationService; + + @Resource + private IInventoryItemService iInventoryItemService; + + @Resource + private InHospitalReturnMedicineAppMapper inHospitalReturnMedicineAppMapper; + + @Resource + private ReturnMedicineMapper returnMedicineMapper; + + @Resource + private IMedicationRequestService medicationRequestService; + + @Resource + private IMedicationDispenseService medicationDispenseService; + + @Resource + private IDeviceDispenseService deviceDispenseService; + + @Resource + private IDeviceRequestService deviceRequestService; + + @Resource + private IYbManager ybService; + + @Resource + private IChargeItemService iChargeItemService; + + @Resource + private IPaymentReconciliationService iPaymentReconciliationService; + + @Resource + private IContractService iContractService; + + @Resource + private IClinicSettleService clinicSettleService; + + @Resource + private IEncounterDiagnosisService encounterDiagnosisService; + + @Resource + private IAccountService accountService; + + @Resource + private IDeviceDefinitionService deviceDefinitionService; + + @Resource + private IMedicationDefinitionService medicationDefinitionService; + + @Resource + private ReceiptApprovalAppServiceImpl receiptApprovalAppService; + + /** + * 获取页面初始化信息 + * + * @return 初始化信息 + */ + @Override + public R> init() { + + ReturnMedicineInitDto initDto = new ReturnMedicineInitDto(); + + // 获取科室下拉选列表 + List organizationList = + iOrganizationService.getList(OrganizationType.DEPARTMENT.getValue(), String.valueOf(OrganizationClass.CLINIC.getValue())); + List organizationOptions = organizationList.stream().map( + organization -> new ReturnMedicineInitDto.DepartmentOption(organization.getId(), organization.getName())) + .collect(Collectors.toList()); + + // 发药状态 + List refundStatusOptions = new ArrayList<>(); + refundStatusOptions.add(new ReturnMedicineInitDto.RefundStatusOption(DispenseStatus.PENDING_REFUND.getValue(), + DispenseStatus.PENDING_REFUND.getInfo())); + refundStatusOptions.add(new ReturnMedicineInitDto.RefundStatusOption(DispenseStatus.REFUNDED.getValue(), + DispenseStatus.REFUNDED.getInfo())); + initDto.setDepartmentOptions(organizationOptions).setRefundStatusOptions(refundStatusOptions); + return R.ok(initDto); + } + + /** + * 查询退药患者分页列表 + * + * @param encounterInfoDto 查询条件 + * @param searchKey 模糊查询关键字 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param request 请求数据 + * @return 退药患者分页列表 + */ + @Override + public R> getReturnMedicinePatientPage(EncounterInfoDto encounterInfoDto, String searchKey, Integer pageNo, + Integer pageSize, HttpServletRequest request) { + Integer refundEnum = encounterInfoDto.getRefundEnum(); + encounterInfoDto.setRefundEnum(null); + // 构建查询条件 + QueryWrapper queryWrapper = HisQueryUtils.buildQueryWrapper(encounterInfoDto, searchKey, + new HashSet<>(Arrays.asList(CommonConstants.FieldName.PatientName, CommonConstants.FieldName.IdCard, + CommonConstants.FieldName.PatientPyStr, CommonConstants.FieldName.PatientWbStr)), + request); + // 查询退药患者分页列表 + Page encounterInfoPage = inHospitalReturnMedicineAppMapper.selectEncounterInfoListPage( + new Page<>(pageNo, pageSize), queryWrapper, refundEnum, DispenseStatus.PENDING_REFUND.getValue(), + DispenseStatus.REFUNDED.getValue(), EncounterClass.IMP.getValue(), + CommonConstants.TableName.MED_MEDICATION_DEFINITION, CommonConstants.TableName.ADM_DEVICE_DEFINITION); + encounterInfoPage.getRecords().forEach(encounterInfo -> { + // 性别 + encounterInfo.setGenderEnum_enumText( + EnumUtils.getInfoByValue(AdministrativeGender.class, encounterInfo.getGenderEnum())); + // 年龄 + encounterInfo.setAge(AgeCalculatorUtil.getAge(encounterInfo.getBirthDate())); + // 退药状态 + encounterInfo + .setRefundEnum_enumText(EnumUtils.getInfoByValue(DispenseStatus.class, encounterInfo.getRefundEnum())); + }); + return R.ok(encounterInfoPage); + } + + /** + * 查询退药信息 + * + * @param encounterId 就诊ID + * @param refundStatus 退药id + * @param itemTable 项目类型 + * @return 退药信息 + */ + @Override + public R> getReturnMedicineInfo(Long encounterId, Integer refundStatus, String itemTable) { + // 获取退药信息 + List returnMedicineInfoList = inHospitalReturnMedicineAppMapper.selectReturnMedicineInfo( + encounterId, CommonConstants.TableName.WOR_DEVICE_REQUEST, CommonConstants.TableName.MED_MEDICATION_REQUEST, + CommonConstants.TableName.MED_MEDICATION_DEFINITION, CommonConstants.TableName.ADM_DEVICE_DEFINITION, + itemTable, refundStatus, DispenseStatus.PENDING_REFUND.getValue(), DispenseStatus.REFUNDED.getValue()); + returnMedicineInfoList.forEach(returnMedicineInfoDto -> { + // 退药状态 + returnMedicineInfoDto.setRefundEnum_enumText( + EnumUtils.getInfoByValue(DispenseStatus.class, returnMedicineInfoDto.getRefundEnum())); + // 退药请求状态 + returnMedicineInfoDto.setReqStatus_enumText( + EnumUtils.getInfoByValue(RequestStatus.class, returnMedicineInfoDto.getReqStatus())); + }); + return R.ok(returnMedicineInfoList); + } + + /** + * 退药处理 + * + * @param medicineReturnList 退药清单 + * @return 处理结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public R> medicineReturn(List medicineReturnList) { + if (medicineReturnList == null || medicineReturnList.isEmpty()) { + return R.ok(); + } + // 分别处理退药与退耗材的请求 + List returnMedicineList = new ArrayList<>(); + List returnDeviceList = new ArrayList<>(); + // 追溯码列表 + List traceNoManageList = new ArrayList<>(); + TraceNoManage traceNoManage; + + medicineReturnList.forEach(item -> { + switch (item.getTableName()) { + case CommonConstants.TableName.MED_MEDICATION_REQUEST -> returnMedicineList + .add(new ReturnMedicineDto().setDispenseId(item.getDispenseId()).setRequestId(item.getRequestId())); + case CommonConstants.TableName.WOR_DEVICE_REQUEST -> returnDeviceList + .add(new ReturnMedicineDto().setDispenseId(item.getDispenseId()).setRequestId(item.getRequestId())); + } + }); + // 进销存参数 + List supplyItemDetailList = new ArrayList<>(); + + // 记录未发药(无库存变动)的发药单ID + Set noInventoryUpdateMedIds = new HashSet<>(); + Set noInventoryUpdateDevIds = new HashSet<>(); + + // 处理退药 + // 获取药品退药id列表 + List medReturnIdList = new ArrayList<>(); + if (!returnMedicineList.isEmpty()) { + // 获取药品退药id列表 + medReturnIdList = + returnMedicineList.stream().map(ReturnMedicineDto::getDispenseId).collect(Collectors.toList()); + // 获取药品退药请求id列表 + List medRequestIdList = + returnMedicineList.stream().map(ReturnMedicineDto::getRequestId).collect(Collectors.toList()); + if (medReturnIdList.isEmpty()) { + throw new ServiceException("请选择要退的药品"); + } + if (medRequestIdList.isEmpty()) { + throw new ServiceException("请选择要退的药品"); + } + // 药品退药信息查询 + List refundMedList = medicationDispenseService.listByIds(medReturnIdList); + // 药品退药请求查询 + List refundMedRequestList = medicationRequestService.listByIds(medRequestIdList); + if (refundMedList == null || refundMedList.isEmpty()) { + throw new ServiceException("请选择要退的药品"); + } + // 重复退药校验 + if (refundMedList.stream().map(MedicationDispense::getStatusEnum) + .anyMatch(x -> x.equals(DispenseStatus.REFUNDED.getValue()))) { + throw new ServiceException("药品已退药,请勿重复退药"); + } + + // 在更新退药单状态前,统计出实际没有发药(已发药数量为0/空)的退药单,避免后续加回库存和报错 + for (MedicationDispense medicationDispense : refundMedList) { + if (medicationDispense.getDispenseQuantity() == null + || medicationDispense.getDispenseQuantity().compareTo(BigDecimal.ZERO) == 0) { + noInventoryUpdateMedIds.add(medicationDispense.getId()); + } + } + + // 更新退药单 + for (MedicationDispense medicationDispense : refundMedList) { + // 退药状态 + medicationDispense.setStatusEnum(DispenseStatus.REFUNDED.getValue()); + // 退药数量 + medicationDispense.setDispenseQuantity(medicationDispense.getQuantity()); + // 状态变更时间 + medicationDispense.setStatusChangedTime(DateUtils.getNowDate()); + // 退药时间 + medicationDispense.setDispenseTime(DateUtils.getNowDate()); + // 退药人 + medicationDispense.setPractitionerId(SecurityUtils.getPractitionerId()); + + // 设置库存变更参数(仅针对实际发过药的药品) + if (!noInventoryUpdateMedIds.contains(medicationDispense.getId())) { + SupplyItemDetailDto supplyItemDetailDto = new SupplyItemDetailDto(); + for (MedicationRequest medicationRequest : refundMedRequestList) { + // 根据退药id查询退药请求id(用于医保关联) + if (medicationDispense.getMedReqId().equals(medicationRequest.getId())) { + supplyItemDetailDto.setRequestId(medicationRequest.getRefundMedicineId()); + } + } + supplyItemDetailDto.setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION) + .setItemId(medicationDispense.getMedicationId()).setLotNumber(medicationDispense.getLotNumber()); + supplyItemDetailList.add(supplyItemDetailDto); + } + + // 追溯码表相关处理(仅针对实际发过药的药品) + if (!noInventoryUpdateMedIds.contains(medicationDispense.getId()) && medicationDispense.getTraceNo() != null) { + // 使用逗号分割追溯码并转换为List + String[] traceNoList = medicationDispense.getTraceNo().split(CommonConstants.Common.COMMA); + for (String item : traceNoList) { + traceNoManage = new TraceNoManage(); + // 追溯码处理 + traceNoManage.setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION) + // 项目id + .setItemId(medicationDispense.getMedicationId()) + // 仓库类型 + .setLocationTypeEnum(null) + // 仓库 + .setLocationId(medicationDispense.getLocationId()) + // 仓位 + .setLocationStoreId(null) + // 产品批号 + .setLotNumber(medicationDispense.getLotNumber()) + // 追溯码 + .setTraceNo(item) + // 追溯码状态 + .setStatusEnum(TraceNoStatus.IN.getValue()) + // 追溯码单位 + .setUnitCode(medicationDispense.getUnitCode()) + // 操作类型 + .setOperationType(SupplyType.RETURN_MEDICATION.getValue()); + traceNoManageList.add(traceNoManage); + } + } + } + // 退药更新 + medicationDispenseService.updateBatchById(refundMedList); + + // 退药完成后,检查医嘱关联的发药记录是否全部退完,如果是则回写医嘱状态为已停止 + // 解决:医嘱取消(status=5)后退药完成,医嘱状态未变更,导致护士站"待处理执行单"仍显示已退完的医嘱 + Set distinctMedReqIds = refundMedList.stream() + .map(MedicationDispense::getMedReqId).collect(Collectors.toSet()); + for (Long medReqId : distinctMedReqIds) { + // 查询该医嘱下所有发药记录 + List allDispenses = medicationDispenseService.list( + new LambdaQueryWrapper() + .eq(MedicationDispense::getMedReqId, medReqId) + .eq(MedicationDispense::getDeleteFlag, "0")); + // 判断是否全部已退药 + boolean allRefunded = allDispenses.stream() + .allMatch(d -> DispenseStatus.REFUNDED.getValue().equals(d.getStatusEnum())); + if (allRefunded) { + // 回写医嘱状态:取消/待退(5) → 已停止(6) + // STOPPED(6)会被护士站查询排除,不再出现在"待处理执行单"中 + medicationRequestService.update( + new LambdaUpdateWrapper() + .eq(MedicationRequest::getId, medReqId) + .eq(MedicationRequest::getStatusEnum, RequestStatus.CANCELLED.getValue()) + .set(MedicationRequest::getStatusEnum, RequestStatus.STOPPED.getValue())); + } + } + } + + // 处理退耗材 + // 获取退耗材id列表 + List devReturnIdList = new ArrayList<>(); + if (!returnDeviceList.isEmpty()) { + // 获取退耗材id列表 + devReturnIdList = + returnDeviceList.stream().map(ReturnMedicineDto::getDispenseId).collect(Collectors.toList()); + // 获取退耗材请求id列表 + List devRequestIdList = returnDeviceList.stream().map(ReturnMedicineDto::getRequestId).collect(Collectors.toList()); + if (devReturnIdList.isEmpty()) { + throw new ServiceException("请选择要退的耗材"); + } + if (devRequestIdList.isEmpty()) { + throw new ServiceException("请选择要退的耗材"); + } + // 退耗材信息查询 + List refundDevList = deviceDispenseService.listByIds(devReturnIdList); + if (refundDevList == null || refundDevList.isEmpty()) { + throw new ServiceException("请选择要退的耗材"); + } + // 重复退耗材校验 + if (refundDevList.stream().map(DeviceDispense::getStatusEnum) + .anyMatch(x -> x.equals(DispenseStatus.REFUNDED.getValue()))) { + throw new ServiceException("耗材已退,请勿重复操作"); + } + + // 在更新退耗材单状态前,统计出实际没有发放(已发放数量为0/空)的退耗材单 + for (DeviceDispense deviceDispense : refundDevList) { + if (deviceDispense.getDispenseQuantity() == null + || deviceDispense.getDispenseQuantity().compareTo(BigDecimal.ZERO) == 0) { + noInventoryUpdateDevIds.add(deviceDispense.getId()); + } + } + + // 更新退耗材单状态 + for (DeviceDispense deviceDispense : refundDevList) { + // 退药时间 + deviceDispense.setDispenseTime(DateUtils.getNowDate()); + // 退药数量 + deviceDispense.setDispenseQuantity(deviceDispense.getQuantity()); + // 退药状态 + deviceDispense.setStatusEnum(DispenseStatus.REFUNDED.getValue()); + // 设置库存变更参数(仅针对实际发放过的耗材) + if (!noInventoryUpdateDevIds.contains(deviceDispense.getId())) { + supplyItemDetailList + .add(new SupplyItemDetailDto().setItemTable(CommonConstants.TableName.ADM_DEVICE_DEFINITION) + .setItemId(deviceDispense.getDeviceDefId()).setLotNumber(deviceDispense.getLotNumber())); + } + } + deviceDispenseService.updateBatchById(refundDevList); + } + + // 追溯码管理表数据追加 + if (!traceNoManageList.isEmpty()) { + traceNoManageService.saveBatch(traceNoManageList); + } + + // 处理退库存 + // 获取库存信息 + List unDispenseInventoryList = + returnMedicineMapper.selectInventoryInfoList(devReturnIdList, medReturnIdList, + CommonConstants.TableName.MED_MEDICATION_DEFINITION, CommonConstants.TableName.ADM_DEVICE_DEFINITION); + // 库存待更新列表 + List inventoryItemList = new ArrayList<>(); + // 根据批号,发放项目,发放药房进行分组处理 + Map> unDispenseInventoryMap = + unDispenseInventoryList.stream().collect(Collectors.groupingBy(x -> x.getItemId() + + CommonConstants.Common.DASH + x.getLotNumber() + CommonConstants.Common.DASH + x.getLocationId())); + if (!unDispenseInventoryMap.isEmpty()) { + for (Map.Entry> entry : unDispenseInventoryMap.entrySet()) { + List inventoryList = entry.getValue(); + if (!inventoryList.isEmpty()) { + // 最小单位数量 + BigDecimal minQuantity = BigDecimal.ZERO; + + for (UnDispenseInventoryDto unDispenseInventoryDto : inventoryList) { + // 过滤未实际发药/发耗材的项目,其库存不加回 + if (noInventoryUpdateMedIds.contains(unDispenseInventoryDto.getDispenseId()) + || noInventoryUpdateDevIds.contains(unDispenseInventoryDto.getDispenseId())) { + continue; + } + BigDecimal quantity = unDispenseInventoryDto.getQuantity(); + if (!unDispenseInventoryDto.getDispenseUnit() + .equals(unDispenseInventoryDto.getInventoryUnitCode())) { + // 转换为小单位进行累加 + quantity = + unDispenseInventoryDto.getQuantity().multiply(unDispenseInventoryDto.getPartPercent()); + } + minQuantity = minQuantity.add(quantity); + } + // 只有当有需要恢复库存的药品/器材时才加回库存 + if (minQuantity.compareTo(BigDecimal.ZERO) > 0) { + // 理论上不出bug的情况下以项目id,批号,仓库进行分组处理库存一定唯一所以get(0) + // 设置待更新的库存信息 + inventoryItemList.add(new InventoryItem().setId(inventoryList.get(0).getInventoryId()) + .setQuantity(inventoryList.get(0).getInventoryQuantity().add(minQuantity))); + } + } + } + // 库存更新 + if (!inventoryItemList.isEmpty()) { + iInventoryItemService.updateBatchById(inventoryItemList); + } + } else { + throw new ServiceException("请检查库存信息"); + } + + // 处理退药医保 + // 返回信息 + String returnMsg = null; + List uploadFailedNoList; + // 调用医保商品销售退货接口 + String ybSwitch = SecurityUtils.getLoginUser().getOptionJsonValue(CommonConstants.Option.YB_SWITCH); // 医保开关 + if (Whether.YES.getCode().equals(ybSwitch)) { + List deviceDefinitions = new ArrayList<>(); + List medicationDefinitions = new ArrayList<>(); + if (!returnMedicineList.isEmpty()) { + // 设置进销存参数 + medicationDefinitions = medicationDefinitionService.listByIds(supplyItemDetailList.stream() + .filter(x -> x.getItemTable().equals(CommonConstants.TableName.MED_MEDICATION_DEFINITION)) + .map(SupplyItemDetailDto::getItemId).collect(Collectors.toList())); + } + if (!returnDeviceList.isEmpty()) { + deviceDefinitions = deviceDefinitionService.listByIds(supplyItemDetailList.stream() + .filter(x -> x.getItemTable().equals(CommonConstants.TableName.ADM_DEVICE_DEFINITION)) + .map(SupplyItemDetailDto::getItemId).collect(Collectors.toList())); + } + + // 创建映射表,添加空集合保护 + Map medicationMap = + medicationDefinitions != null ? medicationDefinitions.stream().filter(Objects::nonNull) + .collect(Collectors.toMap(MedicationDefinition::getId, Function.identity())) : new HashMap<>(); + + Map deviceMap = + deviceDefinitions != null ? deviceDefinitions.stream().filter(Objects::nonNull) + .collect(Collectors.toMap(DeviceDefinition::getId, Function.identity())) : new HashMap<>(); + + // 设置库存变更参数,添加完整判空 + for (SupplyItemDetailDto supplyItemDetailDto : supplyItemDetailList) { + if (supplyItemDetailDto == null) + continue; + if (CommonConstants.TableName.MED_MEDICATION_DEFINITION.equals(supplyItemDetailDto.getItemTable())) { + if (supplyItemDetailDto.getItemId() != null) { + MedicationDefinition med = medicationMap.get(supplyItemDetailDto.getItemId()); + if (med != null) { + supplyItemDetailDto.setItemBusNo(med.getBusNo()).setPartPercent(med.getPartPercent()) + .setRxFlag(med.getRxFlag()).setYbNo(med.getYbNo()); + } + } + } else if (CommonConstants.TableName.ADM_DEVICE_DEFINITION.equals(supplyItemDetailDto.getItemTable())) { + if (supplyItemDetailDto.getItemId() != null) { + DeviceDefinition dev = deviceMap.get(supplyItemDetailDto.getItemId()); + if (dev != null) { + supplyItemDetailDto.setItemBusNo(dev.getBusNo()).setPartPercent(dev.getPartPercent()) + .setRxFlag(dev.getRxFlag()).setYbNo(dev.getYbNo()); + } + } + } + } + + // 仅对实际发过药(生成了收费记录且计费的)调用医保退货接口 + List medReturnIdsForYb = medReturnIdList.stream() + .filter(id -> !noInventoryUpdateMedIds.contains(id)) + .collect(Collectors.toList()); + if (!medReturnIdsForYb.isEmpty()) { + uploadFailedNoList = this.ybReturnIntegrated(medReturnIdsForYb, null); + if (uploadFailedNoList != null) { + returnMsg = "3506商品销售退货上传错误,错误项目编码" + uploadFailedNoList; + } else { + returnMsg = "3506商品销售退货上传成功"; + } + } + + if (!supplyItemDetailList.isEmpty()) { + uploadFailedNoList = receiptApprovalAppService.ybInventoryIntegrated(supplyItemDetailList, + YbInvChgType.OTHER_OUT, DateUtils.getNowDate(), true); + if (uploadFailedNoList != null) { + returnMsg = (returnMsg != null ? returnMsg + ";" : "") + "医保进销存集成上传错误: " + uploadFailedNoList; + } + } + } + // 返回退药成功信息 + return R.ok(returnMsg, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[] {"退药"})); + } + + /** + * 医保退药相关进销存接口 + * + * @param dispenseMedIdList 退药id列表 + * @param dispenseDevIdList 退耗材id列表 + * @return 上传失败的编号集合 + */ + public List ybReturnIntegrated(List dispenseMedIdList, List dispenseDevIdList) { + List uploadFailedNoList = new ArrayList<>(); + R> result; + if (!dispenseMedIdList.isEmpty() || !dispenseDevIdList.isEmpty()) { + // 查询退药项目相关信息 + List dispenseInventoryList = returnMedicineMapper.selectReturnItemDetail( + dispenseDevIdList, dispenseMedIdList, CommonConstants.TableName.MED_MEDICATION_DEFINITION, + CommonConstants.TableName.ADM_DEVICE_DEFINITION); + for (DispenseInventoryDto dispenseInventoryDto : dispenseInventoryList) { + if (dispenseInventoryDto.getYbNo() == null) { + continue; + } + Pair medical3506Pair = getMedical3506Param(dispenseInventoryDto); + // 如果自费则自动取省医保 + Contract contract = medical3506Pair.getRight(); + if (contract != null) { + if (CommonConstants.BusinessName.DEFAULT_CONTRACT_NO + .equals(medical3506Pair.getRight().getBusNo())) { + contract = null; + } + } + result = ybService.cancelMerchandise(medical3506Pair.getLeft(), contract); + if (result.getCode() != 200) { + uploadFailedNoList.add(dispenseInventoryDto.getDispenseNo()); + } + } + } + return uploadFailedNoList; + } + + private Pair getMedical3506Param(DispenseInventoryDto dispenseInventoryDto) { + Medical3506Param medical3506Param = new Medical3506Param(); + ChargeItem chargeItem = null; + if (CommonConstants.TableName.MED_MEDICATION_DEFINITION.equals(dispenseInventoryDto.getItemTable())) { + // 查询费用结算信息 + chargeItem = iChargeItemService.getOne(new LambdaQueryWrapper() + .eq(ChargeItem::getServiceTable, CommonConstants.TableName.MED_MEDICATION_REQUEST) + .eq(ChargeItem::getServiceId, dispenseInventoryDto.getRefundId()) + .eq(ChargeItem::getTenantId, SecurityUtils.getLoginUser().getTenantId())); + } else if (CommonConstants.TableName.ADM_DEVICE_DEFINITION.equals(dispenseInventoryDto.getItemTable())) { + chargeItem = iChargeItemService.getOne(new LambdaQueryWrapper() + .eq(ChargeItem::getServiceTable, CommonConstants.TableName.WOR_DEVICE_REQUEST) + .eq(ChargeItem::getServiceId, dispenseInventoryDto.getRefundId()) + .eq(ChargeItem::getTenantId, SecurityUtils.getLoginUser().getTenantId())); + } + if (chargeItem == null) { + throw new ServiceException("未查询到收费项"); + } + // 查询就诊诊断信息 + EncounterDiagnosis encounterDiagnosis = encounterDiagnosisService.getById(chargeItem.getEncounterDiagnosisId()); + if (encounterDiagnosis == null) { + throw new ServiceException("未查找到就诊诊断信息"); + } + // 查询付款信息 + PaymentReconciliation paymentReconciliation = + iPaymentReconciliationService.getOne(new LambdaQueryWrapper() + .eq(PaymentReconciliation::getEncounterId, chargeItem.getEncounterId()) + .like(PaymentReconciliation::getChargeItemIds, chargeItem.getId()) + .eq(PaymentReconciliation::getStatusEnum, PaymentStatus.SUCCESS.getValue()) + .eq(PaymentReconciliation::getPatientId, chargeItem.getPatientId()) + .eq(PaymentReconciliation::getPaymentEnum, PaymentType.PAY.getValue())); + if (paymentReconciliation == null) { + throw new ServiceException("未查询到收费"); + } + + // 查询账户信息 + Account account = accountService + .getOne(new LambdaQueryWrapper().eq(Account::getEncounterId, chargeItem.getEncounterId()) + .eq(Account::getEncounterFlag, Whether.YES.getValue())); + if (account == null) { + throw new ServiceException("未查询到账户"); + } + // 查询合同实体 + Contract contract = + iContractService.getOne(new LambdaQueryWrapper().eq(Contract::getBusNo, account.getContractNo())); + if (contract == null) { + throw new ServiceException("未查询到合同信息"); + } + YbMdtrtCertType mdtrtCertType; + if (AccountType.PERSONAL_CASH_ACCOUNT.getCode().equals(account.getTypeCode())) { + mdtrtCertType = YbMdtrtCertType.MDTRT_CERT_TYPE02; + } else { + mdtrtCertType = YbMdtrtCertType.getByValue(account.getTypeCode());// 2025/05/28 该值存01/02/03 + } + if (mdtrtCertType == null) { + throw new ServiceException("未查询到电子凭证"); + } + // 查询就诊id + if (contract.getCategoryEnum().equals(Category.SELF.getValue()) + || contract.getCategoryEnum().equals(Category.PUBLIC.getValue())) { + medical3506Param.setMdtrtSn(dispenseInventoryDto.getEncounterNo()); + } else { + ClinicSettle clinicSettle = clinicSettleService.getOne(new LambdaQueryWrapper() + .in(ClinicSettle::getSetlId, List.of(paymentReconciliation.getYbSettleIds())) + .eq(ClinicSettle::getMedType, encounterDiagnosis.getMedTypeCode()).last(" LIMIT 1")); + if (clinicSettle != null) { + medical3506Param.setMdtrtSn(clinicSettle.getMdtrtId()); + } else { + medical3506Param.setMdtrtSn(dispenseInventoryDto.getEncounterNo()); + } + } + // // 查询发票信息 + // Invoice invoice = iInvoiceService.getById(paymentReconciliation.getInvoiceId()); + // if (invoice == null) { + // throw new ServiceException("未查询到发票信息"); + // } + // 转换为JSON + ArrayNode medicalTraceNo = new tools.jackson.databind.ObjectMapper().createArrayNode(); + // 获取追溯码信息 + if (dispenseInventoryDto.getTraceNo() != null) { + List traceNoList = + Arrays.stream(dispenseInventoryDto.getTraceNo().split(CommonConstants.Common.COMMA)).map(String::trim) + .filter(s -> !s.isEmpty()).toList(); + for (String traceNo : traceNoList) { + ObjectNode traceNoMap = new tools.jackson.databind.ObjectMapper().createObjectNode(); + traceNoMap.put("drug_trac_codg", traceNo); + medicalTraceNo.add(traceNoMap); + } + } + medical3506Param.setMedListCodg(dispenseInventoryDto.getYbNo()) + .setFixmedinsBchno(dispenseInventoryDto.getRefundId().toString()) + .setFixmedinsHilistId(dispenseInventoryDto.getItemNo()) + .setFixmedinsHilistName(CommonConstants.TableName.MED_MEDICATION_DEFINITION) + .setPsnCertType(mdtrtCertType.getValue()).setManuLotnum(dispenseInventoryDto.getLotNumber()) + .setManuDate(dispenseInventoryDto.getProductionDate()) + .setSelRetnCnt(new BigDecimal(dispenseInventoryDto.getDispenseQuantity().toString())) + .setSelRetnTime(dispenseInventoryDto.getDispenseTime()).setExpyEnd(dispenseInventoryDto.getExpirationDate()) + .setDrugtracinfo(medicalTraceNo).setCertno(dispenseInventoryDto.getIdCard()); + // 查看所属医院 + String fixmedinsCode = + SecurityUtils.getLoginUser().getOptionJsonValue(CommonConstants.Option.FIXMEDINS_CODE); + if (dispenseInventoryDto.getPreparerName() == null && HospitalCodeEnum.CCU.getCode().equals(fixmedinsCode)) { + medical3506Param.setSelRetnOpterName(CommonConstants.CCU.DisDeviceDoctorName); + } else { + medical3506Param.setSelRetnOpterName(dispenseInventoryDto.getPreparerName()); + } + if (dispenseInventoryDto.getInventoryUnitCode().equals(dispenseInventoryDto.getDispenseUnitCode())) { + medical3506Param.setTrdnFlag(Whether.YES.getCode()); + } else { + medical3506Param.setTrdnFlag(Whether.NO.getCode()); + } + if (YbRxFlag.IMPORTANT_HERBAL_SLICES.getCode() == dispenseInventoryDto.getRxFlag()) { + medical3506Param.setRxFlag(YbRxFlag.IMPORTANT_HERBAL_SLICES.getName()); + } else if (YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getCode() == dispenseInventoryDto.getRxFlag()) { + medical3506Param.setRxFlag(YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getName()); + } else if (YbRxFlag.SELF_PREPARED_MEDICATION.getCode() == dispenseInventoryDto.getRxFlag()) { + medical3506Param.setRxFlag(YbRxFlag.WESTERN_AND_CHINESE_PATENT_MEDICINE.getName()); + } + if (CommonConstants.TableName.MED_MEDICATION_DEFINITION.equals(dispenseInventoryDto.getItemTable())) { + medical3506Param.setFixmedinsHilistName(CommonConstants.TableName.MED_MEDICATION_DEFINITION); + } else if (CommonConstants.TableName.ADM_DEVICE_DEFINITION.equals(dispenseInventoryDto.getItemTable())) { + medical3506Param.setFixmedinsHilistName(CommonConstants.TableName.ADM_DEVICE_DEFINITION); + } + return Pair.of(medical3506Param, contract); + } + + private MedicalInventory3511Param getMedical3511Param(DispenseInventoryDto dispenseInventoryDto) { + MedicalInventory3511Param medicalInventory3511Param = new MedicalInventory3511Param(); + + String fixmedinsCode = + SecurityUtils.getLoginUser().getOptionJsonValue(CommonConstants.Option.FIXMEDINS_CODE); + // TODO + medicalInventory3511Param.setFixmedinsCode(fixmedinsCode).setMedinsListCodg(dispenseInventoryDto.getYbNo()) + .setFixmedinsBchno(dispenseInventoryDto.getLotNumber()).setBegndate(dispenseInventoryDto.getDispenseTime()) + .setEnddate(dispenseInventoryDto.getDispenseTime()); + + return medicalInventory3511Param; + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/impl/MedicalDeviceDispenseAppServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/impl/MedicalDeviceDispenseAppServiceImpl.java new file mode 100644 index 000000000..7088ff134 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/pharmacy/dispense/appservice/impl/MedicalDeviceDispenseAppServiceImpl.java @@ -0,0 +1,562 @@ +package com.healthlink.his.web.pharmacy.dispense.appservice.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.core.common.core.domain.R; +import com.core.common.exception.ServiceException; +import com.core.common.utils.AgeCalculatorUtil; +import com.core.common.utils.DateUtils; +import com.core.common.utils.MessageUtils; +import com.core.common.utils.SecurityUtils; +import com.healthlink.his.administration.domain.ChargeItem; +import com.healthlink.his.administration.domain.Organization; +import com.healthlink.his.administration.domain.Practitioner; +import com.healthlink.his.administration.domain.TraceNoManage; +import com.healthlink.his.administration.service.IChargeItemService; +import com.healthlink.his.administration.service.IDeviceDefinitionService; +import com.healthlink.his.administration.service.IOrganizationService; +import com.healthlink.his.administration.service.ITraceNoManageService; +import com.healthlink.his.common.constant.CommonConstants; +import com.healthlink.his.common.constant.PromptMsgConstant; +import com.healthlink.his.common.enums.*; +import com.healthlink.his.common.utils.EnumUtils; +import com.healthlink.his.common.utils.HisQueryUtils; +import com.healthlink.his.web.inventorymanage.appservice.impl.ReceiptApprovalAppServiceImpl; +import com.healthlink.his.web.inventorymanage.dto.SupplyItemDetailDto; +import com.healthlink.his.web.pharmacy.dispense.appservice.IMedicalDeviceDispenseAppService; +import com.healthlink.his.web.pharmacy.dispense.dto.*; +import com.healthlink.his.web.pharmacy.dispense.mapper.MedicalDeviceDispenseMapper; +import com.healthlink.his.web.pharmacy.dispense.mapper.ReturnMedicineMapper; +import com.healthlink.his.workflow.domain.DeviceDispense; +import com.healthlink.his.workflow.domain.InventoryItem; +import com.healthlink.his.workflow.service.IDeviceDispenseService; +import com.healthlink.his.workflow.service.IInventoryItemService; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +; + +/** + * 材料发送 应用实现类 + * + * @author yuxj + * @date 2025/8/21 + */ +@Service +public class MedicalDeviceDispenseAppServiceImpl implements IMedicalDeviceDispenseAppService { + + @Resource + private IOrganizationService organizationService; + + @Resource + private IDeviceDispenseService deviceDispenseService; + + @Resource + private IInventoryItemService inventoryItemService; + + @Resource + private MedicalDeviceDispenseMapper medicalDeviceDispenseMapper; + + @Resource + private ReturnMedicineMapper returnMedicineMapper; + + @Resource + private ITraceNoManageService traceNoManageService; + + @Resource + private WesternMedicineDispenseAppServiceImpl westernMedicineDispenseAppService; + + @Resource + private IChargeItemService chargeItemService; + + @Resource + private IDeviceDefinitionService deviceDefinitionService; + + @Resource + private ReceiptApprovalAppServiceImpl receiptApprovalAppService; + + /** + * 获取页面初始化信息 + * + * @return 初始化信息 + */ + @Override + public R> init() { + + DispenseInitDto initDto = new DispenseInitDto(); + + // 获取科室下拉选列表 + List organizationList + = organizationService.getList(OrganizationType.DEPARTMENT.getValue(), String.valueOf(OrganizationClass.CLINIC.getValue())); + List organizationOptions = organizationList.stream() + .map(organization -> new DispenseInitDto.DepartmentOption(organization.getId(), organization.getName())) + .collect(Collectors.toList()); + + // 获取配药人下拉选列表 + List preparerDoctorList + = medicalDeviceDispenseMapper.getPreparerDoctorList(PractitionerRoles.PHARMACIST.getCode()); + List preparerDoctorOptions = preparerDoctorList.stream() + .map(practitioner -> new DispenseInitDto.PreparerDoctorOption(practitioner.getId(), practitioner.getName())) + .collect(Collectors.toList()); + + // 未发药原因下拉选列表 + List notPerformedReasonOptions + = Stream.of(NotPerformedReasonEnum.values()) + .map(notPerformedReason -> new DispenseInitDto.NotPerformedReasonOption(notPerformedReason.getValue(), + notPerformedReason.getInfo())) + .collect(Collectors.toList()); + + // 发药状态 + List dispenseStatusOptions = new ArrayList<>(); + dispenseStatusOptions.add(new DispenseStatusOption(DispenseStatus.IN_PROGRESS.getValue(), + DispenseStatus.IN_PROGRESS.getInfo())); + dispenseStatusOptions.add(new DispenseStatusOption(DispenseStatus.COMPLETED.getValue(), + DispenseStatus.COMPLETED.getInfo())); + + initDto.setDepartmentOptions(organizationOptions).setNotPerformedReasonOptions(notPerformedReasonOptions) + .setDispenseStatusOptions(dispenseStatusOptions).setPreparerDoctorOptions(preparerDoctorOptions); + return R.ok(initDto); + } + + /** + * 分页查询病人列表 + * + * @param encounterInfoSearchParam 查询条件 + * @param searchKey 模糊查询关键字 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @param request 请求数据 + * @return 病人列表 + */ + @Override + public R> getEncounterInfoListPage(EncounterInfoSearchParam encounterInfoSearchParam, String searchKey, + Integer pageNo, Integer pageSize, HttpServletRequest request) { + // 发药状态初始化 + Integer statusEnum = encounterInfoSearchParam.getStatusEnum(); + encounterInfoSearchParam.setStatusEnum(null); + // 构建查询条件 + QueryWrapper queryWrapper + = HisQueryUtils.buildQueryWrapper(encounterInfoSearchParam, searchKey, + new HashSet<>(Arrays.asList(CommonConstants.FieldName.PatientName, CommonConstants.FieldName.IdCard, + CommonConstants.FieldName.PatientPyStr, CommonConstants.FieldName.PatientWbStr)), + request); + // 查询就诊病人列表 + Page encounterInfoPage + = medicalDeviceDispenseMapper.selectEncounterInfoListPage(new Page<>(pageNo, pageSize), queryWrapper, + statusEnum, DispenseStatus.IN_PROGRESS.getValue(), DispenseStatus.COMPLETED.getValue(), + DispenseStatus.PREPARATION.getValue(), DispenseStatus.PREPARED.getValue()); + encounterInfoPage.getRecords().forEach(encounterInfo -> { + // 性别 + encounterInfo.setGenderEnum_enumText( + EnumUtils.getInfoByValue(AdministrativeGender.class, encounterInfo.getGenderEnum())); + // 发药状态 + encounterInfo + .setStatusEnum_enumText(EnumUtils.getInfoByValue(DispenseStatus.class, encounterInfo.getStatusEnum())); + if (encounterInfo.getBirthDate() != null) { + // 计算年龄 + encounterInfo.setAge(AgeCalculatorUtil.getAge(encounterInfo.getBirthDate())); + } + }); + return R.ok(encounterInfoPage); + } + + /** + * 发耗材单查询 + * + * @param itemDispenseOrderDto 查询信息 + * @param pageNo 当前页码 + * @param pageSize 查询条数 + * @return 发耗材单 + */ + @Override + public R> getDeviceDispenseOrderList(ItemDispenseOrderDto itemDispenseOrderDto, Integer pageNo, + Integer pageSize) { + // 发药状态初始化 + Integer dispenseStatus = itemDispenseOrderDto.getStatusEnum(); + itemDispenseOrderDto.setStatusEnum(null); + // 构建查询条件 + QueryWrapper queryWrapper + = HisQueryUtils.buildQueryWrapper(itemDispenseOrderDto, null, null, null); + // 处方单信息查询 + Page deviceDispenseOrderPage + = medicalDeviceDispenseMapper.selectDeviceDispenseOrderPage(new Page<>(pageNo, pageSize), queryWrapper, + DispenseStatus.IN_PROGRESS.getValue(), DispenseStatus.COMPLETED.getValue(), + DispenseStatus.PREPARATION.getValue(), DispenseStatus.PREPARED.getValue(), dispenseStatus); + deviceDispenseOrderPage.getRecords().forEach(deviceDispenseOrder -> { + // 发药状态 + deviceDispenseOrder.setStatusEnum_enumText( + EnumUtils.getInfoByValue(DispenseStatus.class, deviceDispenseOrder.getStatusEnum())); + // 设置所在表名 + deviceDispenseOrder.setItemTable(CommonConstants.TableName.ADM_DEVICE_DEFINITION); + }); + return R.ok(deviceDispenseOrderPage); + } + + /** + * 核对发耗材 + * + * @param dispenseDeviceList 发耗材信息 + * @return 处理结果 + */ + @Override + public R> deviceDispense(List dispenseDeviceList) { + // 配药人检查 + if (dispenseDeviceList.get(0).getPreparerId() == null + || dispenseDeviceList.get(0).getPreparerId().equals(SecurityUtils.getPractitionerId())) { + return R.fail("请选择调配药师"); + } + // 获取发药单id列表 + List