提交
This commit is contained in:
+59
@@ -0,0 +1,59 @@
|
||||
package com.baiyue.lastleg.service;
|
||||
|
||||
import net.sourceforge.pinyin4j.PinyinHelper;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
|
||||
/** Allocates suffix-free document numbers across all service instances. */
|
||||
@Component
|
||||
public class CompactBusinessNumberService {
|
||||
private static final ZoneId ZONE = ZoneId.of("Asia/Shanghai");
|
||||
private static final DateTimeFormatter FORMAT = DateTimeFormatter.ofPattern("yyMMddHHmmss", Locale.ROOT).withZone(ZONE);
|
||||
private final JdbcTemplate jdbc;
|
||||
private final ReturnOrderReferenceResolver customers;
|
||||
|
||||
public CompactBusinessNumberService(JdbcTemplate jdbc, ReturnOrderReferenceResolver customers) {
|
||||
this.jdbc = jdbc;
|
||||
this.customers = customers;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public String next(String prefix, String customerId) {
|
||||
return allocate(prefix, initials(customers.customerName(customerId)), Instant.now());
|
||||
}
|
||||
|
||||
String allocate(String prefix, String initials, Instant now) {
|
||||
String key = prefix + "-" + initials;
|
||||
long seconds = now.getEpochSecond();
|
||||
// The row lock serializes identical prefixes/initials even across customers and JVMs.
|
||||
jdbc.update("INSERT INTO ll_compact_number_clock(number_key,last_second) VALUES(?,LAST_INSERT_ID(?)) "
|
||||
+ "ON DUPLICATE KEY UPDATE last_second=LAST_INSERT_ID(GREATEST(last_second+1,?))", key, seconds, seconds);
|
||||
Long allocated = jdbc.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
|
||||
if (allocated == null || allocated < seconds) throw new IllegalStateException("业务编号生成失败");
|
||||
return key + "-" + FORMAT.format(Instant.ofEpochSecond(allocated));
|
||||
}
|
||||
|
||||
static String initials(String name) {
|
||||
if (name == null || name.isBlank()) return "KH";
|
||||
StringBuilder result = new StringBuilder();
|
||||
boolean latinWord = false;
|
||||
for (char c : name.trim().toCharArray()) {
|
||||
if (result.length() >= 4) break;
|
||||
if (Character.UnicodeScript.of(c) == Character.UnicodeScript.HAN) {
|
||||
String[] pinyin = PinyinHelper.toHanyuPinyinStringArray(c);
|
||||
if (pinyin != null && pinyin.length > 0) result.append(Character.toUpperCase(pinyin[0].charAt(0)));
|
||||
latinWord = false;
|
||||
} else if (c < 128 && Character.isLetterOrDigit(c)) {
|
||||
if (!latinWord) result.append(Character.toUpperCase(c));
|
||||
latinWord = true;
|
||||
} else latinWord = false;
|
||||
}
|
||||
return result.isEmpty() ? "KH" : result.toString();
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ public class LastlegOrderNoGenerator {
|
||||
|
||||
public String next(String businessType, String warehouse, long uniqueId) {
|
||||
String code = businessType == null ? "" : businessType.trim().toUpperCase(Locale.ROOT);
|
||||
if ("RETURN_CARTON".equals(code)) return compactCartonMark(uniqueId);
|
||||
String returnPrefix = switch (code) {
|
||||
case "RETURN" -> "RT";
|
||||
case "RETURN_RECEIPT" -> "RR";
|
||||
@@ -65,6 +66,12 @@ public class LastlegOrderNoGenerator {
|
||||
return "0".repeat(25 - encoded.length()) + encoded;
|
||||
}
|
||||
|
||||
/** Preserve every snowflake ID bit; do not truncate or hash physical label identifiers. */
|
||||
public static String compactCartonMark(long id) {
|
||||
if (id <= 0) throw new IllegalArgumentException("Carton id must be positive");
|
||||
return "BX-" + Long.toString(id, 36).toUpperCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
private String normalizeType(String value) {
|
||||
String code = value == null ? "LMO" : value.trim().toUpperCase(Locale.ROOT);
|
||||
return switch (code) {
|
||||
|
||||
+4
@@ -65,6 +65,10 @@ public class ReturnOrderReferenceResolver {
|
||||
}
|
||||
}
|
||||
|
||||
public String customerName(String id) {
|
||||
return customerReference(id).tenantName();
|
||||
}
|
||||
|
||||
private ReturnCustomerReferenceClient.Customer customerReference(String id) {
|
||||
try {
|
||||
var result = customers.customers(internalToken, 1, 30, null, "ACTIVE", Long.parseLong(id));
|
||||
|
||||
Reference in New Issue
Block a user