feat: add self-operated analytics and enforce Lastleg module boundaries

This commit is contained in:
2026-10-12 20:27:35 +08:00
parent c06e788b0f
commit a1f1d93902
174 changed files with 13514 additions and 490 deletions
@@ -1,8 +1,10 @@
package com.baiyue.lastleg.service;
import com.baiyue.lastleg.entity.LastlegOrder;
import com.baiyue.lastleg.fleet.customer.FleetCustomerDirectory;
import com.baiyue.lastleg.service.reference.ReturnCustomerReferenceClient;
import com.baiyue.lastleg.inboundplan.pda.gateway.WarehouseResourceGateway;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ResponseStatusException;
@@ -16,12 +18,15 @@ import java.util.Map;
@Service
public class ReturnOrderReferenceResolver {
private static final Logger log = LoggerFactory.getLogger(ReturnOrderReferenceResolver.class);
private final FleetCustomerDirectory customers;
private final ReturnCustomerReferenceClient customers;
private final WarehouseResourceGateway warehouses;
private final String internalToken;
public ReturnOrderReferenceResolver(FleetCustomerDirectory customers, WarehouseResourceGateway warehouses) {
public ReturnOrderReferenceResolver(ReturnCustomerReferenceClient customers, WarehouseResourceGateway warehouses,
@Value("${baiyue.security.internal-service-token}") String internalToken) {
this.customers = customers;
this.warehouses = warehouses;
this.internalToken = internalToken;
}
public void populate(List<LastlegOrder> orders) {
@@ -33,14 +38,14 @@ public class ReturnOrderReferenceResolver {
}
private void populate(List<LastlegOrder> orders, boolean required) {
Map<String, FleetCustomerDirectory.Customer> customerReferences = new HashMap<>();
Map<String, ReturnCustomerReferenceClient.Customer> customerReferences = new HashMap<>();
Map<String, WarehouseResourceGateway.WarehouseReference> warehouseReferences = new HashMap<>();
for (LastlegOrder order : orders) {
if (!"RETURN_RELABEL".equals(order.getOrderType())) continue;
if (!StringUtils.hasText(order.getCustomerName())) {
try {
var customer = customerReferences.computeIfAbsent(order.getCustomerId(), customers::find);
order.setCustomerName(customer.name());
var customer = customerReferences.computeIfAbsent(order.getCustomerId(), this::customerReference);
order.setCustomerName(customer.tenantName());
} catch (ResponseStatusException error) {
if (required) throw error;
log.warn("Return customer reference unavailable for order {}, status {}", order.getId(), error.getStatusCode().value());
@@ -59,4 +64,18 @@ public class ReturnOrderReferenceResolver {
}
}
}
private ReturnCustomerReferenceClient.Customer customerReference(String id) {
try {
var result = customers.customers(internalToken, 1, 30, null, "ACTIVE", Long.parseLong(id));
if (result == null || !result.successful() || result.data() == null)
throw new ResponseStatusException(HttpStatus.SERVICE_UNAVAILABLE, "客户目录暂不可用,请稍后重试");
return result.data().records().stream()
.filter(row -> row.id() != null && row.id() > 0 && row.id().toString().equals(id) && "ACTIVE".equals(row.status()))
.findFirst().orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "请选择有效客户"));
} catch (ResponseStatusException error) { throw error; }
catch (RuntimeException error) {
throw new ResponseStatusException(HttpStatus.SERVICE_UNAVAILABLE, "客户目录暂不可用,请稍后重试");
}
}
}
@@ -0,0 +1,19 @@
package com.baiyue.lastleg.service.reference;
import com.baiyue.common.core.api.ApiResponse;
import com.baiyue.common.core.api.PageResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
/** IAM owns customer references used to fill return-order snapshots. */
@FeignClient(name = "iam-service", contextId = "returnCustomerReferenceClient", url = "${baiyue.clients.iam.url:}")
public interface ReturnCustomerReferenceClient {
@GetMapping("/internal/iam/finance-customers")
ApiResponse<PageResult<Customer>> customers(@RequestHeader("X-Internal-Service-Token") String token,
@RequestParam("page") long page, @RequestParam("size") long size, @RequestParam("keyword") String keyword,
@RequestParam("status") String status, @RequestParam("customerId") Long customerId);
record Customer(Long id, String tenantCode, String tenantName, String status, String contactName, String contactPhone) { }
}