应付配置文件导入保存该文件
This commit is contained in:
@@ -14,6 +14,9 @@ public class PayPreview
|
||||
{
|
||||
private String sourceFile;
|
||||
|
||||
/** 本次价卡在 OSS 上的地址,保存时写到每个产品版本 */
|
||||
private String filePath;
|
||||
|
||||
private String fileMd5;
|
||||
|
||||
private String supplierName;
|
||||
|
||||
@@ -93,6 +93,9 @@ public class PayProduct extends BaseEntity
|
||||
@Excel(name = "来源文件", width = 36)
|
||||
private String sourceFile;
|
||||
|
||||
/** 源文件在 OSS 上的地址,形如 oss://bucket/key。历史记录按它下载 */
|
||||
private String filePath;
|
||||
|
||||
private String fileMd5;
|
||||
|
||||
@Excel(name = "价卡归属", width = 12)
|
||||
|
||||
@@ -37,6 +37,9 @@ public class PayProductTerm extends BaseEntity
|
||||
|
||||
private String sourceFile;
|
||||
|
||||
/** 这一版源文件的 OSS 地址,空表示导入时还没有存文件 */
|
||||
private String filePath;
|
||||
|
||||
private Integer weightCount;
|
||||
|
||||
private Integer surchargeCount;
|
||||
|
||||
@@ -30,8 +30,12 @@ public class PaySurcharge
|
||||
/** 从收费标准里解析出的金额;百分比时这里是百分数 */
|
||||
private BigDecimal amount;
|
||||
|
||||
/** 币种代码,计费时和订单币种比对 */
|
||||
private String currency;
|
||||
|
||||
/** 货币和计费单位,与重量段单位同一写法,如 EUR/ITEM、RMB/KG、% */
|
||||
private String priceUnit;
|
||||
|
||||
/** 费用说明 */
|
||||
private String feeDesc;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ public final class PayDetailExporter
|
||||
header(weightSheet, "产品名称", "报价工作表", "区块", "国家", "国家代码", "分区", "重量段", "下限KG", "上限KG",
|
||||
"体积", "费用项", "单价", "单位");
|
||||
Sheet feeSheet = workbook.createSheet("附加费");
|
||||
header(feeSheet, "产品名称", "报价工作表", "区块", "费用名称", "分区", "收费标准", "金额", "币种", "收取时点",
|
||||
header(feeSheet, "产品名称", "报价工作表", "区块", "费用名称", "分区", "收费标准", "金额", "币种", "单位", "收取时点",
|
||||
"生效开始", "生效结束", "时效原文", "费用说明");
|
||||
Sheet extraSheet = workbook.createSheet("其他配置");
|
||||
header(extraSheet, "产品名称", "报价工作表", "类型", "配置内容");
|
||||
@@ -121,11 +121,12 @@ public final class PayDetailExporter
|
||||
cell(row, 5, fee.getChargeText());
|
||||
cell(row, 6, plain(fee.getAmount()));
|
||||
cell(row, 7, fee.getCurrency());
|
||||
cell(row, 8, fee.getChargeTiming());
|
||||
cell(row, 9, day(fee.getEffectiveStart()));
|
||||
cell(row, 10, day(fee.getEffectiveEnd()));
|
||||
cell(row, 11, fee.getPeriodText());
|
||||
cell(row, 12, fee.getFeeDesc());
|
||||
cell(row, 8, fee.getPriceUnit());
|
||||
cell(row, 9, fee.getChargeTiming());
|
||||
cell(row, 10, day(fee.getEffectiveStart()));
|
||||
cell(row, 11, day(fee.getEffectiveEnd()));
|
||||
cell(row, 12, fee.getPeriodText());
|
||||
cell(row, 13, fee.getFeeDesc());
|
||||
}
|
||||
return rowIndex;
|
||||
}
|
||||
|
||||
@@ -384,6 +384,7 @@ public class PayWorkbookParser
|
||||
copy.setChargeText(fee.getChargeText());
|
||||
copy.setAmount(fee.getAmount());
|
||||
copy.setCurrency(fee.getCurrency());
|
||||
copy.setPriceUnit(fee.getPriceUnit());
|
||||
copy.setFeeDesc(fee.getFeeDesc());
|
||||
copy.setPeriodText(fee.getPeriodText());
|
||||
copy.setEffectiveStart(fee.getEffectiveStart());
|
||||
@@ -857,9 +858,10 @@ public class PayWorkbookParser
|
||||
fee.setSectionName(cut(new StringBuilder(sheetName), 200));
|
||||
fee.setFeeName("高风险地区附加费");
|
||||
fee.setZoneName(cut(new StringBuilder(country.isEmpty() ? code : country), 200));
|
||||
fee.setChargeText(cut(new StringBuilder(amount.toPlainString() + " " + currency + (unit.contains("/kg") ? "/kg" : "")), 500));
|
||||
fee.setAmount(amount);
|
||||
fee.setCurrency(currency);
|
||||
fee.setPriceUnit(currency + (unit.toLowerCase(Locale.ROOT).contains("/kg") ? "/KG" : ""));
|
||||
fee.setChargeText(cut(new StringBuilder(amount.toPlainString() + " " + currency + (unit.contains("/kg") ? "/kg" : "")), 500));
|
||||
fee.setFeeDesc(desc);
|
||||
fee.setCalcRule(PaySurchargeRules.MANUAL);
|
||||
fee.setCalcParam(code);
|
||||
@@ -1090,6 +1092,12 @@ public class PayWorkbookParser
|
||||
pending = "";
|
||||
continue;
|
||||
}
|
||||
if (isNoteTitle(grid, row))
|
||||
{
|
||||
row = readNoteBlock(grid, row, product);
|
||||
pending = "";
|
||||
continue;
|
||||
}
|
||||
if (isLooseSurcharge(grid, row))
|
||||
{
|
||||
addLooseSurcharge(grid, row, pending, product);
|
||||
@@ -1320,10 +1328,18 @@ public class PayWorkbookParser
|
||||
for (int col = 0; col < grid.cols(); col++)
|
||||
{
|
||||
String text = grid.text(data, col);
|
||||
if ((kind[col] == 2 || kind[col] == 3) && text.isBlank())
|
||||
{
|
||||
text = grid.mergedText(data, col);
|
||||
}
|
||||
if (text.isBlank())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (kind[col] == 0 && parent[col].contains("尺寸"))
|
||||
{
|
||||
keepLimit(product, parent[col], text);
|
||||
}
|
||||
if (kind[col] == 1 || (weight.isEmpty() && PayTexts.looksLikeWeight(text)))
|
||||
{
|
||||
if (weight.isEmpty() || kind[col] == 1)
|
||||
@@ -1364,7 +1380,8 @@ public class PayWorkbookParser
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (col > 0 && parent[col].equals(parent[col - 1]))
|
||||
if (col > 0 && parent[col].equals(parent[col - 1])
|
||||
&& zoneOf(sub[col], parent[col]).equals(zoneOf(sub[col - 1], parent[col - 1])))
|
||||
{
|
||||
BigDecimal previous = priceOf(grid, data, col - 1);
|
||||
if (previous != null && previous.compareTo(price) == 0)
|
||||
@@ -1384,7 +1401,7 @@ public class PayWorkbookParser
|
||||
band.setWeightMax(bounds[1]);
|
||||
if (feeHead)
|
||||
{
|
||||
band.setChargeName(shortCharge(parent[col]));
|
||||
band.setChargeName(chargeTitle(parent[col]));
|
||||
band.setZoneName(zoneOf(sub[col], parent[col]));
|
||||
}
|
||||
else
|
||||
@@ -1793,6 +1810,7 @@ public class PayWorkbookParser
|
||||
{
|
||||
fee.setAmount(null);
|
||||
fee.setCurrency("");
|
||||
fee.setPriceUnit("");
|
||||
return;
|
||||
}
|
||||
Matcher matcher = Pattern.compile("(\\d+(?:\\.\\d+)?)\\s*欧元").matcher(sentence);
|
||||
@@ -1805,12 +1823,15 @@ public class PayWorkbookParser
|
||||
}
|
||||
if (hits == 1)
|
||||
{
|
||||
fee.setAmount(new BigDecimal(amount));
|
||||
BigDecimal price = new BigDecimal(amount);
|
||||
fee.setAmount(price);
|
||||
fee.setCurrency("EUR");
|
||||
fee.setPriceUnit(surchargeUnit(new PayTexts.Money(price, "EUR", ""), sentence));
|
||||
return;
|
||||
}
|
||||
fee.setAmount(null);
|
||||
fee.setCurrency("");
|
||||
fee.setPriceUnit("");
|
||||
}
|
||||
|
||||
private static void markManual(PayProduct product)
|
||||
@@ -2039,6 +2060,7 @@ public class PayWorkbookParser
|
||||
fee.setChargeText(String.join("、", factors.keySet()));
|
||||
fee.setAmount(null);
|
||||
fee.setCurrency("");
|
||||
fee.setPriceUnit("");
|
||||
markManual(product);
|
||||
}
|
||||
|
||||
@@ -2369,6 +2391,10 @@ public class PayWorkbookParser
|
||||
fee.setChargeText(priceText.trim());
|
||||
fee.setAmount(BigDecimal.ZERO);
|
||||
fee.setCurrency(fee.getCurrency() == null || fee.getCurrency().isBlank() ? "EUR" : fee.getCurrency());
|
||||
if (fee.getPriceUnit() == null || fee.getPriceUnit().isBlank())
|
||||
{
|
||||
fee.setPriceUnit(fee.getCurrency());
|
||||
}
|
||||
}
|
||||
row++;
|
||||
}
|
||||
@@ -2838,6 +2864,10 @@ public class PayWorkbookParser
|
||||
{
|
||||
remarkCol = col;
|
||||
}
|
||||
else if (text.contains("收取") || text.contains("时点"))
|
||||
{
|
||||
remarkCol = remarkCol < 0 ? col : remarkCol;
|
||||
}
|
||||
else if (nameCol < 0 && isFeeNameHead(text))
|
||||
{
|
||||
nameCol = col;
|
||||
@@ -3125,6 +3155,7 @@ public class PayWorkbookParser
|
||||
fee.setChargeText(cut(new StringBuilder(blankTo(standard, money.amount == null ? "" : money.amount.toPlainString())), 500));
|
||||
fee.setAmount(money.amount);
|
||||
fee.setCurrency(money.currency);
|
||||
fee.setPriceUnit(cut(new StringBuilder(surchargeUnit(money, blankTo(standard, combined))), 40));
|
||||
fee.setFeeDesc(cut(new StringBuilder(joinDesc(desc, remark)), 2000));
|
||||
fee.setPeriodText(period.text == null ? "" : cut(new StringBuilder(period.text), 500));
|
||||
fee.setEffectiveStart(PayTexts.toDate(period.start));
|
||||
@@ -3134,6 +3165,7 @@ public class PayWorkbookParser
|
||||
{
|
||||
fee.setAmount(null);
|
||||
fee.setCurrency("");
|
||||
fee.setPriceUnit("");
|
||||
}
|
||||
fee.setSortNo(product.getSurcharges().size() + 1);
|
||||
PaySurchargeRules.apply(fee);
|
||||
@@ -3588,6 +3620,76 @@ public class PayWorkbookParser
|
||||
return next < grid.rows() && rowHasWeight(grid, next) && countNumbers(grid, next) >= 2;
|
||||
}
|
||||
|
||||
/** 一、计费说明这种标题。后面的句子是配置,不是费用行。 */
|
||||
private static boolean isNoteTitle(ExcelGrid grid, int row)
|
||||
{
|
||||
String line = joinRow(grid, row).trim();
|
||||
if (line.isEmpty() || line.length() > 24 || countText(grid, row) > 2 || line.contains("。"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return line.matches("^[一二三四五六七八九十]+、.+");
|
||||
}
|
||||
|
||||
private int readNoteBlock(ExcelGrid grid, int row, PayProduct product)
|
||||
{
|
||||
String title = joinRow(grid, row).trim();
|
||||
StringBuilder body = new StringBuilder();
|
||||
row++;
|
||||
while (row < grid.rows() && !grid.blankRow(row) && !isHardHeader(grid, row) && !isNoteTitle(grid, row)
|
||||
&& !isSurchargeHeader(grid, row))
|
||||
{
|
||||
String line = joinRow(grid, row).replace('\n', ' ').trim();
|
||||
if (!line.isEmpty())
|
||||
{
|
||||
if (body.length() > 0)
|
||||
{
|
||||
body.append(' ');
|
||||
}
|
||||
body.append(line);
|
||||
}
|
||||
row++;
|
||||
}
|
||||
if (body.length() > 0)
|
||||
{
|
||||
addConfig(product, title + " | " + body);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
/** 尺寸限制是整段产品的规则,不写进每一档单价。 */
|
||||
private void keepLimit(PayProduct product, String head, String text)
|
||||
{
|
||||
String body = text.replace('\n', ';').replace(";;", ";").trim();
|
||||
if (body.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
String title = head.contains("尺寸") ? "尺寸限制" : shortCharge(head);
|
||||
addConfig(product, title + " | " + body);
|
||||
}
|
||||
|
||||
private void addConfig(PayProduct product, String text)
|
||||
{
|
||||
String line = cut(new StringBuilder(text), 1000);
|
||||
if (line.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (PayExtraLine existing : product.getExtraLines())
|
||||
{
|
||||
if (line.equals(existing.getLineText()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
PayExtraLine extra = new PayExtraLine();
|
||||
extra.setLineType("配置");
|
||||
extra.setLineText(line);
|
||||
extra.setSortNo(product.getExtraLines().size() + 1);
|
||||
product.getExtraLines().add(extra);
|
||||
}
|
||||
|
||||
/** 单独的「附加费」标题。后面跟着金额说明或条件费率,而不是收费标准表。 */
|
||||
private static boolean isFeeSectionTitle(ExcelGrid grid, int row)
|
||||
{
|
||||
@@ -4122,6 +4224,39 @@ public class PayWorkbookParser
|
||||
return currency.isEmpty() ? "每票" : currency + "/票";
|
||||
}
|
||||
|
||||
/** 附加费的货币单位跟重量段一样,价格数字单独放 amount,这里只放 EUR/ITEM、RMB/KG、%。 */
|
||||
private static String surchargeUnit(PayTexts.Money money, String standard)
|
||||
{
|
||||
if (money == null || money.amount == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
if ("%".equals(money.unit))
|
||||
{
|
||||
return "%";
|
||||
}
|
||||
String fromText = unitOf(standard == null ? "" : standard);
|
||||
String currency = money.currency == null ? "" : money.currency;
|
||||
String unit = money.unit == null ? "" : money.unit;
|
||||
if (fromText.contains("/"))
|
||||
{
|
||||
return fromText;
|
||||
}
|
||||
if (unit.isEmpty() && ("ITEM".equals(fromText) || "KG".equals(fromText)))
|
||||
{
|
||||
unit = fromText;
|
||||
}
|
||||
if (!currency.isEmpty() && !unit.isEmpty())
|
||||
{
|
||||
return currency + "/" + unit;
|
||||
}
|
||||
if (!fromText.isEmpty() && currency.isEmpty())
|
||||
{
|
||||
return fromText;
|
||||
}
|
||||
return currency.isEmpty() ? unit : currency;
|
||||
}
|
||||
|
||||
private static String unitOf(String header)
|
||||
{
|
||||
String value = header.toUpperCase(Locale.ROOT);
|
||||
@@ -4135,6 +4270,19 @@ public class PayWorkbookParser
|
||||
return per.isEmpty() ? currency : currency + "/" + per;
|
||||
}
|
||||
|
||||
/** 去掉表头里的币种括号,留下服务名。两段派送费才能分成 Crono Express 和 Crono。 */
|
||||
private static String chargeTitle(String head)
|
||||
{
|
||||
if (head == null || head.isBlank())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
String value = head.replace('\n', ' ').replace('\r', ' ');
|
||||
value = value.replaceAll("(?i)[((]\\s*(?:EUR|GBP|USD|RMB|CNY|欧元|英镑|美元|人民币)\\s*/\\s*[^))]{1,12}[))]", " ");
|
||||
value = value.replaceAll("\\s+", " ").trim();
|
||||
return shortCharge(value);
|
||||
}
|
||||
|
||||
private static String shortCharge(String text)
|
||||
{
|
||||
if (text == null)
|
||||
@@ -4169,7 +4317,7 @@ public class PayWorkbookParser
|
||||
{
|
||||
if (isPriceHead(head))
|
||||
{
|
||||
return shortCharge(head);
|
||||
return chargeTitle(head);
|
||||
}
|
||||
}
|
||||
return "价格";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.bms.price.service;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Date;
|
||||
import com.bms.price.domain.PayPreview;
|
||||
@@ -66,5 +67,11 @@ public interface IPayProductService
|
||||
/** 产品及其重量段、附加费、邮编配置 */
|
||||
PayProduct selectPayProductDetail(Long productId);
|
||||
|
||||
/** 确认这一版有源文件,返回原始文件名 */
|
||||
String sourceFileName(Long productId);
|
||||
|
||||
/** 把这一版的源文件写到输出流 */
|
||||
void writeSource(Long productId, OutputStream output);
|
||||
|
||||
int deletePayProducts(Long[] productIds);
|
||||
}
|
||||
|
||||
+164
@@ -1,20 +1,29 @@
|
||||
package com.bms.price.service.impl;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.bms.common.core.domain.entity.SysDictData;
|
||||
import com.bms.common.exception.ServiceException;
|
||||
import com.bms.common.utils.DateUtils;
|
||||
import com.bms.common.utils.SecurityUtils;
|
||||
import com.bms.common.utils.file.OssStorage;
|
||||
import com.bms.common.utils.uuid.IdUtils;
|
||||
import com.bms.price.domain.ChannelProductMap;
|
||||
import com.bms.price.domain.PayExtraLine;
|
||||
import com.bms.price.domain.PayPreview;
|
||||
@@ -58,14 +67,26 @@ public class PayProductServiceImpl implements IPayProductService
|
||||
@Autowired
|
||||
private ISysDictTypeService dictTypeService;
|
||||
|
||||
@Autowired
|
||||
private OssStorage ossStorage;
|
||||
|
||||
private final PayWorkbookParser parser = new PayWorkbookParser();
|
||||
|
||||
/** 预览时已经传到 OSS 的文件。保存不再只靠前端把地址传回来。 */
|
||||
private final Map<String, UploadedSource> uploadedSources = new ConcurrentHashMap<>();
|
||||
|
||||
private static final long SOURCE_REMEMBER_MS = 6L * 60 * 60 * 1000;
|
||||
|
||||
@Override
|
||||
public PayPreview preview(byte[] bytes, String filename, String dictValue)
|
||||
{
|
||||
PayPreview preview = parser.parseMatched(bytes, filename, dictValue, loadDictValues());
|
||||
String stored = storeSource(bytes, filename);
|
||||
rememberSource(preview.getFileMd5(), stored);
|
||||
preview.setFilePath(stored);
|
||||
for (PayProduct product : preview.getProducts())
|
||||
{
|
||||
product.setFilePath(stored);
|
||||
Long existsId = isBlank(product.getDictValue()) ? null : payProductMapper.selectTemplateId(product.getDictValue());
|
||||
product.setDuplicated(existsId != null);
|
||||
product.setExistsId(existsId);
|
||||
@@ -102,6 +123,7 @@ public class PayProductServiceImpl implements IPayProductService
|
||||
continue;
|
||||
}
|
||||
product.setProductType(requireProductType(product.getProductType()));
|
||||
product.setFilePath(resolveSource(product));
|
||||
prepareCounts(product);
|
||||
fitColumns(product);
|
||||
product.setProductId(null);
|
||||
@@ -152,6 +174,7 @@ public class PayProductServiceImpl implements IPayProductService
|
||||
product.setProductType(isBlank(product.getProductType()) ? existing.getProductType() : payTypeOf(product.getProductType()));
|
||||
product.setFileMd5(blankTo(product.getFileMd5(), existing.getFileMd5()));
|
||||
product.setSourceFile(blankTo(product.getSourceFile(), existing.getSourceFile()));
|
||||
product.setFilePath(blankTo(sourcePath(product.getFilePath()), existing.getFilePath()));
|
||||
product.setSheetName(blankTo(product.getSheetName(), existing.getSheetName()));
|
||||
product.setUpdateBy(SecurityUtils.getUsername());
|
||||
prepareCounts(product);
|
||||
@@ -334,6 +357,7 @@ public class PayProductServiceImpl implements IPayProductService
|
||||
copy.setSheetName(blankTo(edited.getSheetName(), origin.getSheetName()));
|
||||
copy.setRelatedSheet(blankTo(edited.getRelatedSheet(), origin.getRelatedSheet()));
|
||||
copy.setSourceFile(blankTo(edited.getSourceFile(), origin.getSourceFile()));
|
||||
copy.setFilePath(blankTo(sourcePath(edited.getFilePath()), origin.getFilePath()));
|
||||
copy.setFileMd5(blankTo(edited.getFileMd5(), origin.getFileMd5()));
|
||||
copy.setSupplierName(blankTo(edited.getSupplierName(), origin.getSupplierName()));
|
||||
copy.setEffectiveDate(edited.getEffectiveDate() != null ? edited.getEffectiveDate() : origin.getEffectiveDate());
|
||||
@@ -453,6 +477,7 @@ public class PayProductServiceImpl implements IPayProductService
|
||||
term.setProductId(product.getProductId());
|
||||
term.setVersionNo(product.getVersionNo() == null ? 1 : product.getVersionNo());
|
||||
term.setEffectiveStart(product.getEffectiveDate());
|
||||
term.setFilePath(sourcePath(product.getFilePath()));
|
||||
term.setStatus("1");
|
||||
term.setCreateBy(product.getCreateBy());
|
||||
payProductTermMapper.insertTerm(term);
|
||||
@@ -477,6 +502,130 @@ public class PayProductServiceImpl implements IPayProductService
|
||||
return products;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sourceFileName(Long productId)
|
||||
{
|
||||
return sourceOf(productId).getSourceFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSource(Long productId, OutputStream output)
|
||||
{
|
||||
try
|
||||
{
|
||||
ossStorage.download(sourceOf(productId).getFilePath(), output);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new ServiceException("源文件下载失败");
|
||||
}
|
||||
}
|
||||
|
||||
private PayProduct sourceOf(Long productId)
|
||||
{
|
||||
PayProduct product = productId == null ? null : payProductMapper.selectPayProductById(productId);
|
||||
if (product == null)
|
||||
{
|
||||
throw new ServiceException("产品不存在或已删除");
|
||||
}
|
||||
String path = sourcePath(product.getFilePath());
|
||||
if (path == null)
|
||||
{
|
||||
throw new ServiceException("这一版没有可下载的源文件");
|
||||
}
|
||||
product.setFilePath(path);
|
||||
if (isBlank(product.getSourceFile()))
|
||||
{
|
||||
product.setSourceFile("价卡.xlsx");
|
||||
}
|
||||
return product;
|
||||
}
|
||||
|
||||
/** 识别完成后把原文件放到 OSS,同一份文件只传一次。 */
|
||||
private String storeSource(byte[] bytes, String filename)
|
||||
{
|
||||
String original = isBlank(filename) ? "import.xlsx" : filename.trim();
|
||||
String ext = "xlsx";
|
||||
int dot = original.lastIndexOf('.');
|
||||
if (dot >= 0 && dot < original.length() - 1)
|
||||
{
|
||||
ext = original.substring(dot + 1).toLowerCase(Locale.ROOT);
|
||||
}
|
||||
if (!"xlsx".equals(ext) && !"xls".equals(ext))
|
||||
{
|
||||
ext = "xlsx";
|
||||
}
|
||||
String contentType = "xls".equals(ext)
|
||||
? "application/vnd.ms-excel"
|
||||
: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
String objectKey = "price/pay/" + DateUtils.datePath() + "/" + IdUtils.fastSimpleUUID() + "." + ext;
|
||||
try
|
||||
{
|
||||
return ossStorage.upload(new ByteArrayInputStream(bytes), bytes.length, objectKey, contentType);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new ServiceException("价卡文件上传失败");
|
||||
}
|
||||
}
|
||||
|
||||
/** 保存时用预览传回的地址;前端没带上时,用刚才上传记住的那一份。 */
|
||||
private String resolveSource(PayProduct product)
|
||||
{
|
||||
String path = sourcePath(product.getFilePath());
|
||||
if (path == null)
|
||||
{
|
||||
path = rememberedSource(product.getFileMd5());
|
||||
}
|
||||
if (path == null)
|
||||
{
|
||||
throw new ServiceException("源文件还没有上传成功,请重新选择价卡后再保存");
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private void rememberSource(String fileMd5, String path)
|
||||
{
|
||||
if (isBlank(fileMd5) || sourcePath(path) == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
long now = System.currentTimeMillis();
|
||||
Iterator<Map.Entry<String, UploadedSource>> it = uploadedSources.entrySet().iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
if (now - it.next().getValue().at > SOURCE_REMEMBER_MS)
|
||||
{
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
uploadedSources.put(fileMd5, new UploadedSource(path, now));
|
||||
}
|
||||
|
||||
private String rememberedSource(String fileMd5)
|
||||
{
|
||||
if (isBlank(fileMd5))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
UploadedSource stored = uploadedSources.get(fileMd5);
|
||||
if (stored == null || System.currentTimeMillis() - stored.at > SOURCE_REMEMBER_MS)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return stored.path;
|
||||
}
|
||||
|
||||
/** 只接受本次应付价卡目录下的 OSS 地址,避免把别的文件地址写进来。 */
|
||||
private static String sourcePath(String path)
|
||||
{
|
||||
if (path == null || !path.startsWith("oss://") || !path.contains("/price/pay/"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return path.trim();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayProduct selectPayProductDetail(Long productId)
|
||||
{
|
||||
@@ -647,6 +796,7 @@ public class PayProductServiceImpl implements IPayProductService
|
||||
product.setSheetName(cut(product.getSheetName(), 200));
|
||||
product.setRelatedSheet(cut(product.getRelatedSheet(), 500));
|
||||
product.setSourceFile(cut(product.getSourceFile(), 500));
|
||||
product.setFilePath(cut(product.getFilePath(), 500));
|
||||
product.setSupplierName(cut(product.getSupplierName(), 100));
|
||||
product.setCurrency(cut(product.getCurrency(), 20));
|
||||
product.setServiceNote(cut(product.getServiceNote(), 4000));
|
||||
@@ -675,6 +825,7 @@ public class PayProductServiceImpl implements IPayProductService
|
||||
fee.setZoneName(cut(fee.getZoneName(), 200));
|
||||
fee.setChargeText(cut(fee.getChargeText(), 500));
|
||||
fee.setCurrency(cut(fee.getCurrency(), 20));
|
||||
fee.setPriceUnit(cut(fee.getPriceUnit(), 40));
|
||||
fee.setFeeDesc(cut(fee.getFeeDesc(), 2000));
|
||||
fee.setPeriodText(cut(fee.getPeriodText(), 500));
|
||||
fee.setChargeTiming(cut(fee.getChargeTiming(), 40));
|
||||
@@ -1074,4 +1225,17 @@ public class PayProductServiceImpl implements IPayProductService
|
||||
{
|
||||
return isBlank(value) ? fallback : value;
|
||||
}
|
||||
|
||||
private static final class UploadedSource
|
||||
{
|
||||
private final String path;
|
||||
|
||||
private final long at;
|
||||
|
||||
private UploadedSource(String path, long at)
|
||||
{
|
||||
this.path = path;
|
||||
this.at = at;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<update id="updateServiceChannel" parameterType="com.bms.masterdata.domain.ServiceChannel">
|
||||
update srv_service_channel
|
||||
set channel_code = #{channelCode},
|
||||
|
||||
channel_name = #{channelName},
|
||||
service_code = #{serviceCode},
|
||||
service_name = #{serviceName},
|
||||
|
||||
@@ -23,6 +23,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="sheetName" column="sheet_name"/>
|
||||
<result property="relatedSheet" column="related_sheet"/>
|
||||
<result property="sourceFile" column="source_file"/>
|
||||
<result property="filePath" column="file_path"/>
|
||||
<result property="fileMd5" column="file_md5"/>
|
||||
<result property="supplierName" column="supplier_name"/>
|
||||
<result property="effectiveDate" column="effective_date"/>
|
||||
@@ -112,6 +113,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
ifnull(cur.extra_per_kg, pay_product.extra_per_kg) as extra_per_kg, pay_product.service_type,
|
||||
pay_product.classification, pay_product.catalog_remark, pay_product.update_content, pay_product.weight_limit,
|
||||
pay_product.sheet_name, pay_product.related_sheet, ifnull(cur.source_file, pay_product.source_file) as source_file,
|
||||
case when cur.product_id is null then pay_product.file_path else cur.file_path end as file_path,
|
||||
pay_product.file_md5,
|
||||
pay_product.supplier_name, pay_product.effective_date, ifnull(cur.currency, pay_product.currency) as currency,
|
||||
pay_product.service_note,
|
||||
@@ -137,7 +139,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
|
||||
<select id="selectPayProductById" parameterType="long" resultMap="PayProductResult">
|
||||
select product_id, product_name, product_type, dict_value, origin_id, channel_id, version_no, country_scope, charge_type, extra_per_kg, service_type,
|
||||
classification, catalog_remark, update_content, weight_limit, sheet_name, related_sheet, source_file,
|
||||
classification, catalog_remark, update_content, weight_limit, sheet_name, related_sheet, source_file, file_path,
|
||||
file_md5, supplier_name, effective_date, currency, service_note, parse_status, weight_count,
|
||||
surcharge_count, extra_count, created_by, create_time, updated_by, update_time, remark
|
||||
from pay_product
|
||||
@@ -153,13 +155,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<insert id="insertPayProduct" parameterType="com.bms.price.domain.PayProduct" useGeneratedKeys="true" keyProperty="productId">
|
||||
insert into pay_product (
|
||||
product_name, product_type, dict_value, origin_id, channel_id, version_no, country_scope, charge_type, extra_per_kg, service_type, classification,
|
||||
catalog_remark, update_content, weight_limit, sheet_name, related_sheet, source_file, file_md5,
|
||||
catalog_remark, update_content, weight_limit, sheet_name, related_sheet, source_file, file_path, file_md5,
|
||||
supplier_name, effective_date, currency, service_note, parse_status, weight_count, surcharge_count,
|
||||
extra_count, created_by, create_time, remark
|
||||
) values (
|
||||
#{productName}, #{productType}, #{dictValue}, #{originId}, #{channelId}, ifnull(#{versionNo}, 1), #{countryScope}, #{chargeType}, #{extraPerKg},
|
||||
#{serviceType}, #{classification}, #{catalogRemark}, #{updateContent}, #{weightLimit}, #{sheetName},
|
||||
#{relatedSheet}, #{sourceFile}, #{fileMd5}, #{supplierName}, #{effectiveDate}, #{currency},
|
||||
#{relatedSheet}, #{sourceFile}, #{filePath}, #{fileMd5}, #{supplierName}, #{effectiveDate}, #{currency},
|
||||
#{serviceNote}, #{parseStatus}, #{weightCount}, #{surchargeCount}, #{extraCount}, #{createBy}, sysdate(),
|
||||
#{remark}
|
||||
)
|
||||
@@ -184,6 +186,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
sheet_name = #{sheetName},
|
||||
related_sheet = #{relatedSheet},
|
||||
source_file = #{sourceFile},
|
||||
file_path = #{filePath},
|
||||
file_md5 = #{fileMd5},
|
||||
supplier_name = #{supplierName},
|
||||
effective_date = #{effectiveDate},
|
||||
@@ -246,12 +249,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
|
||||
<insert id="insertSurcharges">
|
||||
insert into pay_surcharge (
|
||||
product_id, version_no, section_name, fee_name, zone_name, charge_text, amount, currency, fee_desc, period_text,
|
||||
product_id, version_no, section_name, fee_name, zone_name, charge_text, amount, currency, price_unit, fee_desc, period_text,
|
||||
effective_start, effective_end, charge_timing, calc_rule, calc_param, sort_no
|
||||
) values
|
||||
<foreach collection="list" item="row" separator=",">
|
||||
(#{row.productId}, ifnull(#{row.versionNo}, 1), #{row.sectionName}, #{row.feeName}, #{row.zoneName}, #{row.chargeText}, #{row.amount},
|
||||
#{row.currency}, #{row.feeDesc}, #{row.periodText}, #{row.effectiveStart}, #{row.effectiveEnd},
|
||||
#{row.currency}, #{row.priceUnit}, #{row.feeDesc}, #{row.periodText}, #{row.effectiveStart}, #{row.effectiveEnd},
|
||||
#{row.chargeTiming}, ifnull(#{row.calcRule}, 'MANUAL'), #{row.calcParam}, #{row.sortNo})
|
||||
</foreach>
|
||||
</insert>
|
||||
@@ -275,7 +278,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
|
||||
<select id="selectSurcharges" resultType="com.bms.price.domain.PaySurcharge">
|
||||
select surcharge_id as surchargeId, product_id as productId, version_no as versionNo, section_name as sectionName, fee_name as feeName,
|
||||
zone_name as zoneName, charge_text as chargeText, amount, currency, fee_desc as feeDesc,
|
||||
zone_name as zoneName, charge_text as chargeText, amount, currency, price_unit as priceUnit, fee_desc as feeDesc,
|
||||
period_text as periodText, effective_start as effectiveStart, effective_end as effectiveEnd,
|
||||
charge_timing as chargeTiming, calc_rule as calcRule, calc_param as calcParam, sort_no as sortNo
|
||||
from pay_surcharge
|
||||
|
||||
@@ -8,7 +8,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
select t.term_id as termId, t.dict_value as dictValue, t.product_id as productId, t.version_no as versionNo,
|
||||
t.effective_start as effectiveStart, t.effective_end as effectiveEnd, t.status,
|
||||
t.created_by as createBy, t.create_time as createTime, t.remark,
|
||||
p.product_name as productName, p.source_file as sourceFile, p.weight_count as weightCount,
|
||||
p.product_name as productName, p.source_file as sourceFile,
|
||||
ifnull(t.file_path, p.file_path) as filePath, p.weight_count as weightCount,
|
||||
p.surcharge_count as surchargeCount, p.currency
|
||||
from pay_product_term t
|
||||
join pay_product p on p.product_id = t.product_id
|
||||
@@ -34,9 +35,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
|
||||
<insert id="insertTerm" parameterType="com.bms.price.domain.PayProductTerm" useGeneratedKeys="true" keyProperty="termId">
|
||||
insert into pay_product_term (
|
||||
dict_value, product_id, version_no, effective_start, effective_end, status, created_by, create_time, remark
|
||||
dict_value, product_id, version_no, effective_start, effective_end, file_path, status, created_by, create_time, remark
|
||||
) values (
|
||||
#{dictValue}, #{productId}, ifnull(#{versionNo}, 1), #{effectiveStart}, #{effectiveEnd},
|
||||
#{dictValue}, #{productId}, ifnull(#{versionNo}, 1), #{effectiveStart}, #{effectiveEnd}, #{filePath},
|
||||
ifnull(#{status}, '0'), #{createBy}, sysdate(), #{remark}
|
||||
)
|
||||
</insert>
|
||||
|
||||
Reference in New Issue
Block a user