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;
|
}
|
}
|
}
|