增加导出功能
This commit is contained in:
@@ -2,7 +2,9 @@ package com.bms.price.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import com.bms.price.domain.PrcOrderBill;
|
||||
import com.bms.price.domain.PrcOrderBillExportTask;
|
||||
import com.bms.price.domain.BatchAddIncomeBillFeeTask;
|
||||
import com.bms.price.domain.ChargeWeightImportTask;
|
||||
import com.bms.price.domain.vo.AddIncomeBillFeeRequest;
|
||||
@@ -157,4 +159,18 @@ public interface IPrcOrderBillService
|
||||
|
||||
/** Data-scoped count for local rebill. */
|
||||
int countBillIdsForLocalRebill(PrcOrderBill query);
|
||||
|
||||
/**
|
||||
* Submit async Excel export for order list or billing list.
|
||||
* Requires at least one meaningful filter; returns taskId for poll/download.
|
||||
*
|
||||
* @param exportType {@link PrcOrderBillExportTask#TYPE_ORDER} or {@link PrcOrderBillExportTask#TYPE_BILLING}
|
||||
*/
|
||||
String submitOrderBillExport(String exportType, PrcOrderBill query);
|
||||
|
||||
/** Poll Redis progress for order/billing list export task. */
|
||||
PrcOrderBillExportTask getOrderBillExportTask(String taskId);
|
||||
|
||||
/** Stream SUCCESS export file to response by taskId. */
|
||||
void downloadOrderBillExport(String taskId, HttpServletResponse response) throws Exception;
|
||||
}
|
||||
|
||||
+94
@@ -2,6 +2,9 @@ package com.bms.price.service.impl;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Arrays;
|
||||
@@ -12,10 +15,13 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
@@ -27,11 +33,13 @@ import com.bms.ar.enums.ArOrderBillStatus;
|
||||
import com.bms.common.annotation.DataScope;
|
||||
import com.bms.common.core.domain.entity.SysUser;
|
||||
import com.bms.common.exception.ServiceException;
|
||||
import com.bms.common.config.BmsConfig;
|
||||
import com.bms.common.utils.DateUtils;
|
||||
import com.bms.common.utils.DictUtils;
|
||||
import com.bms.common.utils.MessageUtils;
|
||||
import com.bms.common.utils.SecurityUtils;
|
||||
import com.bms.common.utils.StringUtils;
|
||||
import com.bms.common.utils.file.FileUtils;
|
||||
import com.bms.common.utils.sign.Md5Utils;
|
||||
import com.bms.common.utils.uuid.IdUtils;
|
||||
import com.bms.customer.customerinfo.domain.BmsCustomer;
|
||||
@@ -41,6 +49,7 @@ import com.bms.system.service.IBmsBizRuleService;
|
||||
import com.bms.price.domain.PrcIncomeBill;
|
||||
import com.bms.price.domain.PrcIncomeBillFee;
|
||||
import com.bms.price.domain.PrcOrderBill;
|
||||
import com.bms.price.domain.PrcOrderBillExportTask;
|
||||
import com.bms.price.domain.PrcOrderBillExt;
|
||||
import com.bms.price.domain.PrcPayBill;
|
||||
import com.bms.price.domain.PrcPayBillFee;
|
||||
@@ -58,8 +67,10 @@ import com.bms.price.domain.vo.UpdateIncomeBillFeeRequest;
|
||||
import com.bms.price.task.PrcBatchAddIncomeFeeAsyncRunner;
|
||||
import com.bms.price.task.PrcChargeWeightImportAsyncRunner;
|
||||
import com.bms.price.task.PrcChargeWeightImportAsyncRunner.ChargeWeightImportWorkItem;
|
||||
import com.bms.price.task.PrcOrderBillExportAsyncRunner;
|
||||
import com.bms.price.task.PrcOrderBillLocalRebillAsyncRunner;
|
||||
import com.bms.price.task.PrcRecalcBillPriceAsyncRunner;
|
||||
import com.bms.price.service.support.OrderBillExportSupport;
|
||||
import com.bms.price.domain.vo.TmsPriceBillRequest;
|
||||
import com.bms.price.domain.vo.TmsOrderBillStatusResult;
|
||||
import com.bms.price.domain.vo.TmsPriceQuoteFeeLine;
|
||||
@@ -152,6 +163,9 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
@Autowired
|
||||
private PrcOrderBillLocalRebillAsyncRunner localRebillAsyncRunner;
|
||||
|
||||
@Autowired
|
||||
private PrcOrderBillExportAsyncRunner orderBillExportAsyncRunner;
|
||||
|
||||
@Autowired
|
||||
private IBmsBizRuleService bizRuleService;
|
||||
|
||||
@@ -161,6 +175,8 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
private static final int RECALC_PRICE_MAX = 5000;
|
||||
/** Soft max for one local-rebill job (id-only load + paged parallel). */
|
||||
private static final int LOCAL_REBILL_MAX = 100000;
|
||||
/** Soft max for one order/billing list Excel export. */
|
||||
private static final int ORDER_BILL_EXPORT_MAX = 50000;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@@ -843,6 +859,84 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
return localRebillAsyncRunner.get(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String submitOrderBillExport(String exportType, PrcOrderBill query)
|
||||
{
|
||||
String type = StringUtils.nvl(exportType, "").trim().toUpperCase();
|
||||
if (!PrcOrderBillExportTask.TYPE_ORDER.equals(type)
|
||||
&& !PrcOrderBillExportTask.TYPE_BILLING.equals(type))
|
||||
{
|
||||
type = PrcOrderBillExportTask.TYPE_ORDER;
|
||||
}
|
||||
PrcOrderBill q = query == null ? new PrcOrderBill() : query;
|
||||
if (!OrderBillExportSupport.hasExportFilter(q))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.export.filterRequired"));
|
||||
}
|
||||
int total = self.countBillIdsForLocalRebill(q);
|
||||
if (total <= 0)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.export.noMatch"));
|
||||
}
|
||||
if (total > ORDER_BILL_EXPORT_MAX)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.export.tooMany",
|
||||
Integer.valueOf(ORDER_BILL_EXPORT_MAX)));
|
||||
}
|
||||
String prefix = PrcOrderBillExportTask.TYPE_BILLING.equals(type)
|
||||
? "\u8ba1\u8d39\u5217\u8868"
|
||||
: "\u8ba2\u5355\u5217\u8868";
|
||||
String fileName = prefix + "_" + DateUtils.dateTimeNow() + ".xlsx";
|
||||
String taskId = IdUtils.fastSimpleUUID();
|
||||
orderBillExportAsyncRunner.put(taskId, PrcOrderBillExportTask.STATUS_PENDING, 0, "queued", null,
|
||||
type, fileName, null, 0);
|
||||
// Pass request Authentication into async thread for @DataScope on selectBillList.
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
orderBillExportAsyncRunner.run(taskId, type, q, fileName, authentication);
|
||||
return taskId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrcOrderBillExportTask getOrderBillExportTask(String taskId)
|
||||
{
|
||||
if (StringUtils.isEmpty(taskId) || orderBillExportAsyncRunner == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return orderBillExportAsyncRunner.get(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downloadOrderBillExport(String taskId, HttpServletResponse response) throws Exception
|
||||
{
|
||||
PrcOrderBillExportTask task = getOrderBillExportTask(taskId);
|
||||
if (task == null)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.export.taskNotExists"));
|
||||
}
|
||||
if (!PrcOrderBillExportTask.STATUS_SUCCESS.equals(task.getStatus())
|
||||
|| StringUtils.isEmpty(task.getStorageKey()))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.export.notReady"));
|
||||
}
|
||||
if (!FileUtils.checkAllowDownload(task.getStorageKey()))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.export.fileMissing"));
|
||||
}
|
||||
Path downloadRoot = Paths.get(BmsConfig.getDownloadPath()).toAbsolutePath().normalize();
|
||||
Path filePath = downloadRoot.resolve(task.getStorageKey()).normalize();
|
||||
if (!filePath.startsWith(downloadRoot) || !Files.isRegularFile(filePath))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.export.fileMissing"));
|
||||
}
|
||||
String fileName = StringUtils.isNotEmpty(task.getFileName())
|
||||
? task.getFileName()
|
||||
: (taskId + ".xlsx");
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
FileUtils.setAttachmentResponseHeader(response, fileName);
|
||||
FileUtils.writeBytes(filePath.toString(), response.getOutputStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataScope(deptAlias = "su", deptField = "dept_id", userAlias = "su", userField = "user_id", permission = "price:billing:bill")
|
||||
public List<String> selectBillIdsForLocalRebill(PrcOrderBill query)
|
||||
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
package com.bms.price.service.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import com.bms.common.utils.StringUtils;
|
||||
import com.bms.common.utils.poi.ExcelUtil;
|
||||
import com.bms.price.domain.PrcOrderBill;
|
||||
import com.bms.price.domain.vo.PrcBillingBillListExportRow;
|
||||
import com.bms.price.domain.vo.PrcOrderBillListExportRow;
|
||||
|
||||
/** Map PrcOrderBill rows to Excel export VOs and write response. */
|
||||
public final class OrderBillExportSupport
|
||||
{
|
||||
private OrderBillExportSupport()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* True when query has at least one meaningful filter.
|
||||
* Default orderStatuses alone does not count.
|
||||
*/
|
||||
public static boolean hasExportFilter(PrcOrderBill query)
|
||||
{
|
||||
if (query == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (hasTexts(query.getOrderIdentifiers()) || hasTexts(query.getOrderNos())
|
||||
|| hasTexts(query.getTrackingNos()) || hasTexts(query.getTransferNos())
|
||||
|| hasTexts(query.getCustomerCodes()) || hasTexts(query.getProductCodes())
|
||||
|| hasTexts(query.getBillIds()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.isNotEmpty(query.getCreditArrearsStatus())
|
||||
|| StringUtils.isNotEmpty(query.getCountryCode())
|
||||
|| StringUtils.isNotEmpty(query.getCustomerCode())
|
||||
|| StringUtils.isNotEmpty(query.getOrderNo())
|
||||
|| StringUtils.isNotEmpty(query.getTrackingNo())
|
||||
|| StringUtils.isNotEmpty(query.getTransferNo())
|
||||
|| StringUtils.isNotEmpty(query.getProductCode()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (query.getBillingFailStatuses() != null && !query.getBillingFailStatuses().isEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (query.getBillingFailStatus() != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
Map<String, Object> params = query.getParams();
|
||||
if (params != null)
|
||||
{
|
||||
if (notBlank(params.get("beginBizDate")) || notBlank(params.get("endBizDate"))
|
||||
|| notBlank(params.get("beginPickupDate")) || notBlank(params.get("endPickupDate")))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hasTexts(List<?> list)
|
||||
{
|
||||
if (list == null || list.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (Object item : list)
|
||||
{
|
||||
if (item != null && StringUtils.isNotEmpty(String.valueOf(item).trim()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean notBlank(Object v)
|
||||
{
|
||||
return v != null && StringUtils.isNotEmpty(String.valueOf(v).trim());
|
||||
}
|
||||
|
||||
/** Export order-list Excel by current query result. */
|
||||
public static void exportOrderList(HttpServletResponse response, List<PrcOrderBill> list)
|
||||
{
|
||||
ExcelUtil.export(response, toOrderListRows(list), PrcOrderBillListExportRow.class, "\u8ba2\u5355\u5217\u8868");
|
||||
}
|
||||
|
||||
/** Export billing-list Excel by current query result. */
|
||||
public static void exportBillingList(HttpServletResponse response, List<PrcOrderBill> list)
|
||||
{
|
||||
ExcelUtil.export(response, toBillingListRows(list), PrcBillingBillListExportRow.class, "\u8ba1\u8d39\u5217\u8868");
|
||||
}
|
||||
|
||||
public static List<PrcOrderBillListExportRow> toOrderListRows(List<PrcOrderBill> list)
|
||||
{
|
||||
List<PrcOrderBillListExportRow> rows = new ArrayList<PrcOrderBillListExportRow>();
|
||||
if (list == null)
|
||||
{
|
||||
return rows;
|
||||
}
|
||||
for (PrcOrderBill bill : list)
|
||||
{
|
||||
if (bill == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
PrcOrderBillListExportRow row = new PrcOrderBillListExportRow();
|
||||
row.setOrderNo(bill.getOrderNo());
|
||||
row.setTrackingNo(bill.getTrackingNo());
|
||||
row.setTransferNo(bill.getTransferNo());
|
||||
row.setCustomerName(bill.getCustomerName());
|
||||
row.setCustomerCode(bill.getCustomerCode());
|
||||
row.setProductCode(bill.getProductCode());
|
||||
row.setProductName(bill.getProductName());
|
||||
row.setCountryCode(bill.getCountryCode());
|
||||
row.setCountryName(bill.getCountryName());
|
||||
row.setPieces(bill.getPieces());
|
||||
row.setWeight(bill.getWeight());
|
||||
row.setVolumeWeight(bill.getVolumeWeight());
|
||||
row.setReceiveWeight(bill.getReceiveWeight());
|
||||
row.setDestPostcode(bill.getDestPostcode());
|
||||
row.setOrderStatusLabel(orderStatusLabel(bill.getOrderStatus()));
|
||||
row.setBillingFailStatusLabel(billingFailStatusLabel(bill.getBillingFailStatus()));
|
||||
row.setBizDate(bill.getBizDate());
|
||||
row.setOrderTime(bill.getOrderTime());
|
||||
row.setPickupDate(bill.getPickupDate());
|
||||
row.setBelongSaler(bill.getBelongSaler());
|
||||
row.setSettlementMan(bill.getSettlementMan());
|
||||
row.setServiceMan(bill.getServiceMan());
|
||||
rows.add(row);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
public static List<PrcBillingBillListExportRow> toBillingListRows(List<PrcOrderBill> list)
|
||||
{
|
||||
List<PrcBillingBillListExportRow> rows = new ArrayList<PrcBillingBillListExportRow>();
|
||||
if (list == null)
|
||||
{
|
||||
return rows;
|
||||
}
|
||||
for (PrcOrderBill bill : list)
|
||||
{
|
||||
if (bill == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
PrcBillingBillListExportRow row = new PrcBillingBillListExportRow();
|
||||
row.setOrderNo(bill.getOrderNo());
|
||||
row.setTrackingNo(bill.getTrackingNo());
|
||||
row.setTransferNo(bill.getTransferNo());
|
||||
row.setCustomerName(bill.getCustomerName());
|
||||
row.setCustomerCode(bill.getCustomerCode());
|
||||
row.setProductCode(bill.getProductCode());
|
||||
row.setProductName(bill.getProductName());
|
||||
row.setCountryCode(bill.getCountryCode());
|
||||
row.setCountryName(bill.getCountryName());
|
||||
row.setPieces(bill.getPieces());
|
||||
row.setChargeWeight(bill.getChargeWeight());
|
||||
row.setWeight(bill.getWeight());
|
||||
row.setReceiveWeight(bill.getReceiveWeight());
|
||||
row.setIncomeTotal(bill.getIncomeTotal());
|
||||
row.setPayTotal(bill.getPayTotal());
|
||||
row.setMatchSourceLabel(matchSourceLabel(bill.getMatchSource()));
|
||||
row.setBillingFailStatusLabel(billingFailStatusLabel(bill.getBillingFailStatus()));
|
||||
row.setCustomerActiveStatusLabel(customerActiveLabel(bill.getCustomerActiveStatus()));
|
||||
row.setCreditArrearsStatusLabel(creditArrearsLabel(bill.getCreditArrearsStatus()));
|
||||
row.setBizDate(bill.getBizDate());
|
||||
row.setOrderTime(bill.getOrderTime());
|
||||
row.setBelongSaler(bill.getBelongSaler());
|
||||
row.setSettlementMan(bill.getSettlementMan());
|
||||
row.setServiceMan(bill.getServiceMan());
|
||||
rows.add(row);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
public static String orderStatusLabel(Integer status)
|
||||
{
|
||||
if (status == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
switch (status.intValue())
|
||||
{
|
||||
case 0: return "草稿订单";
|
||||
case 1: return "确认订单";
|
||||
case 2: return "已中转";
|
||||
case 3: return "已收货";
|
||||
case 4: return "已装箱";
|
||||
case 5: return "已出库";
|
||||
case 6: return "转运中";
|
||||
case 7: return "已上网";
|
||||
case 8: return "已签收";
|
||||
case 9: return "已退件";
|
||||
case 10: return "已取消";
|
||||
case 11: return "已复核";
|
||||
default: return String.valueOf(status);
|
||||
}
|
||||
}
|
||||
|
||||
public static String billingFailStatusLabel(Integer status)
|
||||
{
|
||||
if (status == null)
|
||||
{
|
||||
return "计费成功";
|
||||
}
|
||||
switch (status.intValue())
|
||||
{
|
||||
case 0: return "计费成功";
|
||||
case 1: return "未匹配产品";
|
||||
case 2: return "未匹配国家";
|
||||
case 3: return "未匹配重量段";
|
||||
case 4: return "未绑定套餐";
|
||||
case 5: return "无生效套餐版本";
|
||||
case 6: return "已生成应收账单";
|
||||
case 7: return "产品档案缺失";
|
||||
case 8: return "未命中价格";
|
||||
case 9: return "分区无价格";
|
||||
case 10: return "邮编必填";
|
||||
case 11: return "邮编未匹配分区";
|
||||
case 12: return "上游订单不存在";
|
||||
case 13: return "上游订单号为空";
|
||||
case 14: return "上游客户为空";
|
||||
case 15: return "上游产品为空";
|
||||
case 16: return "上游重量无效";
|
||||
case 17: return "计费时间为空";
|
||||
case 18: return "退费订单无法解析";
|
||||
case 19: return "客户代码为空";
|
||||
case 20: return "客户已停用";
|
||||
case 21: return "运费为空";
|
||||
case 22: return "未知失败";
|
||||
default: return String.valueOf(status);
|
||||
}
|
||||
}
|
||||
|
||||
public static String matchSourceLabel(String source)
|
||||
{
|
||||
if (StringUtils.isEmpty(source))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
if ("PACKAGE_FIXED".equals(source) || "FIXED".equals(source))
|
||||
{
|
||||
return "客户固定价套餐";
|
||||
}
|
||||
if ("PACKAGE_DISCOUNT".equals(source) || "DISCOUNT".equals(source))
|
||||
{
|
||||
return "客户折扣套餐";
|
||||
}
|
||||
if ("PRODUCT_DEFAULT".equals(source))
|
||||
{
|
||||
return "产品默认价";
|
||||
}
|
||||
if ("BILLING_FAIL".equals(source))
|
||||
{
|
||||
return "计费失败";
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
public static String customerActiveLabel(String status)
|
||||
{
|
||||
if ("ACTIVE".equals(status))
|
||||
{
|
||||
return "正常";
|
||||
}
|
||||
if ("MISSING".equals(status))
|
||||
{
|
||||
return "不存在";
|
||||
}
|
||||
if ("DISABLED".equals(status))
|
||||
{
|
||||
return "停用";
|
||||
}
|
||||
return status == null ? "" : status;
|
||||
}
|
||||
|
||||
public static String creditArrearsLabel(String status)
|
||||
{
|
||||
if ("NORMAL".equals(status))
|
||||
{
|
||||
return "正常";
|
||||
}
|
||||
if ("ARREARS".equals(status))
|
||||
{
|
||||
return "欠费";
|
||||
}
|
||||
return status == null ? "" : status;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user