#
cl
18 小时以前 c6938bcb89091596edab2740f7bf0b218956b4b0
#
3个文件已修改
150 ■■■■■ 已修改文件
rsf-server/src/main/java/com/vincent/rsf/server/common/config/SchedulerConfig.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/CusBarcodeSyncMatnrService.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/CusBarcodeSyncViewQueryService.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/config/SchedulerConfig.java
@@ -3,6 +3,7 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
@@ -12,6 +13,18 @@
@EnableScheduling
public class SchedulerConfig {
    /** 供未指定执行器名的 @Async 使用,避免与 taskScheduler、httpAuditExecutor 并存时报错 */
    @Bean(name = "taskExecutor")
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();
        ex.setCorePoolSize(2);
        ex.setMaxPoolSize(10);
        ex.setQueueCapacity(200);
        ex.setThreadNamePrefix("async-");
        ex.initialize();
        return ex;
    }
    @Bean
    public ThreadPoolTaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/CusBarcodeSyncMatnrService.java
@@ -12,6 +12,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -118,37 +119,48 @@
            syncMatnrNonForceFromView(cfg, matnrCodes, orderItemByCode, loginUserId);
            return;
        }
        List<Map<String, Object>> viewItems = cusBarcodeSyncViewQueryService.listByItemNos(matnrCodes);
        log.info("[cus_barcode_sync] FORCE_VIEW 分支 CUS_ITEM_SYNC_MODE.val={} viewRows={} viewBarcodes=[{}]",
                formatCfgVal(cfg.rawVal),
                viewItems == null ? 0 : viewItems.size(),
                summarizeViewBarcodes(viewItems));
        List<Map<String, Object>> viewItems = new ArrayList<>(matnrCodes.size());
        for (String code : matnrCodes) {
            boolean hit = CusBarcodeSyncViewQueryService.orderMatnrHitsBarcodeView(code, viewItems);
            List<Map<String, Object>> one = cusBarcodeSyncViewQueryService.listMapsForBarcode(code);
            boolean hit = CusBarcodeSyncViewQueryService.orderMatnrHitsBarcodeView(code, one);
            log.info("[cus_barcode_sync] 强制校验 code={} viewHit={}", code, hit);
            if (!hit) {
                throw new CoolException("物料未在视图 cus_barcode_sync_view 中:" + code);
            }
            viewItems.addAll(one);
        }
        log.info("[cus_barcode_sync] FORCE_VIEW 分支 CUS_ITEM_SYNC_MODE.val={} viewRows={} viewBarcodes=[{}]",
                formatCfgVal(cfg.rawVal),
                viewItems.size(),
                summarizeViewBarcodes(viewItems));
        cusBarcodeSyncMatnrApplyService.applyFromViewRows(viewItems, orderItemByCode, loginUserId);
    }
    private void syncMatnrNonForceFromView(CusItemSyncConfigSnapshot cfg, List<String> matnrCodes, Map<String, SyncOrdersItem> orderItemByCode, Long loginUserId) {
        List<Map<String, Object>> viewItems = null;
        Map<String, List<Map<String, Object>>> viewByCode = null;
        try {
            viewItems = cusBarcodeSyncViewQueryService.listByItemNos(matnrCodes);
            viewByCode = new LinkedHashMap<>();
            for (String code : matnrCodes) {
                viewByCode.put(code, cusBarcodeSyncViewQueryService.listMapsForBarcode(code));
            }
        } catch (Exception ex) {
            log.warn("[cus_barcode_sync] 查询 cus_barcode_sync_view 异常,将仅按物料表校验", ex);
        }
        int viewRowTotal = viewByCode == null ? 0 : viewByCode.values().stream().mapToInt(l -> l == null ? 0 : l.size()).sum();
        log.info("[cus_barcode_sync] NONE 分支 CUS_ITEM_SYNC_MODE.val={} 副库视图 rows={} barcodesInView=[{}]",
                formatCfgVal(cfg.rawVal),
                viewItems == null ? 0 : viewItems.size(),
                summarizeViewBarcodes(viewItems));
        if (viewItems != null && !viewItems.isEmpty()) {
                viewRowTotal,
                summarizeBarcodesWithHits(viewByCode));
        if (viewByCode != null) {
            try {
                cusBarcodeSyncMatnrApplyService.applyFromViewRows(viewItems, orderItemByCode, loginUserId);
                for (String code : matnrCodes) {
                    List<Map<String, Object>> one = viewByCode.get(code);
                    if (one != null && !one.isEmpty()) {
                        cusBarcodeSyncMatnrApplyService.applyFromViewRows(one, orderItemByCode, loginUserId);
                    }
                }
            } catch (Exception ex) {
                log.warn("[cus_barcode_sync] 批量 applyFromViewRows 失败", ex);
                log.warn("[cus_barcode_sync] 按条码 applyFromViewRows 失败", ex);
            }
        }
        // 视图有条码但本地仍无:按行补建档
@@ -158,29 +170,27 @@
                log.info("[cus_barcode_sync] 校验通过 code={} localMatnrId={}", code, m.getId());
                continue;
            }
            boolean viewHit = viewItems != null && CusBarcodeSyncViewQueryService.orderMatnrHitsBarcodeView(code, viewItems);
            int viewRowCount = viewItems == null ? 0 : viewItems.size();
            List<Map<String, Object>> one = viewByCode == null
                    ? Collections.emptyList()
                    : viewByCode.getOrDefault(code, Collections.emptyList());
            boolean viewHit = CusBarcodeSyncViewQueryService.orderMatnrHitsBarcodeView(code, one);
            int viewRowCount = one.size();
            log.info("[cus_barcode_sync] 本地无记录 code={} viewHit={} viewRowCount={}", code, viewHit, viewRowCount);
            Exception applyEx = null;
            if (viewHit && viewItems != null) {
                List<Map<String, Object>> rowsForCode = viewItems.stream()
                        .filter(r -> CusBarcodeSyncViewQueryService.rowMatchesOrderMatnr(code, Objects.toString(r.get("barcode"), null)))
                        .collect(Collectors.toList());
                if (!rowsForCode.isEmpty()) {
                    try {
                        log.info("[cus_barcode_sync] 按条码补档 apply rows={} code={}", rowsForCode.size(), code);
                        cusBarcodeSyncMatnrApplyService.applyFromViewRows(rowsForCode, orderItemByCode, loginUserId);
                    } catch (Exception ex) {
                        applyEx = ex;
                        log.warn("[cus_barcode_sync] 按视图补全物料失败 code={}", code, ex);
                    }
                    m = findLocalMatnrForOrderCode(code);
            if (viewHit && !one.isEmpty()) {
                try {
                    log.info("[cus_barcode_sync] 按条码补档 apply rows={} code={}", one.size(), code);
                    cusBarcodeSyncMatnrApplyService.applyFromViewRows(one, orderItemByCode, loginUserId);
                } catch (Exception ex) {
                    applyEx = ex;
                    log.warn("[cus_barcode_sync] 按视图补全物料失败 code={}", code, ex);
                }
                m = findLocalMatnrForOrderCode(code);
            }
            if (m == null) {
                ManMatnrFailReason fr = resolveManMatnrFailReason(viewItems, viewHit, applyEx);
                ManMatnrFailReason fr = resolveManMatnrFailReason(viewByCode, viewHit, applyEx);
                log.warn("[cus_barcode_sync] 无法落地 man_matnr code={} reason={} viewRowCount={} viewBarcodes=[{}]",
                        code, fr.name(), viewRowCount, summarizeViewBarcodes(viewItems));
                        code, fr.name(), viewRowCount, summarizeViewBarcodes(one));
                throw new CoolException("物料不存在:" + code);
            }
        }
