| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.stock.service.impl; |
| | | |
| | | import com.ruoyi.production.mapper.ProductionOrderMapper; |
| | | import com.ruoyi.production.mapper.ProductionOrderPickMapper; |
| | | import com.ruoyi.production.pojo.ProductionOrder; |
| | | import com.ruoyi.production.pojo.ProductionOrderPick; |
| | | import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper; |
| | | import com.ruoyi.purchase.pojo.PurchaseReturnOrders; |
| | | import com.ruoyi.sales.mapper.SalesLedgerMapper; |
| | | import com.ruoyi.sales.mapper.ShippingInfoMapper; |
| | | import com.ruoyi.sales.pojo.SalesLedger; |
| | | import com.ruoyi.sales.pojo.ShippingInfo; |
| | | import com.ruoyi.stock.mapper.StockOutRecordMapper; |
| | | import com.ruoyi.stock.pojo.StockOutRecord; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.boot.test.context.SpringBootTest; |
| | | import org.springframework.jdbc.core.JdbcTemplate; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @SpringBootTest |
| | | public class StockOutRecordBatchUpdateTest { |
| | | |
| | | @Autowired |
| | | private JdbcTemplate jdbcTemplate; |
| | | |
| | | @Autowired |
| | | private StockOutRecordMapper stockOutRecordMapper; |
| | | |
| | | @Autowired |
| | | private PurchaseReturnOrdersMapper purchaseReturnOrdersMapper; |
| | | |
| | | @Autowired |
| | | private ShippingInfoMapper shippingInfoMapper; |
| | | |
| | | @Autowired |
| | | private SalesLedgerMapper salesLedgerMapper; |
| | | |
| | | @Autowired |
| | | private ProductionOrderPickMapper productionOrderPickMapper; |
| | | |
| | | @Autowired |
| | | private ProductionOrderMapper productionOrderMapper; |
| | | |
| | | /** |
| | | * æ´æ°åºåºåæ¶é´ |
| | | */ |
| | | @Test |
| | | void testUpdateStockOutRecords() { |
| | | List<StockOutRecord> allRecords = stockOutRecordMapper.selectList(null); |
| | | System.out.println("æ»è®°å½æ°: " + allRecords.size()); |
| | | |
| | | List<RecordWithDate> recordWithDates = new ArrayList<>(); |
| | | |
| | | for (StockOutRecord record : allRecords) { |
| | | String type = record.getRecordType(); |
| | | if (type == null) continue; |
| | | |
| | | switch (type) { |
| | | case "1": |
| | | case "10": |
| | | recordWithDates.add(resolveType1or10(record, type)); |
| | | break; |
| | | case "3": |
| | | System.out.println("ç±»å3ï¼ç产æ¥å·¥-åºåºï¼é¢ç忝ï¼å½åæ æ°æ®ï¼è·³è¿"); |
| | | break; |
| | | case "8": |
| | | System.out.println("ç±»å8ï¼éå®-åºåºï¼é¢ç忝ï¼å½åæ æ°æ®ï¼è·³è¿"); |
| | | break; |
| | | case "9": |
| | | recordWithDates.add(resolveType9(record)); |
| | | break; |
| | | case "13": |
| | | recordWithDates.add(resolveType13(record)); |
| | | break; |
| | | case "14": |
| | | recordWithDates.add(resolveType14or15(record)); |
| | | break; |
| | | case "15": |
| | | recordWithDates.add(resolveType14or15(record)); |
| | | break; |
| | | default: |
| | | System.out.println("æªç¥ç±»å " + type + "ï¼è·³è¿ ID=" + record.getId()); |
| | | } |
| | | } |
| | | |
| | | Map<LocalDate, List<RecordWithDate>> byDate = recordWithDates.stream() |
| | | .collect(Collectors.groupingBy( |
| | | rwd -> rwd.dateTime.toLocalDate(), |
| | | LinkedHashMap::new, |
| | | Collectors.toList() |
| | | )); |
| | | |
| | | int totalUpdated = 0; |
| | | for (Map.Entry<LocalDate, List<RecordWithDate>> dateEntry : byDate.entrySet()) { |
| | | LocalDate date = dateEntry.getKey(); |
| | | List<RecordWithDate> records = dateEntry.getValue(); |
| | | records.sort(Comparator.comparing(rwd -> rwd.dateTime)); |
| | | |
| | | assignRandomTimes(records, date); |
| | | |
| | | records.sort(Comparator.comparing(rwd -> rwd.dateTime)); |
| | | |
| | | int seq = 1; |
| | | for (RecordWithDate rwd : records) { |
| | | StockOutRecord record = rwd.record; |
| | | String type = record.getRecordType(); |
| | | String batchNo = "CK" + date.format(DateTimeFormatter.ofPattern("yyyyMMdd")) + String.format("%03d", seq++); |
| | | LocalDateTime createTime = rwd.dateTime; |
| | | |
| | | jdbcTemplate.update( |
| | | "UPDATE stock_out_record SET outbound_batches = ?, create_time = ?, update_time = ? WHERE id = ?", |
| | | batchNo, createTime, createTime, record.getId()); |
| | | |
| | | System.out.println("ID=" + record.getId() |
| | | + " type=" + type |
| | | + " batch=" + batchNo |
| | | + " time=" + createTime); |
| | | totalUpdated++; |
| | | } |
| | | } |
| | | |
| | | System.out.println("å
¨é¨å®æï¼å
±æ´æ° " + totalUpdated + " æ¡è®°å½"); |
| | | } |
| | | |
| | | private void assignRandomTimes(List<RecordWithDate> records, LocalDate date) { |
| | | List<RecordWithDate> individual = new ArrayList<>(); |
| | | Map<Long, List<RecordWithDate>> grouped = new LinkedHashMap<>(); |
| | | |
| | | for (RecordWithDate rwd : records) { |
| | | String type = rwd.record.getRecordType(); |
| | | if (!"1".equals(type) && !"9".equals(type) && !"10".equals(type) |
| | | && !"13".equals(type) && !"14".equals(type) && !"15".equals(type)) { |
| | | continue; |
| | | } |
| | | if (("14".equals(type) || "15".equals(type)) && rwd.record.getRecordId() != null) { |
| | | grouped.computeIfAbsent(rwd.record.getRecordId(), k -> new ArrayList<>()).add(rwd); |
| | | } else { |
| | | individual.add(rwd); |
| | | } |
| | | } |
| | | |
| | | List<TimeSlot> slots = new ArrayList<>(); |
| | | for (RecordWithDate rwd : individual) { |
| | | slots.add(new TimeSlot(rwd.record.getId(), List.of(rwd))); |
| | | } |
| | | for (Map.Entry<Long, List<RecordWithDate>> entry : grouped.entrySet()) { |
| | | long minId = entry.getValue().stream() |
| | | .mapToLong(rwd -> rwd.record.getId()) |
| | | .min().orElse(0); |
| | | slots.add(new TimeSlot(minId, entry.getValue())); |
| | | } |
| | | |
| | | if (slots.isEmpty()) return; |
| | | |
| | | slots.sort(Comparator.comparingLong(s -> s.sortKey)); |
| | | |
| | | int totalMinutes = 480; |
| | | for (int i = 0; i < slots.size(); i++) { |
| | | int offsetMinutes = (int) ((long) i * totalMinutes / slots.size()); |
| | | int jitter = (int) (Math.random() * 6 - 3); |
| | | offsetMinutes = Math.max(0, Math.min(479, offsetMinutes + jitter)); |
| | | |
| | | LocalTime time; |
| | | if (offsetMinutes < 240) { |
| | | time = LocalTime.of(8, 0).plusMinutes(offsetMinutes); |
| | | } else { |
| | | time = LocalTime.of(14, 0).plusMinutes(offsetMinutes - 240); |
| | | } |
| | | LocalDateTime dt = LocalDateTime.of(date, time); |
| | | for (RecordWithDate rwd : slots.get(i).members) { |
| | | rwd.dateTime = dt; |
| | | } |
| | | } |
| | | } |
| | | |
| | | private static class TimeSlot { |
| | | final long sortKey; |
| | | final List<RecordWithDate> members; |
| | | |
| | | TimeSlot(long sortKey, List<RecordWithDate> members) { |
| | | this.sortKey = sortKey; |
| | | this.members = members; |
| | | } |
| | | } |
| | | |
| | | private RecordWithDate resolveType1or10(StockOutRecord record, String type) { |
| | | LocalDate date = record.getCreateTime() != null |
| | | ? record.getCreateTime().toLocalDate() |
| | | : LocalDate.now(); |
| | | return new RecordWithDate(record, LocalDateTime.of(date, LocalTime.of(8, 0))); |
| | | } |
| | | |
| | | private RecordWithDate resolveType9(StockOutRecord record) { |
| | | Long recordId = record.getRecordId(); |
| | | if (recordId != null) { |
| | | PurchaseReturnOrders pro = purchaseReturnOrdersMapper.selectById(recordId); |
| | | if (pro != null && pro.getPreparedAt() != null) { |
| | | return new RecordWithDate(record, LocalDateTime.of(pro.getPreparedAt(), LocalTime.of(8, 0))); |
| | | } |
| | | } |
| | | return fallbackDateTime(record); |
| | | } |
| | | |
| | | private RecordWithDate resolveType13(StockOutRecord record) { |
| | | Long recordId = record.getRecordId(); |
| | | if (recordId != null) { |
| | | ShippingInfo shippingInfo = shippingInfoMapper.selectById(recordId); |
| | | if (shippingInfo != null && shippingInfo.getSalesLedgerId() != null) { |
| | | SalesLedger salesLedger = salesLedgerMapper.selectById(shippingInfo.getSalesLedgerId()); |
| | | if (salesLedger != null && salesLedger.getDeliveryDate() != null) { |
| | | return new RecordWithDate(record, LocalDateTime.of(salesLedger.getDeliveryDate(), LocalTime.of(8, 0))); |
| | | } |
| | | } |
| | | } |
| | | return fallbackDateTime(record); |
| | | } |
| | | |
| | | private RecordWithDate resolveType14or15(StockOutRecord record) { |
| | | Long recordId = record.getRecordId(); |
| | | if (recordId != null) { |
| | | ProductionOrderPick pick = productionOrderPickMapper.selectById(recordId); |
| | | if (pick != null && pick.getProductionOrderId() != null) { |
| | | ProductionOrder order = productionOrderMapper.selectById(pick.getProductionOrderId()); |
| | | if (order != null && order.getStartTime() != null) { |
| | | return new RecordWithDate(record, LocalDateTime.of(order.getStartTime().toLocalDate(), LocalTime.of(8, 0))); |
| | | } |
| | | } |
| | | } |
| | | return fallbackDateTime(record); |
| | | } |
| | | |
| | | private RecordWithDate fallbackDateTime(StockOutRecord record) { |
| | | return record.getCreateTime() != null |
| | | ? new RecordWithDate(record, record.getCreateTime()) |
| | | : new RecordWithDate(record, LocalDateTime.now()); |
| | | } |
| | | |
| | | private static class RecordWithDate { |
| | | final StockOutRecord record; |
| | | LocalDateTime dateTime; |
| | | |
| | | RecordWithDate(StockOutRecord record, LocalDateTime dateTime) { |
| | | this.record = record; |
| | | this.dateTime = dateTime; |
| | | } |
| | | } |
| | | } |