From 5dca49269399c21333b16d62945c7f74570f9ad5 Mon Sep 17 00:00:00 2001
From: chen.llin <1442464845@qq.comm>
Date: 星期三, 24 十二月 2025 20:33:59 +0800
Subject: [PATCH] 字段调整

---
 src/main/java/com/zy/asrs/service/impl/MonthlySettleServiceImpl.java |  593 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 593 insertions(+), 0 deletions(-)

diff --git a/src/main/java/com/zy/asrs/service/impl/MonthlySettleServiceImpl.java b/src/main/java/com/zy/asrs/service/impl/MonthlySettleServiceImpl.java
new file mode 100644
index 0000000..fcd629b
--- /dev/null
+++ b/src/main/java/com/zy/asrs/service/impl/MonthlySettleServiceImpl.java
@@ -0,0 +1,593 @@
+package com.zy.asrs.service.impl;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.plugins.Page;
+import com.baomidou.mybatisplus.service.impl.ServiceImpl;
+import com.core.common.Cools;
+import com.core.common.SnowflakeIdWorker;
+import com.core.exception.CoolException;
+import com.zy.asrs.entity.MonthlySettle;
+import com.zy.asrs.entity.MonthlySettleDetail;
+import com.zy.asrs.entity.result.MaterialInOutRawDTO;
+import com.zy.asrs.entity.result.MaterialInOutStatDTO;
+import com.zy.asrs.entity.result.MonthlySettleResultVO;
+import com.zy.asrs.entity.result.MonthlySettleStatisticsVO;
+import com.zy.asrs.entity.result.PreviousSettleEndingQtyDTO;
+import com.zy.asrs.mapper.MonthlySettleDetailMapper;
+import com.zy.asrs.mapper.MonthlySettleMapper;
+import com.zy.asrs.service.ManLocDetlService;
+import com.zy.asrs.service.MonthlySettleService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service("monthlySettleService")
+public class MonthlySettleServiceImpl extends ServiceImpl<MonthlySettleMapper, MonthlySettle> implements MonthlySettleService {
+
+    @Autowired
+    private MonthlySettleDetailMapper monthlySettleDetailMapper;
+    @Autowired
+    private ManLocDetlService manLocDetlService;
+    @Autowired
+    private SnowflakeIdWorker snowflakeIdWorker;
+
+    @Override
+    public MonthlySettle getLatestSettle() {
+        return this.baseMapper.selectLatestSettle();
+    }
+
+    @Override
+    public Date getNextStartDate() {
+        MonthlySettle latestSettle = getLatestSettle();
+        if (latestSettle == null) {
+            // 濡傛灉娌℃湁鏈堢粨璁板綍锛岃繑鍥瀗ull锛岀敱鍓嶇閫夋嫨璧峰鏃ユ湡
+            return null;
+        }
+        // 杩斿洖鏈�鏅氭湀缁撹褰曠粨鏉熸棩鏈熺殑涓嬩竴澶╋紙璧峰鏃ユ湡搴旇鏄粨鏉熸棩鏈�+1澶╃殑00:00:00锛�
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(latestSettle.getEndDate());
+        // 鍏堣缃负褰撳ぉ鐨�00:00:00锛岀劧鍚庡姞1澶╋紝纭繚杩斿洖鐨勬槸涓嬩竴澶╃殑00:00:00
+        cal.set(Calendar.HOUR_OF_DAY, 0);
+        cal.set(Calendar.MINUTE, 0);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        cal.add(Calendar.DAY_OF_MONTH, 1);
+        return cal.getTime();
+    }
+
+    @Override
+    public Date getLatestEndDate() {
+        MonthlySettle latestSettle = getLatestSettle();
+        if (latestSettle == null) {
+            return null;
+        }
+        // 杩斿洖鏈�鏅氭湀缁撹褰曠殑缁撴潫鏃ユ湡锛堟牸寮忓寲涓哄綋澶╃殑00:00:00锛岀敤浜庢樉绀猴級
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(latestSettle.getEndDate());
+        cal.set(Calendar.HOUR_OF_DAY, 0);
+        cal.set(Calendar.MINUTE, 0);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        return cal.getTime();
+    }
+
+    @Override
+    public boolean hasUnfinishedOrders(Date startDate, Date endDate) {
+        // 缁撴潫鏃ユ湡+23:59:59
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(endDate);
+        cal.set(Calendar.HOUR_OF_DAY, 23);
+        cal.set(Calendar.MINUTE, 59);
+        cal.set(Calendar.SECOND, 59);
+        cal.set(Calendar.MILLISECOND, 999);
+        endDate = cal.getTime();
+        
+        // 娉ㄦ剰锛歰rder_time 鏄� varchar 绫诲瀷锛岄渶瑕佹牸寮忓寲涓哄畬鏁寸殑鏃ユ湡鏃堕棿瀛楃涓茶繘琛屾瘮杈�
+        SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        // 璧峰鏃ユ湡璁剧疆涓哄綋澶╃殑 00:00:00
+        Calendar startCal = Calendar.getInstance();
+        startCal.setTime(startDate);
+        startCal.set(Calendar.HOUR_OF_DAY, 0);
+        startCal.set(Calendar.MINUTE, 0);
+        startCal.set(Calendar.SECOND, 0);
+        startCal.set(Calendar.MILLISECOND, 0);
+        String startDateStr = dateTimeFormat.format(startCal.getTime());
+        String endDateStr = dateTimeFormat.format(endDate);
+        // 鍒嗕袱娆℃煡璇細鍏ュ簱鍜屽嚭搴�
+        int pakinCount = this.baseMapper.countUnfinishedOrdersInRangePakin(startDateStr, endDateStr);
+        int pakoutCount = this.baseMapper.countUnfinishedOrdersInRangePakout(startDateStr, endDateStr);
+        return (pakinCount + pakoutCount) > 0;
+    }
+
+    @Override
+    @Transactional
+    public MonthlySettleResultVO startSettle(Date startDate, Date endDate, Long userId) {
+        // 缁撴潫鏃ユ湡+23:59:59
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(endDate);
+        cal.set(Calendar.HOUR_OF_DAY, 23);
+        cal.set(Calendar.MINUTE, 59);
+        cal.set(Calendar.SECOND, 59);
+        cal.set(Calendar.MILLISECOND, 999);
+        endDate = cal.getTime();
+        
+        // 妫�鏌ヨ捣濮嬫棩鏈熷繀椤诲ぇ浜庢渶鏅氭湀缁撹褰曠殑缁撴潫鏃ユ湡
+        MonthlySettle latestSettle = getLatestSettle();
+        if (latestSettle != null) {
+            Calendar startCal = Calendar.getInstance();
+            startCal.setTime(startDate);
+            startCal.set(Calendar.HOUR_OF_DAY, 0);
+            startCal.set(Calendar.MINUTE, 0);
+            startCal.set(Calendar.SECOND, 0);
+            startCal.set(Calendar.MILLISECOND, 0);
+            
+            Calendar latestEndCal = Calendar.getInstance();
+            latestEndCal.setTime(latestSettle.getEndDate());
+            latestEndCal.set(Calendar.HOUR_OF_DAY, 0);
+            latestEndCal.set(Calendar.MINUTE, 0);
+            latestEndCal.set(Calendar.SECOND, 0);
+            latestEndCal.set(Calendar.MILLISECOND, 0);
+            
+            // 璧峰鏃ユ湡蹇呴』澶т簬鏈�鏅氱粨鏉熸棩鏈燂紝涓嶈兘绛変簬鎴栧皬浜�
+            if (!startCal.getTime().after(latestEndCal.getTime())) {
+                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+                throw new CoolException("璧峰鏃ユ湡蹇呴』澶т簬鏈�鏅氭湀缁撹褰曠殑缁撴潫鏃ユ湡锛�" + sdf.format(latestSettle.getEndDate()));
+            }
+        }
+        
+        // 妫�鏌ユ槸鍚︽湁鏈畬鎴愮殑璁㈠崟
+        if (hasUnfinishedOrders(startDate, endDate)) {
+            throw new CoolException("鏈堢粨鏃堕棿鑼冨洿鍐呭瓨鍦ㄦ湭瀹屾垚鐨勮鍗曪紝鏃犳硶杩涜鏈堢粨");
+        }
+
+        // 缁熻鐗╂枡鍑哄叆搴撴暟閲忥紙鍒嗗埆鏌ヨ涓や釜琛紝鍦↗ava浠g爜涓悎骞讹級
+        // 娉ㄦ剰锛歰rder_time 鏄� varchar 绫诲瀷锛岄渶瑕佹牸寮忓寲涓哄畬鏁寸殑鏃ユ湡鏃堕棿瀛楃涓茶繘琛屾瘮杈�
+        SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        // 璧峰鏃ユ湡璁剧疆涓哄綋澶╃殑 00:00:00
+        Calendar startCal = Calendar.getInstance();
+        startCal.setTime(startDate);
+        startCal.set(Calendar.HOUR_OF_DAY, 0);
+        startCal.set(Calendar.MINUTE, 0);
+        startCal.set(Calendar.SECOND, 0);
+        startCal.set(Calendar.MILLISECOND, 0);
+        String startDateStr = dateTimeFormat.format(startCal.getTime());
+        String endDateStr = dateTimeFormat.format(endDate);
+        
+        // 鍒嗗埆鏌ヨ鍏ュ簱琛ㄥ拰鍑哄簱琛�
+        List<MaterialInOutRawDTO> pakinDataList = this.baseMapper.statisticsMaterialInOutFromPakin(startDateStr, endDateStr);
+        List<MaterialInOutRawDTO> pakoutDataList = this.baseMapper.statisticsMaterialInOutFromPakout(startDateStr, endDateStr);
+        
+        // 鍚堝苟涓や釜琛ㄧ殑鏁版嵁
+        List<MaterialInOutRawDTO> rawDataList = new java.util.ArrayList<>();
+        if (pakinDataList != null && !pakinDataList.isEmpty()) {
+            rawDataList.addAll(pakinDataList);
+        }
+        if (pakoutDataList != null && !pakoutDataList.isEmpty()) {
+            rawDataList.addAll(pakoutDataList);
+        }
+        
+        // 妫�鏌ユ槸鍚︽湁鍑哄叆搴撳巻鍙茶鍗�
+        if (rawDataList == null || rawDataList.isEmpty()) {
+            throw new CoolException("鏈堢粨鏃堕棿鑼冨洿鍐呮病鏈夊嚭鍏ュ簱鍘嗗彶璁㈠崟锛屾棤娉曡繘琛屾湀缁�");
+        }
+        
+        // 鍦↗ava浠g爜涓鐞嗗垎绫荤粺璁¢�昏緫
+        // 1. 澶勭悊NULL鍊硷紙batch銆乥rand銆乵aktx锛�
+        // 2. 鏍规嵁鐗╂枡缂栫爜銆佹壒娆°�佸搧鐗屽垎缁�
+        // 3. 鏍规嵁 pakin_pakout_status 鍖哄垎鍏ュ簱鍜屽嚭搴�
+        Map<String, MaterialInOutStatDTO> materialStatsMap = new HashMap<>();
+        Map<String, String> maktxMap = new HashMap<>(); // 瀛樺偍鐗╂枡鍚嶇О锛堝彇绗竴涓潪绌哄�硷級
+        
+        for (MaterialInOutRawDTO raw : rawDataList) {
+            // 澶勭悊NULL鍊�
+            String matnr = raw.getMatnr();
+            String batch = raw.getBatch() != null ? raw.getBatch() : "";
+            String brand = raw.getBrand() != null ? raw.getBrand() : "";
+            String maktx = raw.getMaktx() != null ? raw.getMaktx() : "";
+            String key = matnr + "_" + batch + "_" + brand;
+            
+            // 淇濆瓨鐗╂枡鍚嶇О锛堝彇绗竴涓潪绌哄�硷級
+            if (maktx != null && !maktx.isEmpty() && !maktxMap.containsKey(key)) {
+                maktxMap.put(key, maktx);
+            }
+            
+            MaterialInOutStatDTO stat = materialStatsMap.get(key);
+            if (stat == null) {
+                stat = new MaterialInOutStatDTO();
+                stat.setMatnr(matnr);
+                stat.setMaktx(maktxMap.getOrDefault(key, ""));
+                stat.setBatch(batch);
+                stat.setBrand(brand);
+                stat.setInQty(BigDecimal.ZERO);
+                stat.setOutQty(BigDecimal.ZERO);
+                materialStatsMap.put(key, stat);
+            }
+            
+            // 鏍规嵁 pakin_pakout_status 鍒嗙被缁熻
+            // 1 = 鍏ュ簱锛�2 = 鍑哄簱锛�0 = 鏈煡锛堝凡鍦⊿QL涓繃婊わ級
+            BigDecimal qty = raw.getQty() != null ? raw.getQty() : BigDecimal.ZERO;
+            Integer status = raw.getPakinPakoutStatus();
+            if (status != null && qty.compareTo(BigDecimal.ZERO) > 0) {
+                if (status == 1) {
+                    // 鍏ュ簱
+                    stat.setInQty(stat.getInQty().add(qty));
+                } else if (status == 2) {
+                    // 鍑哄簱
+                    stat.setOutQty(stat.getOutQty().add(qty));
+                }
+            }
+        }
+        
+        // 杞崲涓篖ist
+        List<MaterialInOutStatDTO> materialStats = new java.util.ArrayList<>(materialStatsMap.values());
+
+        // 鑾峰彇涓婁竴涓湀缁撹褰曪紙鐢ㄤ簬璁$畻鏈熷垵搴撳瓨鍜屾壙鎺ヤ笂涓�鏈熺殑鐗╂枡锛�
+        MonthlySettle   previousSettle = getLatestSettle();
+        Map<String, BigDecimal> previousEndingQtyMap = new HashMap<>();
+        Map<String, PreviousSettleEndingQtyDTO> previousDetailMap = new HashMap<>(); // 瀛樺偍涓婁竴鏈熺殑瀹屾暣鏄庣粏淇℃伅
+        if (previousSettle != null) {
+            List<PreviousSettleEndingQtyDTO> previousDetails = this.baseMapper.getPreviousSettleEndingQty(previousSettle.getId());
+            for (PreviousSettleEndingQtyDTO detail : previousDetails) {
+                String key = detail.getMatnr() + "_" + 
+                            (detail.getBatch() != null ? detail.getBatch() : "") + "_" + 
+                            (detail.getBrand() != null ? detail.getBrand() : "");
+                BigDecimal endingQty = detail.getEndingQty() != null ? detail.getEndingQty() : BigDecimal.ZERO;
+                previousEndingQtyMap.put(key, endingQty);
+                previousDetailMap.put(key, detail); // 淇濆瓨瀹屾暣淇℃伅锛岀敤浜庡悗缁垱寤烘槑缁�
+            }
+        }
+
+        // 鐢熸垚鏈堢粨缂栧彿
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+        String settleNo = "MS" + sdf.format(new Date()) + String.format("%04d", snowflakeIdWorker.nextId() % 10000);
+
+        // 鍒涘缓鏈堢粨涓昏褰�
+        MonthlySettle monthlySettle = new MonthlySettle();
+        monthlySettle.setSettleNo(settleNo);
+        monthlySettle.setStartDate(startDate);
+        monthlySettle.setEndDate(endDate);
+        monthlySettle.setStatus(1); // 宸叉湀缁�
+        monthlySettle.setIsDeleted(0); // 鏈垹闄�
+        monthlySettle.setCreateBy(userId);
+        monthlySettle.setCreateTime(new Date());
+        this.insert(monthlySettle);
+
+        BigDecimal totalInQty = BigDecimal.ZERO;
+        BigDecimal totalOutQty = BigDecimal.ZERO;
+        int materialCount = 0;
+
+        // 鍒涘缓 Map 瀛樺偍鏈湡鏈夊嚭鍏ュ簱鐨勭墿鏂欙紙鐢ㄤ簬鍒ゆ柇鏄惁闇�瑕佷粠涓婁竴鏈熺户鎵匡級
+        Map<String, MaterialInOutStatDTO> currentMaterialMap = new HashMap<>();
+        for (MaterialInOutStatDTO stat : materialStats) {
+            String matnr = stat.getMatnr();
+            String batch = stat.getBatch() != null ? stat.getBatch() : "";
+            String brand = stat.getBrand() != null ? stat.getBrand() : "";
+            String key = matnr + "_" + batch + "_" + brand;
+            currentMaterialMap.put(key, stat);
+        }
+
+        // 鏀堕泦鎵�鏈夋槑缁嗚褰曪紝鐢ㄤ簬鎵归噺鎻掑叆
+        List<MonthlySettleDetail> detailList = new java.util.ArrayList<>();
+
+        // 1. 澶勭悊鏈湡鏈夊嚭鍏ュ簱鐨勭墿鏂�
+        for (MaterialInOutStatDTO stat : materialStats) {
+            // 1. 鎻愬彇鍩虹淇℃伅
+            String matnr = stat.getMatnr();
+            String batch = stat.getBatch() != null ? stat.getBatch() : "";
+            String brand = stat.getBrand() != null ? stat.getBrand() : "";
+            String maktx = stat.getMaktx();
+            
+            // 2. 鎻愬彇鏁伴噺淇℃伅
+            BigDecimal inQty = stat.getInQty() != null ? stat.getInQty() : BigDecimal.ZERO;
+            BigDecimal outQty = stat.getOutQty() != null ? stat.getOutQty() : BigDecimal.ZERO;
+            
+            // 3. 璁$畻搴撳瓨鐩稿叧鏁伴噺
+            BigDecimal beginningQty = getBeginningQty(matnr, batch, brand, previousEndingQtyMap);
+            BigDecimal endingQty = calculateEndingQty(beginningQty, inQty, outQty);
+            // 宸紓鏁伴噺 = 鏈熸湯搴撳瓨 - 鏈熷垵搴撳瓨锛堟湡鏈ぇ浜庢湡鍒濇椂涓烘鏁帮級
+            BigDecimal diffQty = calculateDiffQty(beginningQty, endingQty);
+            
+            // 4. 鍒涘缓鏄庣粏璁板綍锛堟殏涓嶆彃鍏ワ級
+            MonthlySettleDetail detail = buildMonthlySettleDetail(
+                monthlySettle.getId(), settleNo, matnr, batch, maktx, brand,
+                beginningQty, inQty, outQty, endingQty, diffQty
+            );
+            detail.setIsDeleted(0); // 鏈垹闄�
+            detailList.add(detail);
+
+            // 5. 绱缁熻
+            totalInQty = totalInQty.add(inQty);
+            totalOutQty = totalOutQty.add(outQty);
+            materialCount++;
+        }
+
+        // 2. 澶勭悊涓婁竴鏈熷瓨鍦ㄤ絾鏈湡娌℃湁鍑哄叆搴撶殑鐗╂枡锛堥渶瑕佹壙鎺ユ樉绀猴級
+        if (previousSettle != null && !previousDetailMap.isEmpty()) {
+            for (Map.Entry<String, PreviousSettleEndingQtyDTO> entry : previousDetailMap.entrySet()) {
+                String key = entry.getKey();
+                // 濡傛灉鏈湡娌℃湁鍑哄叆搴擄紝浣嗕笂涓�鏈熸湁鏈熸湯搴撳瓨锛堜笖涓嶄负0锛夛紝鍒欓渶瑕佸垱寤轰竴鏉¤褰�
+                if (!currentMaterialMap.containsKey(key)) {
+                    PreviousSettleEndingQtyDTO previousDetail = entry.getValue();
+                    BigDecimal previousEndingQty = previousDetail.getEndingQty() != null ? previousDetail.getEndingQty() : BigDecimal.ZERO;
+                    
+                    // 濡傛灉涓婁竴鏈熺殑鏈熸湯搴撳瓨涓嶄负0锛屾垨鑰呭嵆浣夸负0涔熻鏄剧ず锛堢敤浜庡姣旓級
+                    // 杩欓噷鎴戜滑鎬绘槸鍒涘缓璁板綍锛屽嵆浣夸笂涓�鏈熸湡鏈簱瀛樹负0锛屽洜涓虹敤鎴疯姹�"濡傛灉涓婁竴鏈熷瓨鍦ㄨ繃锛屾湰鏈熷簱瀛樺綊闆朵篃瑕佹樉绀轰竴鏉′负0鐨勮褰�"
+                    String matnr = previousDetail.getMatnr();
+                    String batch = previousDetail.getBatch() != null ? previousDetail.getBatch() : "";
+                    String brand = previousDetail.getBrand() != null ? previousDetail.getBrand() : "";
+                    String maktx = previousDetail.getMaktx() != null ? previousDetail.getMaktx() : "";
+                    
+                    // 鏈湡娌℃湁鍑哄叆搴擄紝鎵�浠ュ叆搴撳拰鍑哄簱鏁伴噺閮戒负0
+                    BigDecimal inQty = BigDecimal.ZERO;
+                    BigDecimal outQty = BigDecimal.ZERO;
+                    
+                    // 鏈熷垵搴撳瓨 = 涓婁竴鏈熺殑鏈熸湯搴撳瓨
+                    BigDecimal beginningQty = previousEndingQty;
+                    // 鏈熸湯搴撳瓨 = 鏈熷垵 + 鍏ュ簱 - 鍑哄簱 = 鏈熷垵锛堝洜涓烘湰鏈熸病鏈夊嚭鍏ュ簱锛�
+                    BigDecimal endingQty = beginningQty;
+                    // 宸紓鏁伴噺 = 鏈熷垵搴撳瓨 - 鏈熸湯搴撳瓨锛堟湡鍒濆ぇ浜庢湡鏈椂涓烘鏁帮級
+                    BigDecimal diffQty = calculateDiffQty(beginningQty, endingQty);
+                    
+                    // 鍒涘缓鏄庣粏璁板綍锛堟殏涓嶆彃鍏ワ級
+                    MonthlySettleDetail detail = buildMonthlySettleDetail(
+                        monthlySettle.getId(), settleNo, matnr, batch, maktx, brand,
+                        beginningQty, inQty, outQty, endingQty, diffQty
+                    );
+                    detail.setIsDeleted(0); // 鏈垹闄�
+                    detailList.add(detail);
+                    
+                    // 绱缁熻锛堣櫧鐒跺叆搴撳拰鍑哄簱涓�0锛屼絾涔熻璁″叆鐗╂枡绉嶇被鏁帮級
+                    materialCount++;
+                }
+            }
+        }
+
+        // 鍒嗘壒鎻掑叆锛屾瘡鎵�1000鏉★紝閬垮厤涓�娆℃�ф彃鍏ヨ繃澶氭暟鎹�
+        if (!detailList.isEmpty()) {
+            int batchSize = 1000;
+            for (int i = 0; i < detailList.size(); i += batchSize) {
+                int end = Math.min(i + batchSize, detailList.size());
+                List<MonthlySettleDetail> batch = detailList.subList(i, end);
+                for (MonthlySettleDetail detail : batch) {
+                    if (monthlySettleDetailMapper.insert(detail) <= 0) {
+                        throw new CoolException("鎻掑叆鏈堢粨鏄庣粏澶辫触");
+                    }
+                }
+            }
+        }
+
+        // 鏇存柊鏈堢粨涓昏褰�
+        monthlySettle.setTotalInQty(totalInQty);
+        monthlySettle.setTotalOutQty(totalOutQty);
+        monthlySettle.setTotalMaterials(materialCount);
+        monthlySettle.setStatus(1); // 宸叉湀缁�
+        monthlySettle.setUpdateBy(userId);
+        monthlySettle.setUpdateTime(new Date());
+        this.updateById(monthlySettle);
+
+        // 鏇存柊璁㈠崟鐨勬湀缁撲俊鎭紙鍏ュ簱鍜屽嚭搴撻兘瑕佹洿鏂帮級
+        this.baseMapper.updateOrderSettleInfo(monthlySettle.getId(), settleNo, startDateStr, endDateStr);
+        this.baseMapper.updateOrderSettleInfoPakout(monthlySettle.getId(), settleNo, startDateStr, endDateStr);
+
+        MonthlySettleResultVO result = new MonthlySettleResultVO();
+        result.setSettleId(monthlySettle.getId());
+        result.setSettleNo(settleNo);
+        result.setTotalInQty(totalInQty);
+        result.setTotalOutQty(totalOutQty);
+        result.setTotalMaterials(materialCount);
+        return result;
+    }
+
+    @Override
+    public MonthlySettleStatisticsVO getSettleStatistics(Long settleId) {
+        MonthlySettle settle = this.selectById(settleId);
+        if (settle == null || (settle.getIsDeleted() != null && settle.getIsDeleted() == 1)) {
+            throw new CoolException("鏈堢粨璁板綍涓嶅瓨鍦�");
+        }
+
+        // 鍏宠仈鐗╂枡琛ㄦ煡璇㈡槑缁�
+        List<MonthlySettleDetail> details = monthlySettleDetailMapper.selectDetailWithMat(settleId);
+
+        MonthlySettleStatisticsVO result = new MonthlySettleStatisticsVO();
+        result.setSettle(settle);
+        result.setDetails(details);
+        return result;
+    }
+
+    @Override
+    public Page<MonthlySettle> getPage(Page<MonthlySettle> page) {
+        Map<String, Object> condition = page.getCondition();
+        EntityWrapper<MonthlySettle> wrapper = new EntityWrapper<>();
+        wrapper.eq("is_deleted", 0);
+        
+        if (condition != null) {
+            if (condition.get("settleNo") != null) {
+                wrapper.like("settle_no", condition.get("settleNo").toString());
+            }
+            if (condition.get("status") != null) {
+                wrapper.eq("status", condition.get("status"));
+            }
+            if (condition.get("startDate") != null && condition.get("endDate") != null) {
+                wrapper.ge("start_date", condition.get("startDate"));
+                wrapper.le("end_date", condition.get("endDate"));
+            }
+        }
+        
+        wrapper.orderBy("create_time", false);
+        List<MonthlySettle> list = this.selectList(wrapper);
+        
+        EntityWrapper<MonthlySettle> countWrapper = new EntityWrapper<>();
+        countWrapper.eq("is_deleted", 0);
+        if (condition != null) {
+            if (condition.get("settleNo") != null) {
+                countWrapper.like("settle_no", condition.get("settleNo").toString());
+            }
+            if (condition.get("status") != null) {
+                countWrapper.eq("status", condition.get("status"));
+            }
+            if (condition.get("startDate") != null && condition.get("endDate") != null) {
+                countWrapper.ge("start_date", condition.get("startDate"));
+                countWrapper.le("end_date", condition.get("endDate"));
+            }
+        }
+        page.setRecords(list);
+        page.setTotal(this.selectCount(countWrapper));
+        return page;
+    }
+
+    /**
+     * 鑾峰彇鏈熷垵搴撳瓨锛堜笂鏈熺粨浣欙級
+     */
+    private BigDecimal getBeginningQty(String matnr, String batch, String brand, Map<String, BigDecimal> previousEndingQtyMap) {
+        String key = matnr + "_" + batch + "_" + brand;
+        return previousEndingQtyMap.getOrDefault(key, BigDecimal.ZERO);
+    }
+
+    /**
+     * 璁$畻鏈熸湯搴撳瓨锛堟湡鍒�+鍏ュ簱-鍑哄簱锛�
+     */
+    private BigDecimal calculateEndingQty(BigDecimal beginningQty, BigDecimal inQty, BigDecimal outQty) {
+        return beginningQty.add(inQty).subtract(outQty);
+    }
+
+    /**
+     * 鑾峰彇褰撳墠瀹為檯搴撳瓨鏁伴噺锛堝凡搴熷純锛屾敼鐢ㄦ壒閲忔煡璇級
+     * @deprecated 浣跨敤鎵归噺鏌ヨ鏂规硶鏇夸唬锛岄伩鍏峃+1鏌ヨ闂
+     */
+    @Deprecated
+    private BigDecimal getCurrentStockQty(String matnr, String batch) {
+        Double stockQty = manLocDetlService.queryStockAnfme(matnr, batch);
+        return stockQty != null ? BigDecimal.valueOf(stockQty) : BigDecimal.ZERO;
+    }
+
+    /**
+     * 璁$畻宸紓鏁伴噺锛堟湡鏈簱瀛�-鏈熷垵搴撳瓨锛�
+     * 鏈熸湯澶т簬鏈熷垵鏃朵负姝f暟锛岃〃绀哄簱瀛樺鍔�
+     */
+    private BigDecimal calculateDiffQty(BigDecimal beginningQty, BigDecimal endingQty) {
+        return endingQty.subtract(beginningQty);
+    }
+
+    /**
+     * 鏋勫缓鏈堢粨鏄庣粏瀵硅薄
+     */
+    private MonthlySettleDetail buildMonthlySettleDetail(
+            Long settleId, String settleNo, String matnr, String batch, String maktx, String brand,
+            BigDecimal beginningQty, BigDecimal inQty, BigDecimal outQty, BigDecimal endingQty,
+            BigDecimal diffQty) {
+        MonthlySettleDetail detail = new MonthlySettleDetail();
+        // 鍩烘湰淇℃伅
+        detail.setSettleId(settleId);
+        detail.setSettleNo(settleNo);
+        detail.setMatnr(matnr);
+        detail.setBatch(batch);
+        detail.setMaktx(maktx);
+        detail.setBrand(brand);
+        // 鏁伴噺淇℃伅
+        detail.setBeginningQty(beginningQty);
+        detail.setInQty(inQty);
+        detail.setOutQty(outQty);
+        detail.setEndingQty(endingQty);
+        // stock_qty 瀛楁宸插簾寮冿紝瀹為檯搴撳瓨绛変簬鏈熸湯搴撳瓨锛屼笉鍐嶅崟鐙瓨鍌�
+        // detail.setStockQty(endingQty);
+        detail.setDiffQty(diffQty);
+        // 鏃堕棿淇℃伅
+        detail.setCreateTime(new Date());
+        return detail;
+    }
+
+    @Override
+    @Transactional
+    public void deleteSettle(Long settleId) {
+        MonthlySettle settle = this.selectById(settleId);
+        if (settle == null || (settle.getIsDeleted() != null && settle.getIsDeleted() == 1)) {
+            throw new CoolException("鏈堢粨璁板綍涓嶅瓨鍦�");
+        }
+
+        // 娓呴櫎鍑哄叆搴撹鍗曠殑鏈堢粨淇℃伅
+        this.baseMapper.clearOrderSettleInfo(settleId);
+        this.baseMapper.clearOrderSettleInfoPakout(settleId);
+
+        // 閫昏緫鍒犻櫎鏈堢粨鏄庣粏
+        EntityWrapper<MonthlySettleDetail> detailWrapper = new EntityWrapper<>();
+        detailWrapper.eq("settle_id", settleId);
+        detailWrapper.eq("is_deleted", 0);
+        List<MonthlySettleDetail> details = monthlySettleDetailMapper.selectList(detailWrapper);
+        if (details != null && !details.isEmpty()) {
+            for (MonthlySettleDetail detail : details) {
+                detail.setIsDeleted(1);
+                monthlySettleDetailMapper.updateById(detail);
+            }
+        }
+
+        // 閫昏緫鍒犻櫎鏈堢粨涓昏褰�
+        settle.setIsDeleted(1);
+        settle.setUpdateTime(new Date());
+        this.updateById(settle);
+    }
+
+    @Override
+    public boolean isOrderTimeInSettledRange(String orderTime) {
+        if (Cools.isEmpty(orderTime)) {
+            return false;
+        }
+        try {
+            // 瑙f瀽璁㈠崟涓氬姟鏃堕棿
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            Date orderDate = sdf.parse(orderTime);
+            
+            // 鏌ヨ鎵�鏈夊凡鏈堢粨鐨勮褰曪紙status=1涓旀湭鍒犻櫎锛�
+            EntityWrapper<MonthlySettle> wrapper = new EntityWrapper<>();
+            wrapper.eq("status", 1);
+            wrapper.eq("is_deleted", 0);
+            List<MonthlySettle> settledList = this.selectList(wrapper);
+            
+            if (settledList == null || settledList.isEmpty()) {
+                return false;
+            }
+            
+            // 妫�鏌ヨ鍗曟椂闂存槸鍚﹀湪浠讳綍宸叉湀缁撶殑鍖洪棿鍐�
+            for (MonthlySettle settle : settledList) {
+                Date startDate = settle.getStartDate();
+                Date endDate = settle.getEndDate();
+                
+                // 纭繚startDate鏄綋澶╃殑00:00:00
+                Calendar startCal = Calendar.getInstance();
+                startCal.setTime(startDate);
+                startCal.set(Calendar.HOUR_OF_DAY, 0);
+                startCal.set(Calendar.MINUTE, 0);
+                startCal.set(Calendar.SECOND, 0);
+                startCal.set(Calendar.MILLISECOND, 0);
+                
+                // 纭繚endDate鏄綋澶╃殑23:59:59.999
+                Calendar endCal = Calendar.getInstance();
+                endCal.setTime(endDate);
+                endCal.set(Calendar.HOUR_OF_DAY, 23);
+                endCal.set(Calendar.MINUTE, 59);
+                endCal.set(Calendar.SECOND, 59);
+                endCal.set(Calendar.MILLISECOND, 999);
+                
+                // 鍒ゆ柇璁㈠崟鏃堕棿鏄惁鍦ㄥ尯闂村唴锛歔startDate鐨�00:00:00, endDate鐨�23:59:59.999]
+                if (!orderDate.before(startCal.getTime()) && !orderDate.after(endCal.getTime())) {
+                    return true;
+                }
+            }
+            
+            return false;
+        } catch (Exception e) {
+            log.error("妫�鏌ヨ鍗曟椂闂存槸鍚﹀湪宸叉湀缁撳尯闂村唴澶辫触", e);
+            return false;
+        }
+    }
+}
+

--
Gitblit v1.9.1