|
|
@@ -0,0 +1,423 @@
|
|
|
+package com.fs.erp.service.jst;
|
|
|
+
|
|
|
+import com.fs.common.utils.StringUtils;
|
|
|
+import com.fs.live.domain.LiveOrder;
|
|
|
+import com.fs.live.service.ILiveOrderService;
|
|
|
+import com.fs.store.domain.FsStoreOrder;
|
|
|
+import com.fs.store.service.IFsStoreOrderService;
|
|
|
+import org.apache.poi.ss.usermodel.Cell;
|
|
|
+import org.apache.poi.ss.usermodel.DataFormatter;
|
|
|
+import org.apache.poi.ss.usermodel.Row;
|
|
|
+import org.apache.poi.ss.usermodel.Sheet;
|
|
|
+import org.apache.poi.ss.usermodel.Workbook;
|
|
|
+import org.apache.poi.ss.usermodel.WorkbookFactory;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
+
|
|
|
+import java.io.InputStream;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.nio.file.Path;
|
|
|
+import java.nio.file.Paths;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
+import java.util.LinkedHashSet;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 从 Excel 读取平台订单号,按商城/直播分别走 deliveryOp 同步逻辑回传发货状态
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class JstExcelDeliveryBatchService {
|
|
|
+
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(JstExcelDeliveryBatchService.class);
|
|
|
+
|
|
|
+ public static final String PLATFORM_ORDER_HEADER = "平台订单号";
|
|
|
+ public static final String DEFAULT_RESULT_RELATIVE_PATH = "myfile/发货结果.txt";
|
|
|
+ private static final int DEFAULT_PLATFORM_ORDER_COLUMN = 3;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IFsStoreOrderService storeOrderService;
|
|
|
+ @Autowired
|
|
|
+ private ILiveOrderService liveOrderService;
|
|
|
+ @Autowired
|
|
|
+ private JstStoreDeliverySyncService jstStoreDeliverySyncService;
|
|
|
+ @Autowired
|
|
|
+ private JstLiveDeliverySyncService jstLiveDeliverySyncService;
|
|
|
+
|
|
|
+ public Map<String, Object> syncFromExcelPath(String filePath, String shopCode) throws Exception {
|
|
|
+ return syncFromExcelPath(filePath, shopCode, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ public Map<String, Object> syncFromExcelPath(String filePath, String shopCode, String resultFilePath)
|
|
|
+ throws Exception {
|
|
|
+ Path path = Paths.get(filePath);
|
|
|
+ if (!Files.exists(path)) {
|
|
|
+ throw new IllegalArgumentException("Excel 文件不存在: " + filePath);
|
|
|
+ }
|
|
|
+ try (InputStream in = Files.newInputStream(path)) {
|
|
|
+ return syncFromExcel(in, shopCode, filePath, resultFilePath);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Map<String, Object> syncFromExcel(InputStream inputStream, String shopCode, String sourceName)
|
|
|
+ throws Exception {
|
|
|
+ return syncFromExcel(inputStream, shopCode, sourceName, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ public Map<String, Object> syncFromExcel(InputStream inputStream, String shopCode, String sourceName,
|
|
|
+ String resultFilePath) throws Exception {
|
|
|
+ List<String> platformOrderNos = readPlatformOrderNos(inputStream);
|
|
|
+ return syncPlatformOrderNos(platformOrderNos, shopCode, sourceName, resultFilePath);
|
|
|
+ }
|
|
|
+
|
|
|
+ public Map<String, Object> syncPlatformOrderNos(List<String> platformOrderNos, String shopCode, String sourceName)
|
|
|
+ throws Exception {
|
|
|
+ return syncPlatformOrderNos(platformOrderNos, shopCode, sourceName, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ public Map<String, Object> syncPlatformOrderNos(List<String> platformOrderNos, String shopCode, String sourceName,
|
|
|
+ String resultFilePath) throws Exception {
|
|
|
+ Map<String, Object> result = new LinkedHashMap<>();
|
|
|
+ result.put("source", sourceName);
|
|
|
+ result.put("shopCode", shopCode);
|
|
|
+ result.put("totalRead", platformOrderNos.size());
|
|
|
+
|
|
|
+ Map<String, String> platformOrderNoMap = new HashMap<>();
|
|
|
+ List<FsStoreOrder> storeOrders = new ArrayList<>();
|
|
|
+ List<LiveOrder> liveOrders = new ArrayList<>();
|
|
|
+ List<JstDeliverySyncReportItem> allReports = new ArrayList<>();
|
|
|
+
|
|
|
+ for (String platformOrderNo : platformOrderNos) {
|
|
|
+ OrderMatch match = resolveOrder(platformOrderNo);
|
|
|
+ if (match.storeOrder != null) {
|
|
|
+ storeOrders.add(match.storeOrder);
|
|
|
+ bindPlatformOrderNo(platformOrderNoMap, platformOrderNo, match.storeOrder.getOrderCode(),
|
|
|
+ match.storeOrder.getExtendOrderId());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (match.liveOrder != null) {
|
|
|
+ liveOrders.add(match.liveOrder);
|
|
|
+ bindPlatformOrderNo(platformOrderNoMap, platformOrderNo, match.liveOrder.getOrderCode(),
|
|
|
+ match.liveOrder.getExtendOrderId());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ allReports.add(new JstDeliverySyncReportItem()
|
|
|
+ .setPlatformOrderNo(platformOrderNo)
|
|
|
+ .setResult(JstDeliverySyncReportItem.RESULT_NOT_FOUND)
|
|
|
+ .setReason(match.reason));
|
|
|
+ }
|
|
|
+
|
|
|
+ for (FsStoreOrder order : new ArrayList<>(storeOrders)) {
|
|
|
+ if (StringUtils.isEmpty(order.getExtendOrderId())) {
|
|
|
+ allReports.add(new JstDeliverySyncReportItem()
|
|
|
+ .setPlatformOrderNo(resolvePlatformKey(platformOrderNoMap, order))
|
|
|
+ .setOrderCode(order.getOrderCode())
|
|
|
+ .setOrderType("STORE")
|
|
|
+ .setResult(JstDeliverySyncReportItem.RESULT_SKIPPED)
|
|
|
+ .setReason("extend_order_id 为空,无法查聚水潭 o_id"));
|
|
|
+ storeOrders.remove(order);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (LiveOrder order : new ArrayList<>(liveOrders)) {
|
|
|
+ if (StringUtils.isEmpty(order.getExtendOrderId())) {
|
|
|
+ allReports.add(new JstDeliverySyncReportItem()
|
|
|
+ .setPlatformOrderNo(resolvePlatformKey(platformOrderNoMap, order))
|
|
|
+ .setOrderCode(order.getOrderCode())
|
|
|
+ .setOrderType("LIVE")
|
|
|
+ .setResult(JstDeliverySyncReportItem.RESULT_SKIPPED)
|
|
|
+ .setReason("extend_order_id 为空,无法查聚水潭 o_id"));
|
|
|
+ liveOrders.remove(order);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!CollectionUtils.isEmpty(storeOrders)) {
|
|
|
+ log.info("Excel 批量发货回传-商城: {} 单, shopCode={}", storeOrders.size(), shopCode);
|
|
|
+ allReports.addAll(jstStoreDeliverySyncService.syncOrdersWithShopReport(storeOrders, shopCode,
|
|
|
+ platformOrderNoMap));
|
|
|
+ }
|
|
|
+ if (!CollectionUtils.isEmpty(liveOrders)) {
|
|
|
+ log.info("Excel 批量发货回传-直播: {} 单, shopCode={}", liveOrders.size(), shopCode);
|
|
|
+ allReports.addAll(jstLiveDeliverySyncService.syncOrdersWithShopReport(liveOrders, shopCode,
|
|
|
+ platformOrderNoMap));
|
|
|
+ }
|
|
|
+
|
|
|
+ List<JstDeliverySyncReportItem> successList = filterReports(allReports, JstDeliverySyncReportItem.RESULT_SUCCESS);
|
|
|
+ List<JstDeliverySyncReportItem> failedList = filterReports(allReports, JstDeliverySyncReportItem.RESULT_FAILED);
|
|
|
+ List<JstDeliverySyncReportItem> notFoundList = filterReports(allReports,
|
|
|
+ JstDeliverySyncReportItem.RESULT_NOT_FOUND);
|
|
|
+ List<JstDeliverySyncReportItem> skippedList = filterReports(allReports, JstDeliverySyncReportItem.RESULT_SKIPPED);
|
|
|
+
|
|
|
+ String resolvedResultPath = resolveResultFilePath(resultFilePath);
|
|
|
+ writeResultFile(resolvedResultPath, sourceName, shopCode, successList, failedList, notFoundList, skippedList);
|
|
|
+
|
|
|
+ result.put("resultFilePath", resolvedResultPath);
|
|
|
+ result.put("successCount", successList.size());
|
|
|
+ result.put("failedCount", failedList.size());
|
|
|
+ result.put("notFoundCount", notFoundList.size());
|
|
|
+ result.put("skippedCount", skippedList.size());
|
|
|
+ result.put("successList", successList);
|
|
|
+ result.put("failedList", failedList);
|
|
|
+ result.put("notFoundList", notFoundList);
|
|
|
+ result.put("skippedList", skippedList);
|
|
|
+ result.put("message", String.format("成功 %d,失败 %d,未找到 %d,跳过 %d;结果已写入 %s",
|
|
|
+ successList.size(), failedList.size(), notFoundList.size(), skippedList.size(), resolvedResultPath));
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String resolveResultFilePath(String resultFilePath) {
|
|
|
+ if (StringUtils.isNotEmpty(resultFilePath)) {
|
|
|
+ return resultFilePath.trim();
|
|
|
+ }
|
|
|
+ Path workspacePath = Paths.get(System.getProperty("user.dir")).resolve(DEFAULT_RESULT_RELATIVE_PATH).normalize();
|
|
|
+ Path parentPath = Paths.get(System.getProperty("user.dir")).getParent();
|
|
|
+ if (parentPath != null) {
|
|
|
+ Path projectRootPath = parentPath.resolve(DEFAULT_RESULT_RELATIVE_PATH).normalize();
|
|
|
+ Path projectRootDir = projectRootPath.getParent();
|
|
|
+ if (projectRootDir != null) {
|
|
|
+ try {
|
|
|
+ Files.createDirectories(projectRootDir);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("创建结果目录失败: {}", projectRootDir, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return projectRootPath.toString();
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ Path parent = workspacePath.getParent();
|
|
|
+ if (parent != null) {
|
|
|
+ Files.createDirectories(parent);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("创建结果目录失败: {}", workspacePath.getParent(), e);
|
|
|
+ }
|
|
|
+ return workspacePath.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void writeResultFile(String resultFilePath, String sourceName, String shopCode,
|
|
|
+ List<JstDeliverySyncReportItem> successList,
|
|
|
+ List<JstDeliverySyncReportItem> failedList,
|
|
|
+ List<JstDeliverySyncReportItem> notFoundList,
|
|
|
+ List<JstDeliverySyncReportItem> skippedList) throws Exception {
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ sb.append("聚水潭发货回传结果").append(System.lineSeparator());
|
|
|
+ sb.append("生成时间: ").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()))
|
|
|
+ .append(System.lineSeparator());
|
|
|
+ sb.append("数据来源: ").append(sourceName).append(System.lineSeparator());
|
|
|
+ sb.append("聚水潭店铺: ").append(shopCode).append(System.lineSeparator());
|
|
|
+ sb.append("汇总: 成功 ").append(successList.size())
|
|
|
+ .append(",失败 ").append(failedList.size())
|
|
|
+ .append(",未找到 ").append(notFoundList.size())
|
|
|
+ .append(",跳过 ").append(skippedList.size())
|
|
|
+ .append(System.lineSeparator());
|
|
|
+ sb.append(System.lineSeparator());
|
|
|
+
|
|
|
+ appendReportSection(sb, "回传成功", successList, true);
|
|
|
+ appendReportSection(sb, "回传失败", failedList, false);
|
|
|
+ appendReportSection(sb, "未找到订单信息", notFoundList, false);
|
|
|
+ appendReportSection(sb, "跳过处理", skippedList, false);
|
|
|
+
|
|
|
+ Path path = Paths.get(resultFilePath);
|
|
|
+ Path parent = path.getParent();
|
|
|
+ if (parent != null) {
|
|
|
+ Files.createDirectories(parent);
|
|
|
+ }
|
|
|
+ Files.write(path, sb.toString().getBytes(StandardCharsets.UTF_8));
|
|
|
+ log.info("发货回传结果已写入: {}", resultFilePath);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void appendReportSection(StringBuilder sb, String title, List<JstDeliverySyncReportItem> items,
|
|
|
+ boolean showExpress) {
|
|
|
+ sb.append("========== ").append(title).append(" (").append(items.size()).append(") ==========")
|
|
|
+ .append(System.lineSeparator());
|
|
|
+ if (CollectionUtils.isEmpty(items)) {
|
|
|
+ sb.append("无").append(System.lineSeparator());
|
|
|
+ sb.append(System.lineSeparator());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ int index = 1;
|
|
|
+ for (JstDeliverySyncReportItem item : items) {
|
|
|
+ sb.append(index++).append(". ");
|
|
|
+ sb.append("平台订单号=").append(nullToEmpty(item.getPlatformOrderNo()));
|
|
|
+ if (StringUtils.isNotEmpty(item.getOrderCode())) {
|
|
|
+ sb.append(" | 本地订单号=").append(item.getOrderCode());
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotEmpty(item.getOrderType())) {
|
|
|
+ sb.append(" | 类型=").append(item.getOrderType());
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotEmpty(item.getExtendOrderId())) {
|
|
|
+ sb.append(" | o_id=").append(item.getExtendOrderId());
|
|
|
+ }
|
|
|
+ if (showExpress && StringUtils.isNotEmpty(item.getMailNo())) {
|
|
|
+ sb.append(" | 运单号=").append(item.getMailNo());
|
|
|
+ }
|
|
|
+ if (showExpress && StringUtils.isNotEmpty(item.getExpressName())) {
|
|
|
+ sb.append(" | 快递=").append(item.getExpressName());
|
|
|
+ } else if (showExpress && StringUtils.isNotEmpty(item.getExpressCode())) {
|
|
|
+ sb.append(" | 快递编码=").append(item.getExpressCode());
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotEmpty(item.getReason())) {
|
|
|
+ sb.append(" | 说明=").append(item.getReason());
|
|
|
+ }
|
|
|
+ sb.append(System.lineSeparator());
|
|
|
+ }
|
|
|
+ sb.append(System.lineSeparator());
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<JstDeliverySyncReportItem> filterReports(List<JstDeliverySyncReportItem> allReports, String result) {
|
|
|
+ List<JstDeliverySyncReportItem> list = new ArrayList<>();
|
|
|
+ for (JstDeliverySyncReportItem item : allReports) {
|
|
|
+ if (result.equals(item.getResult())) {
|
|
|
+ list.add(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<String> readPlatformOrderNos(InputStream inputStream) throws Exception {
|
|
|
+ Set<String> orderNos = new LinkedHashSet<>();
|
|
|
+ DataFormatter formatter = new DataFormatter();
|
|
|
+ try (Workbook workbook = WorkbookFactory.create(inputStream)) {
|
|
|
+ Sheet sheet = workbook.getSheetAt(0);
|
|
|
+ if (sheet == null) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+ int platformOrderColumn = resolvePlatformOrderColumn(sheet, formatter);
|
|
|
+ int startRow = hasHeaderRow(sheet, formatter) ? 1 : 0;
|
|
|
+ for (int r = startRow; r <= sheet.getLastRowNum(); r++) {
|
|
|
+ Row row = sheet.getRow(r);
|
|
|
+ if (row == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String value = readCell(row.getCell(platformOrderColumn - 1), formatter);
|
|
|
+ if (StringUtils.isNotEmpty(value) && !PLATFORM_ORDER_HEADER.equals(value)) {
|
|
|
+ orderNos.add(value.trim());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return new ArrayList<>(orderNos);
|
|
|
+ }
|
|
|
+
|
|
|
+ private int resolvePlatformOrderColumn(Sheet sheet, DataFormatter formatter) {
|
|
|
+ Row header = sheet.getRow(0);
|
|
|
+ if (header == null) {
|
|
|
+ return DEFAULT_PLATFORM_ORDER_COLUMN;
|
|
|
+ }
|
|
|
+ for (int c = 0; c < header.getLastCellNum(); c++) {
|
|
|
+ String text = readCell(header.getCell(c), formatter);
|
|
|
+ if (PLATFORM_ORDER_HEADER.equals(text)) {
|
|
|
+ return c + 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return DEFAULT_PLATFORM_ORDER_COLUMN;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean hasHeaderRow(Sheet sheet, DataFormatter formatter) {
|
|
|
+ Row header = sheet.getRow(0);
|
|
|
+ if (header == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ for (int c = 0; c < header.getLastCellNum(); c++) {
|
|
|
+ String text = readCell(header.getCell(c), formatter);
|
|
|
+ if (PLATFORM_ORDER_HEADER.equals(text)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String readCell(Cell cell, DataFormatter formatter) {
|
|
|
+ if (cell == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String value = formatter.formatCellValue(cell);
|
|
|
+ return value == null ? null : value.trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ private OrderMatch resolveOrder(String platformOrderNo) {
|
|
|
+ OrderMatch match = new OrderMatch();
|
|
|
+ if (StringUtils.isEmpty(platformOrderNo)) {
|
|
|
+ match.reason = "平台订单号为空";
|
|
|
+ return match;
|
|
|
+ }
|
|
|
+
|
|
|
+ FsStoreOrder storeOrder = storeOrderService.selectFsStoreOrderByOrderCode(platformOrderNo);
|
|
|
+ if (storeOrder == null) {
|
|
|
+ storeOrder = storeOrderService.selectFsStoreOrderByExtendOrderId(platformOrderNo);
|
|
|
+ }
|
|
|
+ if (storeOrder == null && StringUtils.isNumeric(platformOrderNo)) {
|
|
|
+ try {
|
|
|
+ storeOrder = storeOrderService.selectFsStoreOrderById(Long.parseLong(platformOrderNo));
|
|
|
+ } catch (NumberFormatException ignored) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (storeOrder != null) {
|
|
|
+ match.storeOrder = storeOrder;
|
|
|
+ return match;
|
|
|
+ }
|
|
|
+
|
|
|
+ LiveOrder liveOrder = liveOrderService.selectLiveOrderByOrderCode(platformOrderNo);
|
|
|
+ if (liveOrder == null) {
|
|
|
+ liveOrder = liveOrderService.selectLiveOrderByExtendId(platformOrderNo);
|
|
|
+ }
|
|
|
+ if (liveOrder == null) {
|
|
|
+ liveOrder = liveOrderService.selectLiveOrderByOrderId(platformOrderNo);
|
|
|
+ }
|
|
|
+ if (liveOrder != null) {
|
|
|
+ match.liveOrder = liveOrder;
|
|
|
+ return match;
|
|
|
+ }
|
|
|
+
|
|
|
+ match.reason = "本地未找到商城/直播订单";
|
|
|
+ return match;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void bindPlatformOrderNo(Map<String, String> platformOrderNoMap, String platformOrderNo,
|
|
|
+ String orderCode, String extendOrderId) {
|
|
|
+ if (StringUtils.isNotEmpty(orderCode)) {
|
|
|
+ platformOrderNoMap.put(orderCode, platformOrderNo);
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotEmpty(extendOrderId)) {
|
|
|
+ platformOrderNoMap.put(extendOrderId, platformOrderNo);
|
|
|
+ }
|
|
|
+ platformOrderNoMap.put(platformOrderNo, platformOrderNo);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String resolvePlatformKey(Map<String, String> platformOrderNoMap, FsStoreOrder order) {
|
|
|
+ if (platformOrderNoMap.containsKey(order.getOrderCode())) {
|
|
|
+ return platformOrderNoMap.get(order.getOrderCode());
|
|
|
+ }
|
|
|
+ if (order.getExtendOrderId() != null && platformOrderNoMap.containsKey(order.getExtendOrderId())) {
|
|
|
+ return platformOrderNoMap.get(order.getExtendOrderId());
|
|
|
+ }
|
|
|
+ return order.getOrderCode();
|
|
|
+ }
|
|
|
+
|
|
|
+ private String resolvePlatformKey(Map<String, String> platformOrderNoMap, LiveOrder order) {
|
|
|
+ if (platformOrderNoMap.containsKey(order.getOrderCode())) {
|
|
|
+ return platformOrderNoMap.get(order.getOrderCode());
|
|
|
+ }
|
|
|
+ if (order.getExtendOrderId() != null && platformOrderNoMap.containsKey(order.getExtendOrderId())) {
|
|
|
+ return platformOrderNoMap.get(order.getExtendOrderId());
|
|
|
+ }
|
|
|
+ return order.getOrderCode();
|
|
|
+ }
|
|
|
+
|
|
|
+ private String nullToEmpty(String value) {
|
|
|
+ return value == null ? "" : value;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static class OrderMatch {
|
|
|
+ private FsStoreOrder storeOrder;
|
|
|
+ private LiveOrder liveOrder;
|
|
|
+ private String reason;
|
|
|
+ }
|
|
|
+}
|