修改结算逻辑
This commit is contained in:
commit
463dfdc5ce
|
|
@ -0,0 +1,503 @@
|
|||
package com.bonus.cost.service;
|
||||
|
||||
import com.bonus.core.ExcelUtils;
|
||||
import com.bonus.cost.beans.ProjectCostCalculation;
|
||||
import com.bonus.cost.beans.ProjectCostCalculationDetail;
|
||||
import com.bonus.cost.beans.ProjectCostCalculationSegment;
|
||||
import com.bonus.cost.beans.ProjectLeaseCostDetail;
|
||||
import com.bonus.cost.beans.ProjectSettlement;
|
||||
import com.bonus.cost.dao.ProjectCostDao;
|
||||
import com.bonus.plan.beans.PlanDevBean;
|
||||
import com.bonus.plan.beans.PlanProBean;
|
||||
import com.bonus.plan.dao.PlanApplicationDao;
|
||||
import com.bonus.sys.UserShiroHelper;
|
||||
import com.bonus.sys.beans.UserBean;
|
||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
|
||||
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
|
||||
import org.apache.poi.hssf.usermodel.HSSFFont;
|
||||
import org.apache.poi.hssf.usermodel.HSSFRow;
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author : 阮世耀
|
||||
* @version : 1.0
|
||||
* @PackagePath: com.bonus.cost.service
|
||||
* @CreateTime: 2025-05-14 15:08
|
||||
*/
|
||||
@Service("NewSettlementService")
|
||||
public class NewSettlementService {
|
||||
|
||||
@Autowired
|
||||
private ProjectCostDao projectCostDao;
|
||||
|
||||
@Autowired
|
||||
private PlanApplicationDao planApplicationDao;
|
||||
|
||||
// 定义两个格式化器:输入格式(带时分秒)、输出格式(仅年月日)
|
||||
private static final DateTimeFormatter INPUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
private static final DateTimeFormatter OUTPUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
|
||||
/**
|
||||
* 新的结算逻辑
|
||||
*
|
||||
*
|
||||
*/
|
||||
public Map<String, Object> getNewSettlement(ProjectLeaseCostDetail o) {
|
||||
// 获取领料明细
|
||||
List<ProjectLeaseCostDetail> leaseDetails = queryProjectLeaseDetails(o);
|
||||
// 获取退料明细
|
||||
List<ProjectLeaseCostDetail> returnDetails = queryProjectReturnDetails(o);
|
||||
|
||||
// 创建一个新的列表来存储合并后的结果
|
||||
List<ProjectLeaseCostDetail> mergedList = new ArrayList<>();
|
||||
if (leaseDetails != null) {
|
||||
mergedList.addAll(leaseDetails);
|
||||
}
|
||||
if (returnDetails != null) {
|
||||
mergedList.addAll(returnDetails);
|
||||
}
|
||||
|
||||
// 按照machineTypeId分组进行计算
|
||||
Map<String, List<ProjectLeaseCostDetail>> groupedByMachineType = mergedList.stream().filter(Objects::nonNull)
|
||||
.filter(item -> item.getMachineTypeId() != null)
|
||||
.collect(Collectors.groupingBy(item -> String.valueOf(item.getMachineTypeId())));
|
||||
|
||||
// 存储计算结果
|
||||
List<Map<String, Object>> calculationResults = new ArrayList<>();
|
||||
// 获取统计开始和结束日期
|
||||
String startTimeStr = o.getStartTime();
|
||||
String endTimeStr = o.getEndTime();
|
||||
//开始时间-转成日期
|
||||
//结束时间-转成日期
|
||||
LocalDateTime startDate = LocalDateTime.parse(startTimeStr + "T00:00:00");
|
||||
LocalDateTime endDate = LocalDateTime.parse(endTimeStr + "T23:59:59");
|
||||
|
||||
|
||||
double totalAmount = 0.0;
|
||||
|
||||
//计算金额
|
||||
for (Map.Entry<String, List<ProjectLeaseCostDetail>> entry : groupedByMachineType.entrySet()) {
|
||||
Map<String, Object> timeLineData = new HashMap<>(); // 存储时间线上的数量变化
|
||||
List<Map<String, Object>> segments = new ArrayList<>(); // 存储各个时间段
|
||||
|
||||
String machineTypeId = entry.getKey();
|
||||
List<ProjectLeaseCostDetail> items = entry.getValue();
|
||||
items.sort(Comparator.comparing(ProjectLeaseCostDetail::getOperateTime,
|
||||
Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
ProjectLeaseCostDetail firstItem = items.get(0);
|
||||
//
|
||||
if("2402".equals(machineTypeId)) {
|
||||
System.err.println(machineTypeId);
|
||||
}
|
||||
double totalItemAmount = 0.0;
|
||||
//循环逻辑处理
|
||||
//默认在操作日期之前 存量
|
||||
int currentCount = 0;
|
||||
//计算统计日期之内的
|
||||
Map<String,Map<String,Object>> maps=new TreeMap<String, Map<String,Object>>();
|
||||
//主要对时间内的操作进行操作
|
||||
boolean add=true;
|
||||
for (ProjectLeaseCostDetail item : items) {
|
||||
if (item == null || item.getOperateTime() == null) {
|
||||
continue;
|
||||
}
|
||||
//操作时间格式化
|
||||
LocalDateTime operateTime = LocalDateTime.parse(item.getOperateTime(), INPUT_FORMATTER);
|
||||
String times = formatLocalDateTimeToDate(operateTime);
|
||||
//获取按照时间存储的数据
|
||||
Map<String,Object> map=maps.get(times)!=null?maps.get(times):new HashMap<String, Object>();
|
||||
// 只处理统计期间开始之前的操作
|
||||
if (operateTime.isBefore(startDate)) {
|
||||
boolean isLease = (item.getOperateType() == null || item.getOperateType() != 2);
|
||||
if (isLease) {
|
||||
int quantity = item.getLeaseNum() != null ? item.getLeaseNum() : 0;
|
||||
currentCount += quantity;
|
||||
} else {
|
||||
int quantity = item.getReturnNum() != null ? item.getReturnNum() : 0;
|
||||
currentCount -= quantity;
|
||||
}
|
||||
}else {
|
||||
Object addObj = map.get("add");
|
||||
int addNum = (addObj != null) ? (int) addObj : 0; // 无值时给默认值0
|
||||
Object delObj = map.get("del");
|
||||
int delNum = (delObj != null) ? (int) delObj : 0; // 无值时给默认值0
|
||||
Object listObj = map.get("list");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<ProjectLeaseCostDetail> list=(listObj != null) ?(List<ProjectLeaseCostDetail>) listObj:new ArrayList<ProjectLeaseCostDetail>();
|
||||
//从操作中获取到数据
|
||||
boolean isLease = (item.getOperateType() == null || item.getOperateType() != 2);
|
||||
list.add(item);
|
||||
//出库
|
||||
if (isLease) {
|
||||
int quantity = item.getLeaseNum() != null ? item.getLeaseNum() : 0;
|
||||
addNum += quantity;
|
||||
} else {
|
||||
//入库
|
||||
int quantity = item.getReturnNum() != null ? item.getReturnNum() : 0;
|
||||
delNum += quantity;
|
||||
}
|
||||
//统计添加到map中
|
||||
map.put("add", addNum);
|
||||
map.put("del", delNum);
|
||||
map.put("list", list);
|
||||
maps.put(times, map);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 第一个开始时间
|
||||
*/
|
||||
LocalDateTime fasetStarTime=null;
|
||||
if(currentCount>0) {
|
||||
//如果之前有数据 则必须是条件的第天
|
||||
fasetStarTime=startDate;
|
||||
}
|
||||
double unitPrice = firstItem.getPrice() != null ? firstItem.getPrice() : 0;
|
||||
//直接循环获取数据
|
||||
// String fasetStarTimeStr = formatLocalDateTimeToDate(fasetStarTime);
|
||||
|
||||
for (Map.Entry<String, Map<String, Object>> mapObject : maps.entrySet()) {
|
||||
Map<String, Object> mapData=mapObject.getValue();
|
||||
String key=mapObject.getKey();
|
||||
//从数据中获取到相关数据
|
||||
Object addObj = mapData.get("add");
|
||||
int addNum = (addObj != null) ? (int) addObj : 0; // 无值时给默认值0
|
||||
Object delObj = mapData.get("del");
|
||||
int delNum = (delObj != null) ? (int) delObj : 0; // 无值时给默认值0
|
||||
Object listObj = mapData.get("list");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<ProjectLeaseCostDetail> dataList=(listObj != null) ?(List<ProjectLeaseCostDetail>) listObj:new ArrayList<ProjectLeaseCostDetail>();
|
||||
ProjectLeaseCostDetail itemData=dataList.get(dataList.size()-1);
|
||||
LocalDateTime operateTime = LocalDateTime.parse(itemData.getOperateTime(), INPUT_FORMATTER);
|
||||
System.out.println("日期:" + key);
|
||||
//正对两种特殊的情况 -一种是 操作在开始时间的
|
||||
//一种操作在结束时间的
|
||||
//操作在开始时间的
|
||||
if(key.equals(startTimeStr)) {
|
||||
//先把数量加上来
|
||||
currentCount=currentCount+addNum;
|
||||
//记录操作时间
|
||||
fasetStarTime=operateTime;
|
||||
//初始化时间只有领取的 -无退换的 则不需要计算 下方是有退料的 则需要将使用的时间计算出来
|
||||
if(delNum!=0) {
|
||||
//如果今天有退还的 并且是开始的时间必须要按照一天计算
|
||||
long daysBetween=getDay(fasetStarTime,operateTime);
|
||||
if(daysBetween==0) {
|
||||
add=false;
|
||||
daysBetween=daysBetween+1;
|
||||
double segmentAmount = currentCount * unitPrice * daysBetween;
|
||||
Map<String, Object> segment = new HashMap<>();
|
||||
segment.put("startTime",fasetStarTime.toString());
|
||||
segment.put("endTime", operateTime.toString());
|
||||
segment.put("days", daysBetween);
|
||||
totalItemAmount=totalItemAmount+segmentAmount;
|
||||
//计算数量
|
||||
currentCount=currentCount+addNum;
|
||||
segment.put("count", currentCount);
|
||||
segment.put("amount", segmentAmount);
|
||||
segments.add(segment);
|
||||
//下次计算进行减去今日退换的
|
||||
currentCount=currentCount-delNum;
|
||||
}
|
||||
}
|
||||
//操作在结束时间点
|
||||
}else if(key.equals(endTimeStr)) {
|
||||
|
||||
//存在之前领用的数据的 先将之前的数据计算出来
|
||||
if(currentCount>0) {
|
||||
//有领用的
|
||||
if(addNum>0) {
|
||||
//计算天数
|
||||
long daysBetween=getDay(fasetStarTime,operateTime);
|
||||
if(daysBetween==0) {
|
||||
daysBetween=1;
|
||||
add=false;
|
||||
}
|
||||
double segmentAmount = currentCount * unitPrice * daysBetween;
|
||||
Map<String, Object> segment = new HashMap<>();
|
||||
segment.put("startTime",fasetStarTime.toString());
|
||||
segment.put("endTime", operateTime.toString());
|
||||
segment.put("days", daysBetween);
|
||||
totalItemAmount=totalItemAmount+segmentAmount;
|
||||
|
||||
segment.put("count", currentCount);
|
||||
segment.put("amount", segmentAmount);
|
||||
segments.add(segment);
|
||||
fasetStarTime=operateTime;
|
||||
//计算数量
|
||||
currentCount=currentCount+addNum;
|
||||
// 然后将领取的座位最后一天单独计算
|
||||
double segmentAmount2 = currentCount * unitPrice * 1;
|
||||
Map<String, Object> segment2 = new HashMap<>();
|
||||
segment2.put("startTime",fasetStarTime.toString());
|
||||
segment2.put("endTime", operateTime.toString());
|
||||
segment2.put("days", 1);
|
||||
segment2.put("count", currentCount);
|
||||
segment2.put("amount", segmentAmount2);
|
||||
segments.add(segment2);
|
||||
totalItemAmount=totalItemAmount+segmentAmount2;
|
||||
}else {
|
||||
//计算天数
|
||||
long daysBetween=getDay(fasetStarTime,operateTime);
|
||||
if(add) {
|
||||
daysBetween=daysBetween+1;
|
||||
}
|
||||
double segmentAmount = currentCount * unitPrice * daysBetween;
|
||||
Map<String, Object> segment = new HashMap<>();
|
||||
segment.put("startTime",fasetStarTime.toString());
|
||||
segment.put("endTime", operateTime.toString());
|
||||
segment.put("days", daysBetween);
|
||||
totalItemAmount=totalItemAmount+segmentAmount;
|
||||
//计算数量
|
||||
currentCount=currentCount+addNum;
|
||||
segment.put("count", currentCount);
|
||||
segment.put("amount", segmentAmount);
|
||||
segments.add(segment);
|
||||
fasetStarTime=operateTime;
|
||||
|
||||
}
|
||||
}else {
|
||||
if(fasetStarTime==null) {
|
||||
fasetStarTime=operateTime;
|
||||
}
|
||||
//计算数量
|
||||
currentCount=currentCount+addNum;
|
||||
//计算最后一天的数据
|
||||
double segmentAmount = currentCount * unitPrice * 1;
|
||||
Map<String, Object> segment = new HashMap<>();
|
||||
segment.put("startTime",fasetStarTime.toString());
|
||||
segment.put("endTime", operateTime.toString());
|
||||
segment.put("days", 1);
|
||||
totalItemAmount=totalItemAmount+segmentAmount;
|
||||
segment.put("count", currentCount);
|
||||
segment.put("amount", segmentAmount);
|
||||
|
||||
segments.add(segment);
|
||||
fasetStarTime=operateTime;
|
||||
}
|
||||
|
||||
}else {
|
||||
if(delNum>0) {
|
||||
//先把领取的
|
||||
|
||||
long daysBetween=getDay(fasetStarTime,operateTime);
|
||||
if(daysBetween==0) {
|
||||
daysBetween=1;
|
||||
add =false;
|
||||
}
|
||||
|
||||
double segmentAmount = currentCount * unitPrice * daysBetween;
|
||||
Map<String, Object> segment = new HashMap<>();
|
||||
segment.put("startTime",fasetStarTime.toString());
|
||||
segment.put("endTime", operateTime.toString());
|
||||
segment.put("days", daysBetween);
|
||||
totalItemAmount=totalItemAmount+segmentAmount;
|
||||
segment.put("count", currentCount);
|
||||
segment.put("amount", segmentAmount);
|
||||
segments.add(segment);
|
||||
currentCount=currentCount+addNum;
|
||||
|
||||
// 然后将领取的座位最后一天单独计算
|
||||
double segmentAmount2 = currentCount * unitPrice * 1;
|
||||
Map<String, Object> segment2 = new HashMap<>();
|
||||
LocalDateTime nextDayTime = operateTime.plusDays(1);
|
||||
segment2.put("startTime",operateTime.toString());
|
||||
segment2.put("endTime", nextDayTime.toString());
|
||||
segment2.put("days", 1);
|
||||
segment2.put("count", currentCount);
|
||||
segment2.put("amount", segmentAmount2);
|
||||
segments.add(segment2);
|
||||
totalItemAmount=totalItemAmount+segmentAmount2;
|
||||
//然后减去
|
||||
currentCount=currentCount-delNum;
|
||||
fasetStarTime=nextDayTime;
|
||||
|
||||
}else {
|
||||
//无之前的数据的 第一次进来的
|
||||
if(fasetStarTime==null) {
|
||||
currentCount=currentCount+addNum;
|
||||
fasetStarTime=operateTime;
|
||||
if(delNum!=0) {
|
||||
//如果今天有退还的 并且是开始的时间必须要按照一天计算
|
||||
long daysBetween=getDay(fasetStarTime,operateTime);
|
||||
if(daysBetween==0) {
|
||||
double segmentAmount = currentCount * unitPrice * daysBetween;
|
||||
daysBetween=daysBetween+1;
|
||||
Map<String, Object> segment = new HashMap<>();
|
||||
segment.put("startTime",fasetStarTime.toString());
|
||||
segment.put("endTime", operateTime.toString());
|
||||
segment.put("days", daysBetween);
|
||||
totalItemAmount=totalItemAmount+segmentAmount;
|
||||
//计算数量
|
||||
currentCount=currentCount+addNum;
|
||||
segment.put("count", currentCount);
|
||||
segment.put("amount", segmentAmount);
|
||||
segments.add(segment);
|
||||
//下次计算进行减去今日退换的
|
||||
currentCount=currentCount-delNum;
|
||||
}
|
||||
}
|
||||
}else {
|
||||
//处于中间的 之前有数据的
|
||||
//有添加数据的
|
||||
long daysBetween=getDay(fasetStarTime,operateTime);
|
||||
if(daysBetween==0) {
|
||||
daysBetween=daysBetween+1;
|
||||
add=false;
|
||||
}
|
||||
if(currentCount+addNum-addNum==0) {
|
||||
daysBetween=daysBetween+1;
|
||||
add=false;
|
||||
}
|
||||
|
||||
double segmentAmount = currentCount * unitPrice * daysBetween;
|
||||
Map<String, Object> segment = new HashMap<>();
|
||||
segment.put("startTime",fasetStarTime.toString());
|
||||
segment.put("endTime", operateTime.toString());
|
||||
segment.put("days", daysBetween);
|
||||
totalItemAmount=totalItemAmount+segmentAmount;
|
||||
segment.put("count", currentCount);
|
||||
segment.put("amount", segmentAmount);
|
||||
segments.add(segment);
|
||||
fasetStarTime=operateTime;
|
||||
//将数量减少-或者添加
|
||||
currentCount=currentCount+addNum;
|
||||
currentCount=currentCount-delNum;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
//如果还是存在数据--并且 最后一天未计算的
|
||||
String fasetStarTimeStr = formatLocalDateTimeToDate(fasetStarTime);
|
||||
if(currentCount>0 && !fasetStarTimeStr.equals(endTimeStr)) {
|
||||
long daysBetween=getDay(fasetStarTime,endDate);
|
||||
if(daysBetween==0) {
|
||||
daysBetween=1;
|
||||
}else {
|
||||
if(add) {
|
||||
daysBetween=daysBetween+1;
|
||||
}
|
||||
|
||||
}
|
||||
Map<String, Object> segment = new HashMap<>();
|
||||
segment.put("startTime",fasetStarTime.toString());
|
||||
segment.put("endTime", endDate.toString());
|
||||
segment.put("days", daysBetween);
|
||||
double segmentAmount = currentCount * unitPrice * daysBetween;
|
||||
totalItemAmount=totalItemAmount+segmentAmount;
|
||||
segment.put("count", currentCount);
|
||||
segment.put("amount", segmentAmount);
|
||||
segments.add(segment);
|
||||
}
|
||||
//至此计算结束
|
||||
// 创建计算结果对象
|
||||
Map<String, Object> calculationResult = new HashMap<>();
|
||||
calculationResult.put("machineTypeId", machineTypeId);
|
||||
calculationResult.put("machineTypeName", firstItem.getMachineTypeName());
|
||||
calculationResult.put("machineModel", firstItem.getMachineModel());
|
||||
calculationResult.put("machineUnit", firstItem.getMachineUnit());
|
||||
calculationResult.put("price", unitPrice);
|
||||
calculationResult.put("currentCount", currentCount);
|
||||
calculationResult.put("amount", totalItemAmount);
|
||||
calculationResult.put("timeline", timeLineData);
|
||||
calculationResult.put("segments", segments);
|
||||
calculationResult.put("details", items);
|
||||
calculationResults.add(calculationResult);
|
||||
// 更新总金额
|
||||
totalAmount += totalItemAmount;
|
||||
}
|
||||
// 将原始明细按操作时间排序
|
||||
List<ProjectLeaseCostDetail> sortedDetails = mergedList.stream().filter(Objects::nonNull).sorted(Comparator
|
||||
.comparing(ProjectLeaseCostDetail::getOperateTime, Comparator.nullsFirst(Comparator.naturalOrder())))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 返回结果
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("details", sortedDetails); // 原始按时间排序的明细
|
||||
result.put("calculationResults", calculationResults); // 计算结果
|
||||
result.put("totalAmount", totalAmount); // 总金额
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 将local日期 转成当日日期
|
||||
* @param dateTime
|
||||
* @return
|
||||
*/
|
||||
public static String formatLocalDateTimeToDate(LocalDateTime dateTime) {
|
||||
if (dateTime == null) {
|
||||
return null; // 处理空值,避免空指针
|
||||
}
|
||||
return dateTime.format(OUTPUT_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个日期的 天数
|
||||
* @param operateTime
|
||||
* @param endtime
|
||||
* @return
|
||||
*/
|
||||
public long getDay(LocalDateTime operateTime,LocalDateTime endtime) {
|
||||
LocalDate startDate = operateTime.toLocalDate();
|
||||
LocalDate endDate = endtime.toLocalDate();
|
||||
long naturalDays = ChronoUnit.DAYS.between(startDate, endDate);
|
||||
// System.out.println("自然日天数差(正确结果):" + naturalDays);
|
||||
return naturalDays;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取两个日期的时间
|
||||
* @param starTime
|
||||
* @param endTime
|
||||
* @return
|
||||
*/
|
||||
public static long getDay(String starTime,String endTime) {
|
||||
LocalDate startDate = LocalDate.parse(starTime, OUTPUT_FORMATTER);
|
||||
LocalDate endDate = LocalDate.parse(endTime, OUTPUT_FORMATTER);
|
||||
long naturalDays = ChronoUnit.DAYS.between(startDate, endDate);
|
||||
// System.out.println("自然日天数差(正确结果):" + naturalDays);
|
||||
return naturalDays;
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.err.print(getDay("2025-01-22","2025-01-22"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<ProjectLeaseCostDetail> queryProjectLeaseDetails(ProjectLeaseCostDetail o) {
|
||||
return projectCostDao.queryProjectLeaseDetails(o);
|
||||
}
|
||||
|
||||
|
||||
public List<ProjectLeaseCostDetail> queryProjectReturnDetails(ProjectLeaseCostDetail o) {
|
||||
return projectCostDao.queryProjectReturnDetails(o);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue