Commit c8fe83a9 by zhu.zewen

修复药品专用登记相关专账

修复专账详情筛选
新增专账日结和月结
parent 09ea606e
......@@ -3,6 +3,7 @@ package com.jmai;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.scheduling.annotation.EnableScheduling;
......@@ -15,6 +16,7 @@ import org.springframework.boot.builder.SpringApplicationBuilder;
@SpringBootApplication(scanBasePackages = {
"com.jmai"
})
@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(Application.class);
......
......@@ -29,8 +29,8 @@ public class BillDTO {
@ApiModelProperty(value = "药品数量")
private Integer physicNum;
@ApiModelProperty(value = "类型(处理模式):1-采购入库、2-申领入库、3-申领出库、4-药品专用登记(科室)" +
"、5-回收空安瓿、6-退回空安瓿、7-销毁空安瓿、8-药品专用登记(药房),100-日结,101-月结")
@ApiModelProperty(value = "类型(处理模式):1-采购入库、2-申领入库、3-申领出库、4-科室专用入(药品专用登记)" +
"、5-回收空安瓿、6-退回空安瓿、7-销毁空安瓿、8-药房专用出(药品专用登记),100-日结,101-月结")
private Integer type;
@ApiModelProperty(value = "相关申请、入库等表id")
......
......@@ -4,16 +4,32 @@ import com.jmai.sys.dto.PageReq;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class PhysicBillQueryReq extends PageReq {
@ApiModelProperty(value = "药品名称")
private String physicName;
@ApiModelProperty(value = "规格")
private String physicSpec;
@ApiModelProperty(value = "厂家名称")
private String factoryName;
@ApiModelProperty(value = "类型(处理模式):1-采购入库、2-申领入库、3-申领出库、4-科室专用入(药品专用登记)" +
"、5-回收空安瓿、6-退回空安瓿、7-销毁空安瓿、8-药房专用出(药品专用登记),100-日结,101-月结")
private Integer type;
@ApiModelProperty(value = "状态")
private Integer status;
@ApiModelProperty(value = "创建时间")
private List<LocalDateTime> createTime;
@ApiModelProperty(value = "创建时间开始", hidden = true)
private LocalDateTime createTimeStart;
@ApiModelProperty(value = "创建时间结束", hidden = true)
private LocalDateTime createTimeEnd;
}
......@@ -6,6 +6,9 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDate;
import java.time.YearMonth;
@Data
@ApiModel(description = "药品专账")
@TableName("physic_bill")
......@@ -31,7 +34,8 @@ public class PhysicBill extends BaseVersionEntity {
@ApiModelProperty(value = "凭证号")
private String voucherNo;
@ApiModelProperty(value = "1-采购入库 2-申领入库 3-申领出库")
@ApiModelProperty(value = "类型(处理模式):1-采购入库、2-申领入库、3-申领出库、4-科室专用入(药品专用登记)" +
"、5-回收空安瓿、6-退回空安瓿、7-销毁空安瓿、8-药房专用出(药品专用登记),100-日结,101-月结")
private Integer type;
@ApiModelProperty(value = "收入")
......@@ -39,6 +43,12 @@ public class PhysicBill extends BaseVersionEntity {
@ApiModelProperty(value = "发出")
private Integer expendNum;
@ApiModelProperty(value = "结算日期")
private LocalDate settleDate;
@ApiModelProperty(value = "结算月份(年月)")
private YearMonth settleMonth;
@ApiModelProperty(value = "相关申请、入库id")
private Long refId;
......
......@@ -28,7 +28,7 @@ public class PhysicRecord extends BaseVersionEntity {
@ApiModelProperty(value = "批号")
private String batchNo;
@ApiModelProperty(value = "药品数量")
@ApiModelProperty(value = "药品数量(科室出,药房入)")
private Integer physicNum;
@ApiModelProperty(value = "类型:2-药房,3-科室(参考组织部门)")
......
......@@ -8,8 +8,8 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jmai.api.exception.ServiceException;
import com.jmai.physic.cloudsign.CloudsignService;
import com.jmai.sys.service.ConfigService;
import com.jmai.sys.consts.ConfigTypes;
import com.jmai.sys.dto.ConfigDto;
import com.jmai.physic.dto.*;
import com.jmai.physic.entity.PhysicBill;
......@@ -24,19 +24,26 @@ import com.jmai.sys.consts.enums.RoleTypeEum;
import com.jmai.sys.ctx.SpringContextUtils;
import com.jmai.sys.entity.SysUser;
import com.jmai.sys.mapper.SysUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Map;
import java.util.stream.Collectors;
import static com.jmai.sys.consts.ConfigTypes.PHYSIC_HANDOVER;
import static com.jmai.sys.consts.ConfigTypes.PhysicHandoverCancelConfig.*;
@Slf4j
@Service
public class PhysicBillServiceImpl extends AbstractService implements PhysicBillService {
......@@ -57,6 +64,7 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
@Resource
private SysUserMapper sysUserMapper;
@Transactional
@Override
public void createBill(BillDTO req) {
......@@ -66,20 +74,28 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
Integer batchNoSum = physicBillMapper.selectSumByBatchNo(req.getPhysicName(), req.getPhysicSpec(), req.getFactoryName(), req.getBatchNo(), req.getDeptId());
Integer sum = physicBillMapper.selectSumByName(req.getPhysicName(), req.getPhysicSpec(), req.getFactoryName(), req.getDeptId());
if (ObjectUtil.equals(req.getType(), 1) || ObjectUtil.equals(req.getType(), 2)) {
if (isAcquire(req.getType())) {
// 入库
bill.setAcquireNum(req.getPhysicNum());
bill.setBalance(batchNoSum + req.getPhysicNum());
bill.setBalanceAll(sum + req.getPhysicNum());
} else if (ObjectUtil.equals(req.getType(), 3) || ObjectUtil.equals(req.getType(), 4)) {
} else if (isExpend(req.getType())) {
// 出库
bill.setExpendNum(req.getPhysicNum());
bill.setBalance(batchNoSum - req.getPhysicNum());
bill.setBalanceAll(sum - req.getPhysicNum());
}
bill.setStatus(0);
physicBillMapper.insert(bill);
}
private boolean isAcquire(Integer type) {
return type != null && (ObjectUtil.equals(type, 1) || ObjectUtil.equals(type, 2) || ObjectUtil.equals(type, 4));
}
private boolean isExpend(Integer type) {
return type != null && (ObjectUtil.equals(type, 3) || ObjectUtil.equals(type, 8));
}
@Override
......@@ -91,6 +107,11 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
@Override
public Page<BillQueryVO> listPage(PhysicBillQueryReq req) {
if (ObjectUtil.isNotEmpty(req.getCreateTime())) {
req.setCreateTimeStart(req.getCreateTime().get(0));
req.setCreateTimeEnd(req.getCreateTime().get(1));
}
Page<BillQueryVO> page = buildEmptyPage(req);
Page<BillQueryVO> billInfoVOPage = physicBillMapper.selectBillPage(page, req);
return billInfoVOPage;
......@@ -467,4 +488,234 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
Integer dayLimit = config.getIntFromJsonValue(DAY_LIMIT);
return dayLimit != null ? dayLimit : 3;
}
/**
* 生成药品分组键
*/
private String generateBillGroupKey(PhysicBill bill) {
return bill.getDeptId() + "_" +
bill.getPhysicName() + "_" +
bill.getPhysicSpec() + "_" +
bill.getFactoryName() + "_" +
bill.getBatchNo();
}
/**
* 获取指定日期之前的期末结存数量
*/
private Integer getPreviousClosingBalance(PhysicBill bill, LocalDate date) {
// 先尝试从日结账单获取最近的结存数据
PhysicBill latestDailySettle = physicBillMapper.selectOne(
com.baomidou.mybatisplus.core.toolkit.Wrappers.<PhysicBill>lambdaQuery()
.eq(PhysicBill::getDeptId, bill.getDeptId())
.eq(PhysicBill::getPhysicName, bill.getPhysicName())
.eq(PhysicBill::getPhysicSpec, bill.getPhysicSpec())
.eq(PhysicBill::getFactoryName, bill.getFactoryName())
.eq(PhysicBill::getBatchNo, bill.getBatchNo())
.eq(PhysicBill::getType, 100) // 日结
.le(PhysicBill::getSettleDate, date)
.orderByDesc(PhysicBill::getSettleDate)
.last("LIMIT 1")
);
if (latestDailySettle != null) {
return latestDailySettle.getBalance() != null ? latestDailySettle.getBalance() : 0;
}
// 如果没有日结数据,则尝试从月结账单获取
PhysicBill latestMonthlySettle = physicBillMapper.selectOne(
com.baomidou.mybatisplus.core.toolkit.Wrappers.<PhysicBill>lambdaQuery()
.eq(PhysicBill::getDeptId, bill.getDeptId())
.eq(PhysicBill::getPhysicName, bill.getPhysicName())
.eq(PhysicBill::getPhysicSpec, bill.getPhysicSpec())
.eq(PhysicBill::getFactoryName, bill.getFactoryName())
.eq(PhysicBill::getBatchNo, bill.getBatchNo())
.eq(PhysicBill::getType, 101) // 月结
.orderByDesc(PhysicBill::getSettleMonth)
.last("LIMIT 1")
);
if (latestMonthlySettle != null) {
return latestMonthlySettle.getBalance() != null ? latestMonthlySettle.getBalance() : 0;
}
// 如果都没有,则从原始账单中计算初始结存
List<PhysicBill> initialBills = physicBillMapper.selectList(
com.baomidou.mybatisplus.core.toolkit.Wrappers.<PhysicBill>lambdaQuery()
.eq(PhysicBill::getDeptId, bill.getDeptId())
.eq(PhysicBill::getPhysicName, bill.getPhysicName())
.eq(PhysicBill::getPhysicSpec, bill.getPhysicSpec())
.eq(PhysicBill::getFactoryName, bill.getFactoryName())
.eq(PhysicBill::getBatchNo, bill.getBatchNo())
.ne(PhysicBill::getType, 100) // 排除日结
.ne(PhysicBill::getType, 101) // 排除月结
.le(PhysicBill::getCreateTime, date.atStartOfDay().plusDays(1))
);
int totalAcquire = initialBills.stream()
.filter(b -> isAcquire(b.getType()))
.mapToInt(b -> b.getAcquireNum() != null ? b.getAcquireNum() : 0)
.sum();
int totalExpend = initialBills.stream()
.filter(b -> isExpend(b.getType()))
.mapToInt(b -> b.getExpendNum() != null ? b.getExpendNum() : 0)
.sum();
return totalAcquire - totalExpend;
}
/**
* 生成日结数据
*/
private void generateDailySettlements() {
// 获取昨天的日期
LocalDate yesterday = LocalDate.now().minusDays(1);
// 获取所有部门的药品交易数据
List<PhysicBill> bills = physicBillMapper.selectList(
com.baomidou.mybatisplus.core.toolkit.Wrappers.<PhysicBill>lambdaQuery()
.ge(PhysicBill::getCreateTime, yesterday.atStartOfDay())
.lt(PhysicBill::getCreateTime, yesterday.atStartOfDay().plusDays(1))
.ne(PhysicBill::getType, 100) // 排除日结
.ne(PhysicBill::getType, 101) // 排除月结
.orderByAsc(PhysicBill::getDeptId)
.orderByAsc(PhysicBill::getPhysicName)
.orderByAsc(PhysicBill::getPhysicSpec)
.orderByAsc(PhysicBill::getFactoryName)
.orderByAsc(PhysicBill::getBatchNo)
);
// 按部门和药品信息分组处理
Map<String, List<PhysicBill>> groupedBills = bills.stream()
.collect(Collectors.groupingBy(bill -> generateBillGroupKey(bill)));
for (Map.Entry<String, List<PhysicBill>> entry : groupedBills.entrySet()) {
List<PhysicBill> billList = entry.getValue();
if (!billList.isEmpty()) {
PhysicBill firstBill = billList.get(0);
// 计算期初结存(获取前一天之前的期末结存)
Integer openingBalance = getPreviousClosingBalance(firstBill, yesterday.minusDays(1));
// 计算当天收入和支出数量
int acquireNum = billList.stream()
.filter(bill -> isAcquire(bill.getType()))
.mapToInt(bill -> bill.getAcquireNum() != null ? bill.getAcquireNum() : 0)
.sum();
int expendNum = billList.stream()
.filter(bill -> isExpend(bill.getType()))
.mapToInt(bill -> bill.getExpendNum() != null ? bill.getExpendNum() : 0)
.sum();
// 计算期末结存
Integer closingBalance = openingBalance + acquireNum - expendNum;
// 创建日结记录
PhysicBill dailySettle = new PhysicBill();
dailySettle.setDeptId(firstBill.getDeptId());
dailySettle.setPhysicName(firstBill.getPhysicName());
dailySettle.setPhysicSpec(firstBill.getPhysicSpec());
dailySettle.setFactoryName(firstBill.getFactoryName());
dailySettle.setBatchNo(firstBill.getBatchNo());
dailySettle.setType(100); // 日结类型
dailySettle.setSettleDate(yesterday);
dailySettle.setAcquireNum(acquireNum); // 期间收入数量
dailySettle.setExpendNum(expendNum); // 期间支出数量
dailySettle.setBalance(closingBalance); // 使用balance字段存储期末结存
// 保存日结记录
physicBillMapper.insert(dailySettle);
}
}
}
/**
* 生成月结数据
*/
private void generateMonthlySettlements() {
// 获取上个月
YearMonth lastMonth = YearMonth.now().minusMonths(1);
// 获取上个月的所有药品交易数据
LocalDate startDate = lastMonth.atDay(1);
LocalDate endDate = lastMonth.atEndOfMonth();
List<PhysicBill> bills = physicBillMapper.selectList(
com.baomidou.mybatisplus.core.toolkit.Wrappers.<PhysicBill>lambdaQuery()
.ge(PhysicBill::getCreateTime, startDate.atStartOfDay())
.lt(PhysicBill::getCreateTime, endDate.atStartOfDay().plusDays(1))
.ne(PhysicBill::getType, 100) // 排除日结
.ne(PhysicBill::getType, 101) // 排除月结
.orderByAsc(PhysicBill::getDeptId)
.orderByAsc(PhysicBill::getPhysicName)
.orderByAsc(PhysicBill::getPhysicSpec)
.orderByAsc(PhysicBill::getFactoryName)
.orderByAsc(PhysicBill::getBatchNo)
);
// 按部门和药品信息分组处理
Map<String, List<PhysicBill>> groupedBills = bills.stream()
.collect(Collectors.groupingBy(bill -> generateBillGroupKey(bill)));
for (Map.Entry<String, List<PhysicBill>> entry : groupedBills.entrySet()) {
List<PhysicBill> billList = entry.getValue();
if (!billList.isEmpty()) {
PhysicBill firstBill = billList.get(0);
// 计算期初结存(获取上个月之前的期末结存)
Integer openingBalance = getPreviousClosingBalance(firstBill, startDate.minusDays(1));
// 计算当月收入和支出数量
int acquireNum = billList.stream()
.filter(bill -> isAcquire(bill.getType()))
.mapToInt(bill -> bill.getAcquireNum() != null ? bill.getAcquireNum() : 0)
.sum();
int expendNum = billList.stream()
.filter(bill -> isExpend(bill.getType()))
.mapToInt(bill -> bill.getExpendNum() != null ? bill.getExpendNum() : 0)
.sum();
// 计算期末结存
Integer closingBalance = openingBalance + acquireNum - expendNum;
// 创建月结记录
PhysicBill monthlySettle = new PhysicBill();
monthlySettle.setDeptId(firstBill.getDeptId());
monthlySettle.setPhysicName(firstBill.getPhysicName());
monthlySettle.setPhysicSpec(firstBill.getPhysicSpec());
monthlySettle.setFactoryName(firstBill.getFactoryName());
monthlySettle.setBatchNo(firstBill.getBatchNo());
monthlySettle.setType(101); // 月结类型
monthlySettle.setSettleMonth(lastMonth);
monthlySettle.setAcquireNum(acquireNum); // 期间收入数量
monthlySettle.setExpendNum(expendNum); // 期间支出数量
monthlySettle.setBalance(closingBalance); // 使用balance字段存储期末结存
// 保存月结记录
physicBillMapper.insert(monthlySettle);
}
}
}
/**
* 每天凌晨1点执行日结和月结生成任务
*/
@Scheduled(cron = "0 0 1 * * ?")
public void generateSettlements() {
try {
// 生成前一天的日结
generateDailySettlements();
// 检查是否为每月第一天,如果是则生成上个月的月结
LocalDate today = LocalDate.now();
if (today.getDayOfMonth() == 1) {
generateMonthlySettlements();
}
} catch (Exception e) {
// 记录异常日志
e.printStackTrace();
}
}
}
\ No newline at end of file
......@@ -35,6 +35,9 @@ import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* 药品专用登记 => 药房出,科室入
*/
@Service
public class PhysicRecordServiceImpl extends AbstractService implements PhysicRecordService {
@Resource
......@@ -90,7 +93,8 @@ public class PhysicRecordServiceImpl extends AbstractService implements PhysicRe
private PhysicRecord newRecord(PhysicRecordCreateReq req, PhysicRecordCreateReq.Physic physic, Integer type) {
PhysicRecord record = new PhysicRecord();
BeanUtil.copyProperties(req, record);
if (ObjectUtil.equals(type, 2)) {
boolean yfDept = ObjectUtil.equals(type, 2);
if (yfDept) {
// 药房
Long yfDeptId = DeptEnum.YF.getCode();
record.setDeptId(yfDeptId);
......@@ -191,9 +195,10 @@ public class PhysicRecordServiceImpl extends AbstractService implements PhysicRe
if (finished) {
// 5)完成 => 生成专账
boolean yfDept = ObjectUtil.equals(physicRecord.getType(), 2);
BillDTO billDTO = new BillDTO();
BeanUtil.copyProperties(physicRecord, billDTO);
billDTO.setType(ObjectUtil.equals(physicRecord.getType(), 2) ? 8 : 4);
billDTO.setType(yfDept ? 8 : 4);
billDTO.setDeptId(physicRecord.getDeptId());
billDTO.setRefId(physicRecord.getId());
physicBillService.createBill(billDTO);
......
......@@ -31,8 +31,56 @@
WHERE a.physic_name =#{req.physicName}
AND a.physic_spec =#{req.physicSpec}
AND a.factory_name =#{req.factoryName}
<if test="req.type != null">
AND a.type = #{req.type}
</if>
<if test="req.status != null">
AND a.status = #{req.status}
</if>
<if test="req.createTimeStart != null">
AND a.create_time >= #{req.createTimeStart}
</if>
<if test="req.createTimeEnd != null">
AND a.create_time &lt;= #{req.createTimeEnd}
</if>
ORDER BY a.create_time DESC
</select>
<select id="selectSettlementsByCondition" resultType="com.jmai.physic.entity.PhysicBill">
SELECT *
FROM physic_bill
WHERE del_flag = 0
AND type IN (4, 5) <!-- 日结和月结 -->
<if test="deptId != null">
AND dept_id = #{deptId}
</if>
<if test="physicName != null and physicName != ''">
AND physic_name = #{physicName}
</if>
<if test="physicSpec != null and physicSpec != ''">
AND physic_spec = #{physicSpec}
</if>
<if test="factoryName != null and factoryName != ''">
AND factory_name = #{factoryName}
</if>
<if test="batchNo != null and batchNo != ''">
AND batch_no = #{batchNo}
</if>
<if test="type != null">
AND type = #{type}
</if>
<if test="settleDate != null">
AND settle_date = #{settleDate}
</if>
<if test="startSettleDate != null">
AND settle_date >= #{startSettleDate}
</if>
<if test="endSettleDate != null">
AND settle_date &lt;= #{endSettleDate}
</if>
<if test="settleYearMonth != null">
AND settle_year_month = #{settleYearMonth}
</if>
ORDER BY type ASC, settle_date DESC, settle_year_month DESC, create_time DESC
</select>
</mapper>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment