提交
This commit is contained in:
@@ -920,6 +920,25 @@ DELIMITER ;
|
||||
CALL assert_phase4_pda_operations_ready();
|
||||
DROP PROCEDURE assert_phase4_pda_operations_ready;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_order_fee (
|
||||
id BIGINT NOT NULL COMMENT '费用明细主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键',
|
||||
order_id BIGINT NOT NULL COMMENT '尾程订单ID', fee_item VARCHAR(128) NOT NULL COMMENT '费用项目',
|
||||
currency VARCHAR(3) NOT NULL COMMENT '币种代码', amount DECIMAL(18,2) NOT NULL COMMENT '费用金额',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'PENDING_REVIEW' COMMENT '费用状态:PENDING_REVIEW待审核、APPROVED审核通过、REJECTED已驳回',
|
||||
supplier_description VARCHAR(500) NULL COMMENT '供应商或费用说明', created_by VARCHAR(128) NOT NULL COMMENT '创建操作人',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||
PRIMARY KEY(id), KEY idx_ll_order_fee_customer_order(customer_id,order_id,created_at)
|
||||
) ENGINE=InnoDB COMMENT='尾程订单费用明细';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_order_operation_log (
|
||||
id BIGINT NOT NULL COMMENT '操作记录主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键',
|
||||
order_id BIGINT NOT NULL COMMENT '尾程订单ID', operation_node VARCHAR(64) NOT NULL COMMENT '操作节点',
|
||||
operator_name VARCHAR(128) NOT NULL COMMENT '操作人名称', result VARCHAR(500) NOT NULL COMMENT '处理结果',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间',
|
||||
PRIMARY KEY(id), KEY idx_ll_order_operation_customer_order(customer_id,order_id,created_at)
|
||||
) ENGINE=InnoDB COMMENT='尾程订单操作记录';
|
||||
|
||||
CREATE DATABASE IF NOT EXISTS baiyue_overseas_security DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||||
USE baiyue_overseas_security;
|
||||
CREATE TABLE IF NOT EXISTS overseas_security_event_inbox (
|
||||
|
||||
+16
@@ -7,6 +7,7 @@ import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.dto.LastlegOrderDetailResponse;
|
||||
import com.baiyue.lastleg.dto.LastlegOrderRequests;
|
||||
import com.baiyue.lastleg.dto.LastlegOrderSummary;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderFee;
|
||||
import com.baiyue.lastleg.security.InternalServiceTokenGuard;
|
||||
import com.baiyue.lastleg.security.OverseasPermissions;
|
||||
import com.baiyue.lastleg.service.LastlegOrderService;
|
||||
@@ -81,6 +82,17 @@ public class LastlegOrderController {
|
||||
return ApiResponse.success(orderService.detail(platformScope(user, customerId), id));
|
||||
}
|
||||
|
||||
@PostMapping("/api/platform/v1/last-leg/orders/{id}/fees")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.LAST_MILE_ORDER_EDIT + "')")
|
||||
@Operation(summary = "Add a fee to one tail-leg order", description = "Required authority: " + OverseasPermissions.LAST_MILE_ORDER_EDIT)
|
||||
public ApiResponse<LastlegOrderFee> createFee(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam(required = false) String customerId,
|
||||
@PathVariable long id,
|
||||
@Valid @RequestBody LastlegOrderRequests.CreateFee request) {
|
||||
return ApiResponse.success(orderService.createFee(platformScope(user, customerId), id, request, operatorName(user)));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/api/platform/v1/last-leg/orders/export", produces = "text/csv")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.LAST_MILE_ORDER_EXPORT + "')")
|
||||
@Operation(summary = "Export filtered tail-leg orders as UTF-8 CSV", description = "Required authority: " + OverseasPermissions.LAST_MILE_ORDER_EXPORT)
|
||||
@@ -126,4 +138,8 @@ public class LastlegOrderController {
|
||||
return requestedCustomer == null || requestedCustomer.isBlank() || "0".equals(requestedCustomer)
|
||||
? null : requestedCustomer.trim();
|
||||
}
|
||||
|
||||
private String operatorName(AuthenticatedUser user) {
|
||||
return user.username() == null || user.username().isBlank() ? String.valueOf(user.userId()) : user.username();
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -1,6 +1,7 @@
|
||||
package com.baiyue.lastleg.dto;
|
||||
|
||||
import com.baiyue.lastleg.entity.LastlegOrderDetail;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderFee;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@@ -9,7 +10,10 @@ import java.util.List;
|
||||
public record LastlegOrderDetailResponse(
|
||||
LastlegOrderSummary order,
|
||||
List<LastlegOrderDetail> cargo,
|
||||
List<History> statusHistory
|
||||
List<History> statusHistory,
|
||||
List<LastlegOrderFee> fees,
|
||||
List<Operation> operationHistory
|
||||
) {
|
||||
public record History(Long id, String fromStatus, String toStatus, String remark, LocalDateTime createdAt) {}
|
||||
public record Operation(Long id, String operationNode, String operatorName, String result, LocalDateTime createdAt) {}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,11 @@ import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@@ -55,4 +59,13 @@ public final class LastlegOrderRequests {
|
||||
return new TransferDestination(List.of(orderId), warehouseId, warehouseCode, warehouseName, remark);
|
||||
}
|
||||
}
|
||||
|
||||
public record CreateFee(
|
||||
@NotBlank @Size(max = 128) String feeItem,
|
||||
@NotBlank @Pattern(regexp = "[A-Z]{3}") String currency,
|
||||
@NotNull @DecimalMin(value = "0.01") BigDecimal amount,
|
||||
@NotBlank @Pattern(regexp = "PENDING_REVIEW|APPROVED|REJECTED") String status,
|
||||
@Size(max = 500) String supplierDescription
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.baiyue.lastleg.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("ll_order_fee")
|
||||
public class LastlegOrderFee {
|
||||
@TableId(type = IdType.INPUT) private Long id;
|
||||
private String customerId;
|
||||
private Long orderId;
|
||||
private String feeItem;
|
||||
private String currency;
|
||||
private BigDecimal amount;
|
||||
private String status;
|
||||
private String supplierDescription;
|
||||
private String createdBy;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.baiyue.lastleg.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("ll_order_operation_log")
|
||||
public class LastlegOrderOperationLog {
|
||||
@TableId(type = IdType.INPUT) private Long id;
|
||||
private String customerId;
|
||||
private Long orderId;
|
||||
private String operationNode;
|
||||
private String operatorName;
|
||||
private String result;
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.baiyue.lastleg.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderFee;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface LastlegOrderFeeMapper extends BaseMapper<LastlegOrderFee> {
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.baiyue.lastleg.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderOperationLog;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface LastlegOrderOperationLogMapper extends BaseMapper<LastlegOrderOperationLog> {
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.baiyue.lastleg.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.lastleg.dto.LastlegOrderDetailResponse;
|
||||
@@ -9,11 +10,15 @@ import com.baiyue.lastleg.dto.LastlegOrderSummary;
|
||||
import com.baiyue.lastleg.entity.LastlegOrder;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderDetail;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderStatusHistory;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderFee;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderOperationLog;
|
||||
import com.baiyue.lastleg.inboundplan.entity.InboundPlanCarton;
|
||||
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanCartonMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderDetailMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderStatusHistoryMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderFeeMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderOperationLogMapper;
|
||||
import com.baiyue.lastleg.model.LastlegOrderType;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -37,6 +42,8 @@ public class LastlegOrderService {
|
||||
@Resource private LastlegOrderMapper orderMapper;
|
||||
@Resource private LastlegOrderDetailMapper detailMapper;
|
||||
@Resource private LastlegOrderStatusHistoryMapper historyMapper;
|
||||
@Resource private LastlegOrderFeeMapper feeMapper;
|
||||
@Resource private LastlegOrderOperationLogMapper operationLogMapper;
|
||||
@Resource private InboundPlanCartonMapper cartonMapper;
|
||||
|
||||
public PageResult<LastlegOrderSummary> page(String customerId, LastlegOrderRequests.Query query) {
|
||||
@@ -56,9 +63,51 @@ public class LastlegOrderService {
|
||||
.eq(LastlegOrderStatusHistory::getCustomerId, order.getCustomerId())
|
||||
.eq(LastlegOrderStatusHistory::getOrderId, orderId)
|
||||
.orderByAsc(LastlegOrderStatusHistory::getCreatedAt));
|
||||
List<LastlegOrderFee> fees = feeMapper.selectList(new LambdaQueryWrapper<LastlegOrderFee>()
|
||||
.eq(LastlegOrderFee::getCustomerId, order.getCustomerId())
|
||||
.eq(LastlegOrderFee::getOrderId, orderId).orderByAsc(LastlegOrderFee::getCreatedAt));
|
||||
List<LastlegOrderOperationLog> operations = operationLogMapper.selectList(
|
||||
new LambdaQueryWrapper<LastlegOrderOperationLog>()
|
||||
.eq(LastlegOrderOperationLog::getCustomerId, order.getCustomerId())
|
||||
.eq(LastlegOrderOperationLog::getOrderId, orderId)
|
||||
.orderByAsc(LastlegOrderOperationLog::getCreatedAt));
|
||||
return new LastlegOrderDetailResponse(summary(order), cargo, history.stream()
|
||||
.map(value -> new LastlegOrderDetailResponse.History(value.getId(), value.getFromStatus(),
|
||||
value.getToStatus(), value.getRemark(), value.getCreatedAt())).toList());
|
||||
value.getToStatus(), value.getRemark(), value.getCreatedAt())).toList(), fees, operations.stream()
|
||||
.map(value -> new LastlegOrderDetailResponse.Operation(value.getId(), value.getOperationNode(),
|
||||
value.getOperatorName(), value.getResult(), value.getCreatedAt())).toList());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public LastlegOrderFee createFee(String customerId, long orderId, LastlegOrderRequests.CreateFee request,
|
||||
String operatorName) {
|
||||
LastlegOrder order = findOwned(customerId, orderId);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
LastlegOrderFee fee = new LastlegOrderFee();
|
||||
fee.setId(IdWorker.getId());
|
||||
fee.setCustomerId(order.getCustomerId());
|
||||
fee.setOrderId(orderId);
|
||||
fee.setFeeItem(request.feeItem().trim());
|
||||
fee.setCurrency(request.currency());
|
||||
fee.setAmount(request.amount());
|
||||
fee.setStatus(request.status());
|
||||
fee.setSupplierDescription(StringUtils.hasText(request.supplierDescription())
|
||||
? request.supplierDescription().trim() : null);
|
||||
fee.setCreatedBy(operatorName);
|
||||
fee.setCreatedAt(now);
|
||||
fee.setUpdatedAt(now);
|
||||
feeMapper.insert(fee);
|
||||
|
||||
LastlegOrderOperationLog operation = new LastlegOrderOperationLog();
|
||||
operation.setId(IdWorker.getId());
|
||||
operation.setCustomerId(order.getCustomerId());
|
||||
operation.setOrderId(orderId);
|
||||
operation.setOperationNode("新增费用");
|
||||
operation.setOperatorName(operatorName);
|
||||
operation.setResult("新增" + fee.getFeeItem() + ":" + fee.getCurrency() + " " + fee.getAmount().toPlainString());
|
||||
operation.setCreatedAt(now);
|
||||
operationLogMapper.insert(operation);
|
||||
return fee;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
|
||||
@@ -137,6 +137,34 @@ CREATE TABLE IF NOT EXISTS ll_loading_order_status_history (
|
||||
KEY idx_ll_loading_history_customer_order(customer_id,order_id,created_at)
|
||||
) ENGINE=InnoDB COMMENT='尾程订单状态变更历史';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_order_fee (
|
||||
id BIGINT NOT NULL COMMENT '费用明细主键',
|
||||
customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键',
|
||||
order_id BIGINT NOT NULL COMMENT '尾程订单ID',
|
||||
fee_item VARCHAR(128) NOT NULL COMMENT '费用项目',
|
||||
currency VARCHAR(3) NOT NULL COMMENT '币种代码',
|
||||
amount DECIMAL(18,2) NOT NULL COMMENT '费用金额',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'PENDING_REVIEW' COMMENT '费用状态:PENDING_REVIEW待审核、APPROVED审核通过、REJECTED已驳回',
|
||||
supplier_description VARCHAR(500) NULL COMMENT '供应商或费用说明',
|
||||
created_by VARCHAR(128) NOT NULL COMMENT '创建操作人',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||
PRIMARY KEY(id),
|
||||
KEY idx_ll_order_fee_customer_order(customer_id,order_id,created_at)
|
||||
) ENGINE=InnoDB COMMENT='尾程订单费用明细';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_order_operation_log (
|
||||
id BIGINT NOT NULL COMMENT '操作记录主键',
|
||||
customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键',
|
||||
order_id BIGINT NOT NULL COMMENT '尾程订单ID',
|
||||
operation_node VARCHAR(64) NOT NULL COMMENT '操作节点',
|
||||
operator_name VARCHAR(128) NOT NULL COMMENT '操作人名称',
|
||||
result VARCHAR(500) NOT NULL COMMENT '处理结果',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间',
|
||||
PRIMARY KEY(id),
|
||||
KEY idx_ll_order_operation_customer_order(customer_id,order_id,created_at)
|
||||
) ENGINE=InnoDB COMMENT='尾程订单操作记录';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_event_conflict (
|
||||
id BIGINT NOT NULL COMMENT '冲突记录主键', event_id VARCHAR(128) NOT NULL COMMENT '冲突事件 ID',
|
||||
customer_id BIGINT NOT NULL COMMENT '租户 ID', conflict_type VARCHAR(64) NOT NULL COMMENT '冲突类型',
|
||||
|
||||
@@ -138,6 +138,29 @@ paths:
|
||||
- { name: createdFrom, in: query, schema: { type: string, format: date-time } }
|
||||
- { name: createdTo, in: query, schema: { type: string, format: date-time } }
|
||||
responses: { '200': { description: 统一 ApiResponse 包装的尾程订单分页;列表行 destinationType 为 FBA 或 OVERSEAS } }
|
||||
/api/platform/v1/last-leg/orders/{id}:
|
||||
get:
|
||||
summary: 查询尾程订单详情
|
||||
description: 权限 platform:overseas-warehouse:last-mile-order:list;返回订单、货物、状态历史、费用明细和操作记录。
|
||||
security: [{ bearerAuth: [] }]
|
||||
parameters:
|
||||
- { name: id, in: path, required: true, schema: { type: integer, format: int64 } }
|
||||
responses:
|
||||
'200': { description: 统一 ApiResponse 包装的尾程订单详情 }
|
||||
'404': { description: 尾程订单不存在或不属于查询客户 }
|
||||
/api/platform/v1/last-leg/orders/{id}/fees:
|
||||
post:
|
||||
summary: 新增尾程订单费用
|
||||
description: 权限 platform:overseas-warehouse:last-mile-order:edit;在订单客户范围内新增费用并记录操作人和处理结果。
|
||||
security: [{ bearerAuth: [] }]
|
||||
parameters:
|
||||
- { name: id, in: path, required: true, schema: { type: integer, format: int64 } }
|
||||
requestBody:
|
||||
required: true
|
||||
content: { application/json: { schema: { $ref: '#/components/schemas/LastMileFeeCreate' } } }
|
||||
responses:
|
||||
'200': { description: 新增后的费用明细, content: { application/json: { schema: { $ref: '#/components/schemas/LastMileFeeApiResponse' } } } }
|
||||
'404': { description: 尾程订单不存在或不属于操作客户 }
|
||||
/api/platform/v1/last-leg/dispatches:
|
||||
get:
|
||||
summary: 分页查询排车单
|
||||
@@ -513,6 +536,37 @@ paths:
|
||||
responses: { '200': { description: 统一 ApiResponse 包装的换标单详情 }, '409': { description: 非法状态迁移或关联尾程单缺失 } }
|
||||
components:
|
||||
schemas:
|
||||
LastMileFeeCreate:
|
||||
type: object
|
||||
required: [feeItem, currency, amount, status]
|
||||
properties:
|
||||
feeItem: { type: string, minLength: 1, maxLength: 128 }
|
||||
currency: { type: string, pattern: '^[A-Z]{3}$', example: USD }
|
||||
amount: { type: number, format: decimal, minimum: 0.01 }
|
||||
status: { type: string, enum: [PENDING_REVIEW, APPROVED, REJECTED] }
|
||||
supplierDescription: { type: string, maxLength: 500 }
|
||||
LastMileFee:
|
||||
type: object
|
||||
required: [id, customerId, orderId, feeItem, currency, amount, status, createdBy, createdAt, updatedAt]
|
||||
properties:
|
||||
id: { type: integer, format: int64 }
|
||||
customerId: { type: string }
|
||||
orderId: { type: integer, format: int64 }
|
||||
feeItem: { type: string }
|
||||
currency: { type: string }
|
||||
amount: { type: number, format: decimal }
|
||||
status: { type: string }
|
||||
supplierDescription: { type: string, nullable: true }
|
||||
createdBy: { type: string }
|
||||
createdAt: { type: string, format: date-time }
|
||||
updatedAt: { type: string, format: date-time }
|
||||
LastMileFeeApiResponse:
|
||||
type: object
|
||||
required: [code, message, data]
|
||||
properties:
|
||||
code: { type: string }
|
||||
message: { type: string }
|
||||
data: { $ref: '#/components/schemas/LastMileFee' }
|
||||
PdaWarehouseScan:
|
||||
type: object
|
||||
required: [code]
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.baiyue.lastleg.inboundplan.mapper.InboundPlanCartonMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderDetailMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderStatusHistoryMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderFeeMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderOperationLogMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -19,6 +21,7 @@ import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
@@ -33,6 +36,8 @@ class LastlegOrderServiceTest {
|
||||
@Mock LastlegOrderMapper orders;
|
||||
@Mock LastlegOrderDetailMapper details;
|
||||
@Mock LastlegOrderStatusHistoryMapper histories;
|
||||
@Mock LastlegOrderFeeMapper fees;
|
||||
@Mock LastlegOrderOperationLogMapper operations;
|
||||
@Mock InboundPlanCartonMapper cartons;
|
||||
LastlegOrderService service;
|
||||
|
||||
@@ -42,6 +47,8 @@ class LastlegOrderServiceTest {
|
||||
ReflectionTestUtils.setField(service, "orderMapper", orders);
|
||||
ReflectionTestUtils.setField(service, "detailMapper", details);
|
||||
ReflectionTestUtils.setField(service, "historyMapper", histories);
|
||||
ReflectionTestUtils.setField(service, "feeMapper", fees);
|
||||
ReflectionTestUtils.setField(service, "operationLogMapper", operations);
|
||||
ReflectionTestUtils.setField(service, "cartonMapper", cartons);
|
||||
}
|
||||
|
||||
@@ -52,6 +59,8 @@ class LastlegOrderServiceTest {
|
||||
when(orders.selectOne(any())).thenReturn(order);
|
||||
when(details.selectList(any())).thenReturn(List.of());
|
||||
when(histories.selectList(any())).thenReturn(List.of());
|
||||
when(fees.selectList(any())).thenReturn(List.of());
|
||||
when(operations.selectList(any())).thenReturn(List.of());
|
||||
|
||||
var response = service.detail("100", 11L);
|
||||
|
||||
@@ -91,6 +100,21 @@ class LastlegOrderServiceTest {
|
||||
assertEquals("DESTINATION_ASSIGNED", history.getValue().getToStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createFeePersistsFeeAndOperationForOwnedOrder() {
|
||||
when(orders.selectOne(any())).thenReturn(order(11L, "100", "PENDING_ASSIGNMENT", null));
|
||||
var request = new LastlegOrderRequests.CreateFee(
|
||||
"清关费", "USD", new BigDecimal("420.00"), "PENDING_REVIEW", "报关代理");
|
||||
|
||||
var fee = service.createFee("100", 11L, request, "platform_admin");
|
||||
|
||||
assertEquals("100", fee.getCustomerId());
|
||||
assertEquals("清关费", fee.getFeeItem());
|
||||
assertEquals(new BigDecimal("420.00"), fee.getAmount());
|
||||
verify(fees).insert(any());
|
||||
verify(operations).insert(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void transferRejectsAnOrderAlreadyBoundToInboundPlan() {
|
||||
LastlegOrder order = order(11L, "100", "DESTINATION_ASSIGNED", "IB-1");
|
||||
|
||||
@@ -3824,3 +3824,21 @@ SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE tab
|
||||
AND table_name='ll_cargo_discard_application' AND column_name='review_request_hash'),
|
||||
'SELECT 1', 'ALTER TABLE ll_cargo_discard_application ADD COLUMN review_request_hash CHAR(64) NULL COMMENT ''审核请求内容哈希'' AFTER review_idempotency_key'));
|
||||
PREPARE phase4_discard_review_stmt FROM @ddl; EXECUTE phase4_discard_review_stmt; DEALLOCATE PREPARE phase4_discard_review_stmt;
|
||||
CREATE TABLE IF NOT EXISTS ll_order_fee (
|
||||
id BIGINT NOT NULL COMMENT '费用明细主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键',
|
||||
order_id BIGINT NOT NULL COMMENT '尾程订单ID', fee_item VARCHAR(128) NOT NULL COMMENT '费用项目',
|
||||
currency VARCHAR(3) NOT NULL COMMENT '币种代码', amount DECIMAL(18,2) NOT NULL COMMENT '费用金额',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'PENDING_REVIEW' COMMENT '费用状态:PENDING_REVIEW待审核、APPROVED审核通过、REJECTED已驳回',
|
||||
supplier_description VARCHAR(500) NULL COMMENT '供应商或费用说明', created_by VARCHAR(128) NOT NULL COMMENT '创建操作人',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||
PRIMARY KEY(id), KEY idx_ll_order_fee_customer_order(customer_id,order_id,created_at)
|
||||
) ENGINE=InnoDB COMMENT='尾程订单费用明细';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_order_operation_log (
|
||||
id BIGINT NOT NULL COMMENT '操作记录主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键',
|
||||
order_id BIGINT NOT NULL COMMENT '尾程订单ID', operation_node VARCHAR(64) NOT NULL COMMENT '操作节点',
|
||||
operator_name VARCHAR(128) NOT NULL COMMENT '操作人名称', result VARCHAR(500) NOT NULL COMMENT '处理结果',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间',
|
||||
PRIMARY KEY(id), KEY idx_ll_order_operation_customer_order(customer_id,order_id,created_at)
|
||||
) ENGINE=InnoDB COMMENT='尾程订单操作记录';
|
||||
|
||||
Reference in New Issue
Block a user