@@ -194,11 +204,15 @@
        APPLY_STILL_EMPTY
    }
    private static ManMatnrFailReason resolveManMatnrFailReason(List<Map<String, Object>> viewItems, boolean viewHit, Exception applyEx) {
        if (viewItems == null) {
    private static ManMatnrFailReason resolveManMatnrFailReason(
            Map<String, List<Map<String, Object>>> viewByCode,
            boolean viewHit,
            Exception applyEx) {
        if (viewByCode == null) {
            return ManMatnrFailReason.VIEW_QUERY_ERROR;
        }
        if (viewItems.isEmpty()) {
        boolean anyHit = viewByCode.values().stream().anyMatch(list -> list != null && !list.isEmpty());
        if (!anyHit) {
            return ManMatnrFailReason.VIEW_ZERO_ROWS;
        }
        if (!viewHit) {
@@ -230,6 +244,18 @@
        return s.length() > 1200 ? s.substring(0, 1200) + "..." : s;
    }
    /** 仅汇总本次查询有命中的单据物料号 */
    private static String summarizeBarcodesWithHits(Map<String, List<Map<String, Object>>> viewByCode) {
        if (viewByCode == null || viewByCode.isEmpty()) {
            return "";
        }
        String s = viewByCode.entrySet().stream()
                .filter(e -> e.getValue() != null && !e.getValue().isEmpty())
                .map(Map.Entry::getKey)
                .collect(Collectors.joining(","));
        return s.length() > 1200 ? s.substring(0, 1200) + "..." : s;
    }
    private Matnr findLocalMatnrForOrderCode(String orderMatnr) {
        String t = StringUtils.trimToNull(orderMatnr);
        if (t == null) {
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/CusBarcodeSyncViewQueryService.java
@@ -87,6 +87,30 @@
        return toViewMaps(page.getRecords());
    }
    /** 单条条码一次查询,最多一行(同码多行取其一) */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<Map<String, Object>> listMapsForBarcode(String barcode) {
        String code = StringUtils.trimToNull(barcode);
        if (code == null) {
            return Collections.emptyList();
        }
        if (cusItemSyncDataSourceProvider.getIfAvailable() == null) {
            log.warn("dj-cloud-wms 数据源未配置,跳过 cus_barcode_sync_view");
            return Collections.emptyList();
        }
        List<CusBarcodeSyncView> part = cusBarcodeSyncViewMapper.selectList(
                Wrappers.<CusBarcodeSyncView>lambdaQuery()
                        .eq(CusBarcodeSyncView::getBarcode, code)
                        .select(
                                CusBarcodeSyncView::getBarcode,
                                CusBarcodeSyncView::getItemName,
                                CusBarcodeSyncView::getItemSpec,
                                CusBarcodeSyncView::getUnitNo)
                        .last("LIMIT 1"));
        return toViewMaps(part == null ? Collections.emptyList() : part);
    }
    /** 按条码逐条查询后合并(每条码独立 SQL,非 IN/OR) */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<Map<String, Object>> listByItemNos(Collection<String> itemNos) {
        if (itemNos == null || itemNos.isEmpty()) {
@@ -100,26 +124,11 @@
        if (codes.isEmpty()) {
            return Collections.emptyList();
        }
        if (cusItemSyncDataSourceProvider.getIfAvailable() == null) {
            log.warn("dj-cloud-wms 数据源未配置,跳过 cus_barcode_sync_view");
            return Collections.emptyList();
        }
        List<CusBarcodeSyncView> rows = new ArrayList<>();
        List<Map<String, Object>> merged = new ArrayList<>(codes.size());
        for (String code : codes) {
            List<CusBarcodeSyncView> part = cusBarcodeSyncViewMapper.selectList(
                    Wrappers.<CusBarcodeSyncView>lambdaQuery()
                            .eq(CusBarcodeSyncView::getBarcode, code)
                            .select(
                                    CusBarcodeSyncView::getBarcode,
                                    CusBarcodeSyncView::getItemName,
                                    CusBarcodeSyncView::getItemSpec,
                                    CusBarcodeSyncView::getUnitNo)
                            .last("LIMIT 1"));
            if (part != null && !part.isEmpty()) {
                rows.addAll(part);
            }
            merged.addAll(listMapsForBarcode(code));
        }
        return toViewMaps(rows);
        return merged;
    }
    // 原单次 OR 拼接(避免 IN/OR 单条时可改回)