Commit 67442ea1 by zhu.zewen

优化专账日结和月结计算

新增专账日结和月结手动触发接口
parent c8fe83a9
......@@ -49,4 +49,18 @@ public class PhysicBillController {
PhysicBill bill = physicBillService.sign(physicBillSignReq);
return ResponseData.ok(bill);
}
@PostMapping("/triggerDailySettlement")
@ApiOperation(value = "手动触发指定日期的日结")
public ResponseData<Void> triggerDailySettlement(@RequestBody BillSettlementTriggerReq req) {
physicBillService.triggerDailySettlement(req.getDate());
return ResponseData.ok();
}
@PostMapping("/triggerMonthlySettlement")
@ApiOperation(value = "手动触发指定月份的月结")
public ResponseData<Void> triggerMonthlySettlement(@RequestBody BillSettlementTriggerReq req) {
physicBillService.triggerMonthlySettlement(req.getMonth());
return ResponseData.ok();
}
}
\ No newline at end of file
package com.jmai.physic.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(description = "触发结算请求")
public class BillSettlementTriggerReq {
@ApiModelProperty(value = "日期,格式:yyyy-MM-dd,用于日结")
private String date;
@ApiModelProperty(value = "月份,格式:yyyy-MM,用于月结")
private String month;
}
\ No newline at end of file
package com.jmai.physic.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class PhysicDestroyCheckDetailQueryReq {
@ApiModelProperty(value = "销毁审批ID", required = true)
private Long checkId;
}
\ No newline at end of file
......@@ -6,8 +6,7 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDate;
import java.time.YearMonth;
@Data
@ApiModel(description = "药品专账")
......@@ -44,10 +43,10 @@ public class PhysicBill extends BaseVersionEntity {
private Integer expendNum;
@ApiModelProperty(value = "结算日期")
private LocalDate settleDate;
private String settleDate;
@ApiModelProperty(value = "结算月份(年月)")
private YearMonth settleMonth;
private String settleMonth;
@ApiModelProperty(value = "相关申请、入库id")
private Long refId;
......
......@@ -24,4 +24,8 @@ public interface PhysicBillService {
PhysicBillHandover handover(PhysicBillHandoverCreateReq req);
PhysicBillHandover signHandover(PhysicBillHandoverSignReq req);
void cancelHandover(PhysicBillHandoverCancelReq req);
// 结算功能
void triggerDailySettlement(String settleDateStr);
void triggerMonthlySettlement(String settleMonthStr);
}
......@@ -24,6 +24,9 @@ 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.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
......@@ -124,14 +127,14 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
String getstamp = cloudsignService.sign(physicBillSignReq.getEncryptedToken(), physicBillSignReq.getRelBizNo(), physicBillSignReq.getBase64SourceData());
PhysicBill bill = physicBillMapper.selectById(physicBillSignReq.getPhysicBillId());
SysUser sysUser = sysUserMapper.selectById(userId);
if (bill.getStatus().equals(0)) {
if (ObjectUtil.equals(bill.getStatus(), 0)) {
if (!RoleTypeEum.isPass(sysUser.getRoleAsList(), RoleTypeEum.LY)) {
throw new ServiceException("需要领药人权限才可进行签名");
}
bill.setStatus(1);
SignInfoDTO signInfoDTO = new SignInfoDTO(getstamp, LocalDateTime.now(), userId);
bill.setLyUser(JSONUtil.toJsonStr(signInfoDTO));
} else if (bill.getStatus().equals(1)) {
} else if (ObjectUtil.equals(bill.getStatus(), 1)) {
if (!RoleTypeEum.isPass(sysUser.getRoleAsList(), RoleTypeEum.FH)) {
throw new ServiceException("需要复核人权限才可进行签名");
}
......@@ -275,7 +278,7 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
// 验证当前用户是上次接班人
if (lastHandover.isPresent()) {
SignInfoDTO jsUserInfo = JSONUtil.toBean(lastHandover.get().getJsUser(), SignInfoDTO.class);
if (!jsUserInfo.getUserId().equals(userId)) {
if (ObjectUtil.notEqual(jsUserInfo.getUserId(), userId)) {
throw new ServiceException("仅上次接班人有权限进行下一次交接班");
}
}
......@@ -320,15 +323,15 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
if (ObjectUtil.isEmpty(handover)) {
throw new ServiceException("未找到交接单:" + req.getHandoverId());
}
if (!handover.getDeptId().equals(currentDeptId)) {
if (ObjectUtil.notEqual(handover.getDeptId(), currentDeptId)) {
throw new ServiceException("交接班只能在同一部门内进行");
}
if (handover.getStatus().equals(0)) {
if (ObjectUtil.equals(handover.getStatus(), 0)) {
// 交班人/移交人签名
handover.setStatus(1);
SignInfoDTO signInfoDTO = new SignInfoDTO(getstamp, LocalDateTime.now(), userId);
handover.setYjUser(JSONUtil.toJsonStr(signInfoDTO));
} else if (handover.getStatus().equals(1)) {
} else if (ObjectUtil.equals(handover.getStatus(), 1)) {
// 接班人/接收人签名
handover.setStatus(100);
SignInfoDTO signInfoDTO = new SignInfoDTO(getstamp, LocalDateTime.now(), userId);
......@@ -350,7 +353,7 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
if (ObjectUtil.isEmpty(handover)) {
throw new ServiceException("未找到交接单:" + req.getHandoverId());
}
if (!handover.getDeptId().equals(currentDeptId)) {
if (ObjectUtil.notEqual(handover.getDeptId(), currentDeptId)) {
throw new ServiceException("交接班只能在同一部门内进行");
}
......@@ -358,12 +361,12 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
ConfigDto config = configService.getConfig(PHYSIC_HANDOVER, HANDOVER_CANCEL)
.orElse(new ConfigDto());
if (handover.getStatus().equals(100)) {
if (ObjectUtil.equals(handover.getStatus(), 100)) {
if (!isAllowCancelCompleted(config)) {
throw new ServiceException("已完成交接班不能取消");
}
}
if (handover.getStatus().equals(-100)) {
if (ObjectUtil.equals(handover.getStatus(), -100)) {
throw new ServiceException("交接班已取消,不应重复取消");
}
......@@ -373,7 +376,7 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
.ne(PhysicBillHandover::getStatus, -100)
.orderByDesc(PhysicBillHandover::getId)
.last("LIMIT 1"));
if (ObjectUtil.isEmpty(latestHandover) || !latestHandover.getId().equals(handover.getId())) {
if (ObjectUtil.isEmpty(latestHandover) || ObjectUtil.notEqual(latestHandover.getId(), handover.getId())) {
throw new ServiceException("只允许取消最新一个未取消的交接单");
}
......@@ -393,7 +396,7 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
private void validateCancelPermission(PhysicBillHandover handover, Long currentUserId, ConfigDto config) {
List<String> msg = new ArrayList<>(4);
// 检查是否为创建人
if (handover.getCreateBy() != null && handover.getCreateBy().equals(currentUserId)) {
if (handover.getCreateBy() != null && ObjectUtil.equals(handover.getCreateBy(), currentUserId)) {
return;
} else {
msg.add("非创建人");
......@@ -411,7 +414,7 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
boolean isTransferor = isAllowTransferor(config) && handover.getYjUser() != null;
if (isTransferor) {
SignInfoDTO yjUserInfo = JSONUtil.toBean(handover.getYjUser(), SignInfoDTO.class);
if (yjUserInfo.getUserId().equals(currentUserId)) {
if (ObjectUtil.equals(yjUserInfo.getUserId(), currentUserId)) {
return;
} else {
msg.add("非交班人");
......@@ -422,7 +425,7 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
boolean isReceiver = isAllowReceiver(config) && handover.getJsUser() != null;
if (isReceiver) {
SignInfoDTO jsUserInfo = JSONUtil.toBean(handover.getJsUser(), SignInfoDTO.class);
if (jsUserInfo.getUserId().equals(currentUserId)) {
if (ObjectUtil.equals(jsUserInfo.getUserId(), currentUserId)) {
return;
} else {
msg.add("非接班人");
......@@ -439,7 +442,7 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
*/
private void validateCancelTimeLimit(PhysicBillHandover handover, ConfigDto config) {
// 未完成的交接单不受时间限制
if (handover.getStatus().equals(-100)) {
if (ObjectUtil.equals(handover.getStatus(), -100)) {
return;
}
......@@ -503,7 +506,7 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
/**
* 获取指定日期之前的期末结存数量
*/
private Integer getPreviousClosingBalance(PhysicBill bill, LocalDate date) {
private Integer getPreviousClosingBalance(PhysicBill bill, String dateStr) {
// 先尝试从日结账单获取最近的结存数据
PhysicBill latestDailySettle = physicBillMapper.selectOne(
com.baomidou.mybatisplus.core.toolkit.Wrappers.<PhysicBill>lambdaQuery()
......@@ -513,7 +516,7 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
.eq(PhysicBill::getFactoryName, bill.getFactoryName())
.eq(PhysicBill::getBatchNo, bill.getBatchNo())
.eq(PhysicBill::getType, 100) // 日结
.le(PhysicBill::getSettleDate, date)
.le(PhysicBill::getSettleDate, dateStr)
.orderByDesc(PhysicBill::getSettleDate)
.last("LIMIT 1")
);
......@@ -549,7 +552,7 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
.eq(PhysicBill::getBatchNo, bill.getBatchNo())
.ne(PhysicBill::getType, 100) // 排除日结
.ne(PhysicBill::getType, 101) // 排除月结
.le(PhysicBill::getCreateTime, date.atStartOfDay().plusDays(1))
.le(PhysicBill::getCreateTime, LocalDate.parse(dateStr).atStartOfDay().plusDays(1))
);
int totalAcquire = initialBills.stream()
......@@ -566,69 +569,29 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
}
/**
* 结算信息封装类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class SettlementInfo {
private Integer type; // 结算类型:100-日结,101-月结
private String settleValue; // 结算值:日结为日期字符串,月结为月份字符串
private Object timeUnit; // 时间单位:日结为LocalDate,月结为YearMonth
}
/**
* 生成日结数据
*/
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字段存储期末结存
// 创建结算信息对象
SettlementInfo settlementInfo = new SettlementInfo(100, yesterday.toString(), yesterday);
// 保存日结记录
physicBillMapper.insert(dailySettle);
}
}
// 执行结算处理
processSettlementForPeriod(settlementInfo, yesterday, yesterday);
}
/**
......@@ -636,12 +599,27 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
*/
private void generateMonthlySettlements() {
// 获取上个月
YearMonth lastMonth = YearMonth.now().minusMonths(1);
YearMonth yearMonth = YearMonth.now().minusMonths(1);
String lastMonthStr = yearMonth.toString();
LocalDate startDate = yearMonth.atDay(1);
LocalDate endDate = yearMonth.atEndOfMonth();
// 获取上个月的所有药品交易数据
LocalDate startDate = lastMonth.atDay(1);
LocalDate endDate = lastMonth.atEndOfMonth();
// 创建结算信息对象
SettlementInfo settlementInfo = new SettlementInfo(101, lastMonthStr, yearMonth);
// 执行结算处理
processSettlementForPeriod(settlementInfo, startDate, endDate);
}
/**
* 处理指定时间段的结算
*
* @param settlementInfo 结算信息
* @param startDate 开始日期
* @param endDate 结束日期
*/
private void processSettlementForPeriod(SettlementInfo settlementInfo, LocalDate startDate, LocalDate endDate) {
// 获取指定时间段的所有药品交易数据
List<PhysicBill> bills = physicBillMapper.selectList(
com.baomidou.mybatisplus.core.toolkit.Wrappers.<PhysicBill>lambdaQuery()
.ge(PhysicBill::getCreateTime, startDate.atStartOfDay())
......@@ -664,10 +642,10 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
if (!billList.isEmpty()) {
PhysicBill firstBill = billList.get(0);
// 计算期初结存(获取上个月之前的期末结存)
Integer openingBalance = getPreviousClosingBalance(firstBill, startDate.minusDays(1));
// 计算期初结存(获取指定日期之前的期末结存)
Integer openingBalance = getPreviousClosingBalance(firstBill, startDate.minusDays(1).toString());
// 计算当月收入和支出数量
// 计算期间收入和支出数量
int acquireNum = billList.stream()
.filter(bill -> isAcquire(bill.getType()))
.mapToInt(bill -> bill.getAcquireNum() != null ? bill.getAcquireNum() : 0)
......@@ -681,21 +659,87 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
// 计算期末结存
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字段存储期末结存
// 创建结算记录
PhysicBill settlementRecord = createSettlementRecord(firstBill, settlementInfo, acquireNum, expendNum, closingBalance);
// 检查是否已存在相同的结算记录,如果存在则删除
deleteExistingSettlementIfExists(settlementRecord);
// 保存月结记录
physicBillMapper.insert(monthlySettle);
// 保存结算记录
physicBillMapper.insert(settlementRecord);
}
}
}
/**
* 创建结算记录
*
* @param firstBill 基础账单信息
* @param settlementInfo 结算信息
* @param acquireNum 收入数量
* @param expendNum 支出数量
* @param closingBalance 期末结存
* @return 结算记录
*/
private PhysicBill createSettlementRecord(PhysicBill firstBill, SettlementInfo settlementInfo, int acquireNum, int expendNum, Integer closingBalance) {
PhysicBill settlementRecord = new PhysicBill();
settlementRecord.setDeptId(firstBill.getDeptId());
settlementRecord.setPhysicName(firstBill.getPhysicName());
settlementRecord.setPhysicSpec(firstBill.getPhysicSpec());
settlementRecord.setFactoryName(firstBill.getFactoryName());
settlementRecord.setBatchNo(firstBill.getBatchNo());
settlementRecord.setType(settlementInfo.getType());
// 根据结算类型设置对应的结算字段
if (settlementInfo.getType() == 100) { // 日结
settlementRecord.setSettleDate(settlementInfo.getSettleValue());
} else if (settlementInfo.getType() == 101) { // 月结
settlementRecord.setSettleMonth(settlementInfo.getSettleValue());
}
settlementRecord.setAcquireNum(acquireNum); // 期间收入数量
settlementRecord.setExpendNum(expendNum); // 期间支出数量
settlementRecord.setBalance(closingBalance); // 使用balance字段存储期末结存
return settlementRecord;
}
/**
* 检查并删除已存在的结算记录
*
* @param settlementRecord 结算记录
*/
private void deleteExistingSettlementIfExists(PhysicBill settlementRecord) {
List<PhysicBill> existingSettlements = null;
if (settlementRecord.getType() == 100) { // 日结
existingSettlements = physicBillMapper.selectList(
com.baomidou.mybatisplus.core.toolkit.Wrappers.<PhysicBill>lambdaQuery()
.eq(PhysicBill::getDeptId, settlementRecord.getDeptId())
.eq(PhysicBill::getPhysicName, settlementRecord.getPhysicName())
.eq(PhysicBill::getPhysicSpec, settlementRecord.getPhysicSpec())
.eq(PhysicBill::getFactoryName, settlementRecord.getFactoryName())
.eq(PhysicBill::getBatchNo, settlementRecord.getBatchNo())
.eq(PhysicBill::getType, 100) // 日结
.eq(PhysicBill::getSettleDate, settlementRecord.getSettleDate())
);
} else if (settlementRecord.getType() == 101) { // 月结
existingSettlements = physicBillMapper.selectList(
com.baomidou.mybatisplus.core.toolkit.Wrappers.<PhysicBill>lambdaQuery()
.eq(PhysicBill::getDeptId, settlementRecord.getDeptId())
.eq(PhysicBill::getPhysicName, settlementRecord.getPhysicName())
.eq(PhysicBill::getPhysicSpec, settlementRecord.getPhysicSpec())
.eq(PhysicBill::getFactoryName, settlementRecord.getFactoryName())
.eq(PhysicBill::getBatchNo, settlementRecord.getBatchNo())
.eq(PhysicBill::getType, 101) // 月结
.eq(PhysicBill::getSettleMonth, settlementRecord.getSettleMonth())
);
}
if (existingSettlements != null && !existingSettlements.isEmpty()) {
// 删除已存在的结算记录
for (PhysicBill existing : existingSettlements) {
physicBillMapper.deleteById(existing.getId());
}
}
}
......@@ -718,4 +762,30 @@ public class PhysicBillServiceImpl extends AbstractService implements PhysicBill
e.printStackTrace();
}
}
@Override
public void triggerDailySettlement(String settleDateStr) {
LocalDate settleDate = LocalDate.parse(settleDateStr);
// 创建结算信息对象
SettlementInfo settlementInfo = new SettlementInfo(100, settleDateStr, settleDate);
// 执行结算处理
processSettlementForPeriod(settlementInfo, settleDate, settleDate);
}
@Override
public void triggerMonthlySettlement(String settleMonthStr) {
YearMonth settleMonth = YearMonth.parse(settleMonthStr);
// 获取指定月份的开始和结束日期
LocalDate startDate = settleMonth.atDay(1);
LocalDate endDate = settleMonth.atEndOfMonth();
// 创建结算信息对象
SettlementInfo settlementInfo = new SettlementInfo(101, settleMonthStr, settleMonth);
// 执行结算处理
processSettlementForPeriod(settlementInfo, startDate, endDate);
}
}
\ No newline at end of file
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