From 421876c7a87dfe2402efba3fa5301f9a87d4d9e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B3=E7=BE=BD?= <关羽@gentronhealth.com> Date: Thu, 14 May 2026 16:26:12 +0800 Subject: [PATCH] =?UTF-8?q?Fix=20Bug=20#517:=20[=E5=BA=93=E6=88=BF?= =?UTF-8?q?=E7=AE=A1=E7=90=86-=E9=A2=86=E7=94=A8=E7=AE=A1=E7=90=86]=20?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E9=80=BB=E8=BE=91=E6=A0=A1=E9=AA=8C=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=EF=BC=9A=E5=85=81=E8=AE=B8=E4=BF=9D=E5=AD=98=E5=B9=B6?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=E9=A2=86=E7=94=A8=E6=95=B0=E9=87=8F=E5=A4=A7?= =?UTF-8?q?=E4=BA=8E=E5=BA=93=E5=AD=98=E6=95=B0=E9=87=8F=EF=BC=88=E9=9B=B6?= =?UTF-8?q?=E5=BA=93=E5=AD=98=E9=A2=86=E7=94=A8=EF=BC=89=E7=9A=84=E5=8D=95?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 RequisitionIssueAppServiceImpl.addOrEditIssueReceipt() 中新增库存校验逻辑, 批量保存时校验领用数量是否超过源仓库实际库存,不足时抛出 ServiceException 阻断保存。 Co-Authored-By: Claude Opus 4.7 --- .../impl/RequisitionIssueAppServiceImpl.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inventorymanage/appservice/impl/RequisitionIssueAppServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inventorymanage/appservice/impl/RequisitionIssueAppServiceImpl.java index 0f82f5625..ed0af2260 100755 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inventorymanage/appservice/impl/RequisitionIssueAppServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inventorymanage/appservice/impl/RequisitionIssueAppServiceImpl.java @@ -3,29 +3,38 @@ */ package com.openhis.web.inventorymanage.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.*; import com.core.common.utils.bean.BeanUtils; +import com.openhis.administration.domain.DeviceDefinition; import com.openhis.administration.domain.Practitioner; +import com.openhis.administration.service.IDeviceDefinitionService; import com.openhis.administration.service.IPractitionerService; import com.openhis.common.constant.CommonConstants; import com.openhis.common.constant.PromptMsgConstant; import com.openhis.common.enums.*; import com.openhis.common.utils.EnumUtils; import com.openhis.common.utils.HisQueryUtils; +import com.openhis.medication.domain.MedicationDefinition; +import com.openhis.medication.service.IMedicationDefinitionService; import com.openhis.web.common.dto.UnitDto; import com.openhis.web.inventorymanage.appservice.IRequisitionIssueAppService; import com.openhis.web.inventorymanage.dto.*; import com.openhis.web.inventorymanage.mapper.RequisitionIssueMapper; +import com.openhis.workflow.domain.InventoryItem; import com.openhis.workflow.domain.SupplyRequest; +import com.openhis.workflow.service.IInventoryItemService; import com.openhis.workflow.service.ISupplyRequestService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -48,6 +57,15 @@ public class RequisitionIssueAppServiceImpl implements IRequisitionIssueAppServi @Autowired private IPractitionerService practitionerService; + @Autowired + private IInventoryItemService inventoryItemService; + + @Autowired + private IMedicationDefinitionService medicationDefinitionService; + + @Autowired + private IDeviceDefinitionService deviceDefinitionService; + @Autowired private AssignSeqUtil assignSeqUtil; @@ -167,6 +185,10 @@ public class RequisitionIssueAppServiceImpl implements IRequisitionIssueAppServi // 单据号取得 List busNoList = requisitionIssueDtoList.stream().map(IssueDto::getBusNo).collect(Collectors.toList()); + + // 库存校验:领用数量不能超过源仓库实际库存 + this.validateRequisitionStock(requisitionIssueDtoList); + // 请求数据取得 List requestList = supplyRequestService.getSupplyByBusNo(busNoList.get(0)); if (!requestList.isEmpty()) { @@ -328,4 +350,73 @@ public class RequisitionIssueAppServiceImpl implements IRequisitionIssueAppServi } } } + + /** + * 校验领用数量是否超过源仓库实际库存 + * + * @param requisitionIssueDtoList 领用出库单据列表 + */ + private void validateRequisitionStock(List requisitionIssueDtoList) { + Integer tenantId = SecurityUtils.getLoginUser().getTenantId(); + for (IssueDto issueDto : requisitionIssueDtoList) { + Long itemId = issueDto.getItemId(); + String lotNumber = issueDto.getLotNumber(); + Long sourceLocationId = issueDto.getSourceLocationId(); + BigDecimal reqQuantity = issueDto.getItemQuantity(); + String itemUnit = issueDto.getUnitCode(); + String itemTable = issueDto.getItemTable(); + + // 根据物品类型查询定义信息(拆零比、常规单位、最小单位) + BigDecimal partPercent = BigDecimal.ONE; + String unitCode = itemUnit; + String minUnitCode = itemUnit; + + if (CommonConstants.TableName.MED_MEDICATION_DEFINITION.equals(itemTable)) { + MedicationDefinition medDef = medicationDefinitionService.getById(itemId); + if (medDef != null) { + unitCode = medDef.getUnitCode(); + minUnitCode = medDef.getMinUnitCode(); + if (medDef.getPartPercent() != null) { + partPercent = medDef.getPartPercent(); + } + } + } else if (CommonConstants.TableName.ADM_DEVICE_DEFINITION.equals(itemTable)) { + DeviceDefinition devDef = deviceDefinitionService.getById(itemId); + if (devDef != null) { + unitCode = devDef.getUnitCode(); + minUnitCode = devDef.getMinUnitCode(); + if (devDef.getPartPercent() != null) { + partPercent = devDef.getPartPercent(); + } + } + } + + // 计算领用数量折合最小单位的值 + BigDecimal reqQuantityInMinUnit; + if (itemUnit.equals(unitCode)) { + // 领用单位 = 包装单位,需乘以拆零比 + reqQuantityInMinUnit = reqQuantity.multiply(partPercent); + } else { + // 领用单位 = 最小单位,无需换算 + reqQuantityInMinUnit = reqQuantity; + } + + // 查询源仓库实际库存(按物品编号、批号、仓库匹配) + List inventoryItemList = inventoryItemService.selectInventoryByItemId( + itemId, lotNumber, sourceLocationId, tenantId); + + // 累加匹配批号的总库存(库存表quantity字段为最小单位) + BigDecimal totalStock = BigDecimal.ZERO; + for (InventoryItem inventoryItem : inventoryItemList) { + if (inventoryItem.getLocationId().equals(sourceLocationId)) { + totalStock = totalStock.add(inventoryItem.getQuantity()); + } + } + + // 比较领用数量与库存 + if (reqQuantityInMinUnit.compareTo(totalStock) > 0) { + throw new ServiceException("操作失败,库存数量不足"); + } + } + } }