空运未填报价日期时不默认当天,查出舱位后由销售点选再写回日期。
包装类型里的托盘不再被抄进增值服务。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+33
-9
@@ -121,14 +121,15 @@ public class InquiryTmsQueryService {
|
||||
segment.put("cargoReadyDate", first(facts.get("cargoReadyDate"), facts.get("货好时间")));
|
||||
segment.put("placeOfReceipt", first(facts.get("placeOfReceipt"), facts.get("提货地址")));
|
||||
segment.put("deliveryAddress", first(facts.get("deliveryAddress"), facts.get("收货地址")));
|
||||
// 工单 added_services 在这里收成列表,后面的 mapper 原样放到 TMS addedServices。
|
||||
List<String> addedServices = TmsV2RequestMapper.splitAddedServices(first(
|
||||
facts.get("addedServices"), facts.get("added_services"), facts.get("增值服务")));
|
||||
if (!addedServices.isEmpty()) {
|
||||
segment.put("addedServices", addedServices);
|
||||
}
|
||||
}
|
||||
|
||||
String quoteDate = TmsV2RequestMapper.normalizeQuoteDate(facts.get("报价日期"));
|
||||
if (quoteDate == null) {
|
||||
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
|
||||
fmt.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
|
||||
quoteDate = fmt.format(new Date());
|
||||
}
|
||||
String quoteDate = resolveOutboundQuoteDate(line, facts.get("报价日期"));
|
||||
|
||||
List<String> missing;
|
||||
if ("SEA".equals(line)) {
|
||||
@@ -162,6 +163,10 @@ public class InquiryTmsQueryService {
|
||||
|
||||
String cacheKey = line + ":" + quoteDate + ":" + origin + ":" + destination
|
||||
+ ":" + segment.get("weightKg") + ":" + segment.get("volumeCbm");
|
||||
if ("AIR".equals(line) && segment.get("addedServices") != null) {
|
||||
// 增值服务不同不能共用同一条运价缓存。
|
||||
cacheKey += ":" + segment.get("addedServices");
|
||||
}
|
||||
if ("LAND".equals(line)) {
|
||||
cacheKey += ":" + segment.get("landTransportType") + ":" + segment.get("routeCategory")
|
||||
+ ":" + segment.get("vehicleType") + ":" + segment.get("quantity");
|
||||
@@ -1324,17 +1329,36 @@ public class InquiryTmsQueryService {
|
||||
return raw == null || String.valueOf(raw).trim().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查价出站用的报价日期。
|
||||
*
|
||||
* 海运、陆运没说则填上海当天。空运没说保持 null,不传 quoteDate,
|
||||
* 让 TMS 一次返回各航班日期的舱位。销售说了的日期原样规范化,不用当天盖掉。
|
||||
*/
|
||||
static String resolveOutboundQuoteDate(String line, Object raw) {
|
||||
String quoteDate = TmsV2RequestMapper.normalizeQuoteDate(raw);
|
||||
if (quoteDate != null) {
|
||||
return quoteDate;
|
||||
}
|
||||
if ("AIR".equals(line)) {
|
||||
return null;
|
||||
}
|
||||
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
|
||||
fmt.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
|
||||
return fmt.format(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 空运出站齐套检查。地名栏允许空串,禁止再拿 destination 拦查价。
|
||||
* 报价日期非必填,空着也算出站齐套。
|
||||
*/
|
||||
static List<String> missingAirQuery(String workOrderNo, String quoteDate, Map<String, Object> segment) {
|
||||
List<String> missing = new ArrayList<>();
|
||||
if (workOrderNo == null || !workOrderNo.matches("WO\\d{12}")) {
|
||||
missing.add("workOrderNo");
|
||||
}
|
||||
if (quoteDate == null || quoteDate.isEmpty()) {
|
||||
missing.add("quoteDate");
|
||||
}
|
||||
// 报价日期非必填。空着不计入 missing;参数留给已有调用方,避免再按缺日期拦截。
|
||||
log.debug("air.query dateOptional len={}", quoteDate == null ? 0 : quoteDate.length());
|
||||
for (String key : new String[] {
|
||||
"cargoName", "quantity", "weightKg", "volumeCbm", "packageType"
|
||||
}) {
|
||||
|
||||
+40
@@ -115,6 +115,12 @@ public final class TmsV2RequestMapper {
|
||||
put(target, "cargoReadyDate", first(source, "cargoReadyDate", "货好时间"));
|
||||
put(target, "placeOfReceipt", first(source, "placeOfReceipt", "提货地址"));
|
||||
put(target, "deliveryAddress", first(source, "deliveryAddress", "收货地址"));
|
||||
// 有增值服务才传列表。空列表不能出站,否则 TMS 会当成带了服务条件。
|
||||
List<String> addedServices = splitAddedServices(
|
||||
first(source, "addedServices", "added_services", "增值服务"));
|
||||
if (!addedServices.isEmpty()) {
|
||||
target.put("addedServices", addedServices);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,6 +169,40 @@ public final class TmsV2RequestMapper {
|
||||
put(target, "customsPort", first(source, "customsPort"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 空运增值服务拆成多项。
|
||||
* <p>
|
||||
* 工单里是 added_services 一句话,TMS 要 addedServices 列表。
|
||||
* 顿号、中文逗号、英文逗号都拆;空格不拆,MUST GO 仍是一项。
|
||||
* 已经是列表则逐项原样保留。空项丢掉,不改词。
|
||||
*/
|
||||
public static List<String> splitAddedServices(Object raw) {
|
||||
List<String> out = new ArrayList<>();
|
||||
if (raw instanceof List) {
|
||||
for (Object item : (List<?>) raw) {
|
||||
addServiceToken(out, item);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
String text = textOf(raw);
|
||||
if (text.isEmpty()) {
|
||||
return out;
|
||||
}
|
||||
for (String part : text.split("[、,,]")) {
|
||||
addServiceToken(out, part);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 去掉空白后并入列表。同一词只留第一次。 */
|
||||
private static void addServiceToken(List<String> out, Object raw) {
|
||||
String token = textOf(raw);
|
||||
if (token.isEmpty() || out.contains(token)) {
|
||||
return;
|
||||
}
|
||||
out.add(token);
|
||||
}
|
||||
|
||||
private static String textOf(Object raw) {
|
||||
return raw == null ? "" : String.valueOf(raw).trim();
|
||||
}
|
||||
|
||||
+23
@@ -92,4 +92,27 @@ public class InquiryTmsQueryServiceTest {
|
||||
"WO202609220004", "2026-09-25", segment);
|
||||
org.junit.jupiter.api.Assertions.assertTrue(missing.isEmpty(), String.valueOf(missing));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void airQueryAllowsBlankQuoteDate() {
|
||||
// 空运没填报价日期也算出站齐套,不能再补成当天才放行。
|
||||
java.util.Map<String, Object> segment = new java.util.HashMap<String, Object>();
|
||||
segment.put("cargoName", "茶叶");
|
||||
segment.put("quantity", 1);
|
||||
segment.put("weightKg", "1.5");
|
||||
segment.put("volumeCbm", "100");
|
||||
segment.put("packageType", "托盘");
|
||||
java.util.List<String> missing = InquiryTmsQueryService.missingAirQuery(
|
||||
"WO202609220004", null, segment);
|
||||
org.junit.jupiter.api.Assertions.assertTrue(missing.isEmpty(), String.valueOf(missing));
|
||||
org.junit.jupiter.api.Assertions.assertNull(
|
||||
InquiryTmsQueryService.resolveOutboundQuoteDate("AIR", null));
|
||||
org.junit.jupiter.api.Assertions.assertEquals(
|
||||
"2026-10-08",
|
||||
InquiryTmsQueryService.resolveOutboundQuoteDate("AIR", "2026-10-08"));
|
||||
org.junit.jupiter.api.Assertions.assertNotNull(
|
||||
InquiryTmsQueryService.resolveOutboundQuoteDate("SEA", null));
|
||||
org.junit.jupiter.api.Assertions.assertNotNull(
|
||||
InquiryTmsQueryService.resolveOutboundQuoteDate("LAND", ""));
|
||||
}
|
||||
}
|
||||
|
||||
+25
@@ -193,6 +193,31 @@ public class TmsV2RequestMapperTest {
|
||||
assertFalse(out.containsKey("tradeTerms"));
|
||||
assertFalse(out.containsKey("贸易条款"));
|
||||
assertNull(out.get("originCode"));
|
||||
assertFalse(out.containsKey("addedServices"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void airAddedServicesSplitIntoList() {
|
||||
Map<String, Object> seg = new HashMap<>();
|
||||
seg.put("destinationCode", "KUL");
|
||||
seg.put("cargoName", "茶叶");
|
||||
seg.put("quantity", "10");
|
||||
seg.put("weightKg", "100");
|
||||
seg.put("volumeCbm", "2");
|
||||
seg.put("packageType", "纸箱");
|
||||
seg.put("added_services", "托盘、前置仓,带电");
|
||||
Map<String, Object> internal = new HashMap<>();
|
||||
internal.put("transportMode", "AIR");
|
||||
internal.put("quoteDate", "2026-10-13");
|
||||
internal.put("segments", Collections.singletonList(seg));
|
||||
Map<String, Object> body = TmsV2RequestMapper.quote(internal);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> segs = (List<Map<String, Object>>) body.get("segments");
|
||||
assertEquals(java.util.Arrays.asList("托盘", "前置仓", "带电"), segs.get(0).get("addedServices"));
|
||||
assertFalse(segs.get(0).containsKey("added_services"));
|
||||
assertEquals(
|
||||
java.util.Arrays.asList("MUST GO", "带电"),
|
||||
TmsV2RequestMapper.splitAddedServices("MUST GO、带电"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user