package com.vincent.rsf.server.manager.schedules; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.server.manager.entity.Matnr; import com.vincent.rsf.server.manager.entity.WkOrder; import com.vincent.rsf.server.manager.entity.WkOrderItem; import com.vincent.rsf.server.manager.service.AsnOrderItemService; import com.vincent.rsf.server.manager.service.AsnOrderService; import com.vincent.rsf.server.manager.service.MatnrService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; /** * ASN 单据压测数据定时生成器。 */ @Slf4j @Component public class AsnOrderPressureSchedules { private static final DateTimeFormatter ORDER_CODE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); private static final String ORDER_TYPE = "in"; private static final String ORDER_WORK_TYPE = "71"; private static final Integer TENANT_ID = 1; private static final Long USER_ID = 51L; private static final String MEMO = "ASN_PRESSURE_TEST"; private final AtomicBoolean running = new AtomicBoolean(false); @Autowired private AsnOrderService asnOrderService; @Autowired private AsnOrderItemService asnOrderItemService; @Autowired private MatnrService matnrService; @Value("${pressure.asn-order.enabled:false}") private boolean enabled; @Value("${pressure.asn-order.order-count-per-run:20}") private int orderCountPerRun; @Value("${pressure.asn-order.item-count-per-order:5}") private int itemCountPerOrder; @Value("${pressure.asn-order.item-qty:10}") private double itemQty; @Scheduled(cron = "${pressure.asn-order.cron:0/10 * * * * ?}") @Transactional(rollbackFor = Exception.class) public void insertPressureOrders() { if (!enabled) { return; } if (!running.compareAndSet(false, true)) { log.warn("ASN压测任务仍在执行中,本轮跳过"); return; } try { if (orderCountPerRun <= 0 || itemCountPerOrder <= 0 || itemQty <= 0) { log.warn("ASN压测任务配置无效,跳过执行: orderCountPerRun={}, itemCountPerOrder={}, itemQty={}", orderCountPerRun, itemCountPerOrder, itemQty); return; } List matnrs = loadMatnrs(); if (matnrs.isEmpty()) { log.warn("ASN压测任务未获取到可用物料,跳过执行"); return; } Collections.shuffle(matnrs); Date now = new Date(); LocalDateTime nowTime = LocalDateTime.now(); double totalQty = itemCountPerOrder * itemQty; List orders = new ArrayList<>(orderCountPerRun); for (int i = 0; i < orderCountPerRun; i++) { orders.add(buildOrder(now, nowTime, totalQty, i)); } if (!asnOrderService.saveBatch(orders, 200)) { throw new CoolException("ASN压测主单插入失败"); } List items = new ArrayList<>(orderCountPerRun * itemCountPerOrder); for (int orderIndex = 0; orderIndex < orders.size(); orderIndex++) { WkOrder order = orders.get(orderIndex); for (int itemIndex = 0; itemIndex < itemCountPerOrder; itemIndex++) { Matnr matnr = matnrs.get((orderIndex * itemCountPerOrder + itemIndex) % matnrs.size()); items.add(buildOrderItem(order, matnr, now, orderIndex, itemIndex)); } } if (!asnOrderItemService.saveBatch(items, 500)) { throw new CoolException("ASN压测明细插入失败"); } log.info("ASN压测任务执行完成,本次插入主单 {} 条,明细 {} 条", orders.size(), items.size()); } finally { running.set(false); } } private List loadMatnrs() { int needCount = Math.min(Math.max(orderCountPerRun * itemCountPerOrder, 200), 2000); return matnrService.list(new LambdaQueryWrapper() .eq(Matnr::getDeleted, 0) .eq(Matnr::getStatus, 1) .select(Matnr::getId, Matnr::getCode, Matnr::getName, Matnr::getFieldsIndex, Matnr::getSpec, Matnr::getModel, Matnr::getUnit, Matnr::getPurUnit, Matnr::getStockUnit, Matnr::getBaseUnit, Matnr::getUseOrgId, Matnr::getUseOrgName, Matnr::getErpClsId) .orderByDesc(Matnr::getId) .last("limit " + needCount)); } private WkOrder buildOrder(Date now, LocalDateTime nowTime, double totalQty, int sequence) { String suffix = String.format("%04d", sequence + 1); String code = "erp" + nowTime.format(ORDER_CODE_FORMATTER) + suffix; long serialNo = System.currentTimeMillis() * 1000 + sequence; return new WkOrder() .setCode(code) .setPoCode(code) .setPoId(serialNo) .setType(ORDER_TYPE) .setWkType(ORDER_WORK_TYPE) .setAnfme(totalQty) .setQty(totalQty) .setWorkQty(0.0) .setCheckType(0) .setRleStatus((short) 0) .setNtyStatus(0) .setExceStatus((short) 4) .setStatus(1) .setDeleted(0) .setTenantId(TENANT_ID) .setCreateBy(USER_ID) .setCreateTime(now) .setUpdateBy(USER_ID) .setUpdateTime(now) .setMemo(MEMO) .setReportOnce(4) .setBusinessTime(now) .setStationId("1215") .setOrderInternalCode(String.valueOf(serialNo)) .setStockDirect("stockDirect") .setCustomerId("custom1") .setCustomerName("客户1") .setSupplierId("gongys1") .setSupplierName("供应商1") .setStockOrgId("stockYH") .setStockOrgName("浙江银湖箱包有限公司仓库") .setPurchaseOrgId("yhcaigou") .setPurchaseOrgName("浙江银湖箱包有限公司采购") .setPurchaseUserId("caigouyuan1") .setPurchaseUserName("采购员1") .setPrdOrgId("prdYH") .setPrdOrgName("浙江银湖箱包有限公司") .setSaleOrgId("sale1") .setSaleOrgName("生产组1") .setSaleUserId("shengchanyuan1") .setSaleUserName("生产员1") .setVersion(0); } private WkOrderItem buildOrderItem(WkOrder order, Matnr matnr, Date now, int orderIndex, int itemIndex) { String stockUnit = StringUtils.firstNonBlank(matnr.getStockUnit(), matnr.getPurUnit(), matnr.getUnit(), matnr.getBaseUnit()); String purUnit = StringUtils.firstNonBlank(matnr.getPurUnit(), matnr.getUnit(), matnr.getStockUnit(), matnr.getBaseUnit()); String baseUnit = StringUtils.firstNonBlank(matnr.getBaseUnit(), matnr.getUnit(), matnr.getStockUnit(), matnr.getPurUnit()); String batchCode = "B" + new SimpleDateFormat("yyyyMMddHHmmss").format(now) + String.format("%02d%02d", orderIndex + 1, itemIndex + 1); String trackCode = "T" + System.currentTimeMillis() + String.format("%02d%02d", orderIndex + 1, itemIndex + 1); return new WkOrderItem() .setOrderId(order.getId()) .setOrderCode(order.getCode()) .setPlatItemId("M" + (itemIndex + 1)) .setPoCode(order.getPoCode()) .setFieldsIndex(matnr.getFieldsIndex()) .setMatnrId(matnr.getId()) .setMatnrCode(matnr.getCode()) .setMaktx(matnr.getName()) .setSpec(matnr.getSpec()) .setModel(matnr.getModel()) .setAnfme(itemQty) .setWorkQty(0.0) .setPurQty(itemQty) .setQty(itemQty) .setStockUnit(stockUnit) .setPurUnit(purUnit) .setBatch(batchCode) .setSplrBatch(batchCode) .setSplrCode("gongys1") .setSplrName("供应商1") .setTrackCode(trackCode) .setBarcode(trackCode) .setProdTime(new SimpleDateFormat("yyyy-MM-dd").format(now)) .setNtyStatus(0) .setStatus(1) .setDeleted(0) .setTenantId(TENANT_ID) .setCreateBy(USER_ID) .setCreateTime(now) .setUpdateBy(USER_ID) .setUpdateTime(now) .setMemo(MEMO) .setBaseUnit(baseUnit) .setUseOrgId(matnr.getUseOrgId()) .setUseOrgName(matnr.getUseOrgName()) .setErpClsId(matnr.getErpClsId()) .setPriceUnitId(baseUnit); } }