Merge branch 'test' into test-02huogui
# Conflicts: # deploy/sql/头程数据库统一增量-MySQL8.sql # firstleg/src/main/java/com/baiyue/firstleg/BaiyueFirstlegApplication.java # firstleg/src/main/resources/openapi/firstleg-v1.yaml
This commit is contained in:
@@ -29,7 +29,7 @@ public interface FirstlegInboundClient {
|
||||
}
|
||||
|
||||
record OrderApprovedInboundCommand(
|
||||
long tenantId, long orderId, String orderNo, Long customerId, String customerName,
|
||||
long tenantId, long orderId, String orderNo, String inboundCode, Long customerId, String customerName,
|
||||
Long warehouseId, String warehouseName, Long deliveryWarehouseId, String deliveryWarehouseName,
|
||||
LocalDateTime expectedArrivalAt, String businessType, String channelCode, String channelName,
|
||||
Long carrierId, String carrierName, String taxMode, String containerMode,
|
||||
|
||||
+14
-1
@@ -146,7 +146,7 @@ public class PlatformFirstLegOrderController {
|
||||
}
|
||||
|
||||
@BusinessAudit(event = "ORDER_APPROVE", resourceType = "FIRST_LEG_ORDER", resourceId = "#id", description = "Approve order / 审核通过")
|
||||
@Operation(summary = "Approve / 审核通过", description = "Approves a submitted order and records its status history. / 审核通过已提交订单,并记录状态历史。")
|
||||
@Operation(summary = "Approve / 审核通过", description = "Approves a submitted order without requiring carrier assignment and records its status history. / 审核通过已提交订单,不要求预先指派承运商,并记录状态历史。")
|
||||
@PostMapping("/{id}/approve")
|
||||
@PreAuthorize("hasAuthority('platform:order:approve')")
|
||||
public ApiResponse<Void> approve(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@@ -155,6 +155,19 @@ public class PlatformFirstLegOrderController {
|
||||
return transit(user, tenantId, id, OrderStatus.APPROVED, null);
|
||||
}
|
||||
|
||||
@BusinessAudit(event = "ORDER_ASSIGN_CARRIER", resourceType = "FIRST_LEG_ORDER", resourceId = "#id", description = "指派订单承运商")
|
||||
@Operation(summary = "指派承运商", description = "可选地为待审核订单选择启用的公共承运商,名称快照由服务端主数据回填;该动作不是审核前置条件。")
|
||||
@PutMapping("/{id}/carrier")
|
||||
@PreAuthorize("hasAuthority('platform:order:approve')")
|
||||
public ApiResponse<Void> assignCarrier(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@Parameter(description = "目标租户 ID", required = true) @RequestParam long tenantId,
|
||||
@Parameter(description = "订单 ID", required = true) @PathVariable long id,
|
||||
@Valid @RequestBody OrderRequests.CarrierRequest request) {
|
||||
long scopedTenant = OrderScopeGuard.platform(user, tenantId);
|
||||
service.assignCarrier(scopedTenant, user.userId(), id, request);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@BusinessAudit(event = "ORDER_REJECT", resourceType = "FIRST_LEG_ORDER", resourceId = "#id", description = "Reject order / 驳回订单")
|
||||
@Operation(summary = "Reject / 驳回", description = "Rejects a submitted order with a required reason. / 使用必填原因驳回已提交订单。")
|
||||
@PostMapping("/{id}/reject")
|
||||
|
||||
@@ -2,9 +2,12 @@ package com.baiyue.order.controller;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.audit.BusinessAudit;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.order.dto.UnifiedOrderQuery;
|
||||
import com.baiyue.order.dto.UnifiedOrderResponse;
|
||||
import com.baiyue.order.dto.OrderRequests;
|
||||
import com.baiyue.order.service.OrderApplicationService;
|
||||
import com.baiyue.order.service.OrderScopeGuard;
|
||||
import com.baiyue.order.service.UnifiedOrderQueryService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -17,6 +20,8 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/** Platform product-level order query. Legacy first-leg paths remain available. */
|
||||
@@ -25,6 +30,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequestMapping("/api/platform/v1/orders")
|
||||
public class PlatformUnifiedOrderController {
|
||||
@Resource private UnifiedOrderQueryService service;
|
||||
@Resource private OrderApplicationService orderService;
|
||||
|
||||
@GetMapping
|
||||
@PreAuthorize("hasAuthority('platform:order:list')")
|
||||
@@ -47,4 +53,17 @@ public class PlatformUnifiedOrderController {
|
||||
@PathVariable long orderId) {
|
||||
return ApiResponse.success(service.detail(OrderScopeGuard.platform(user, tenantId), orderId, true));
|
||||
}
|
||||
|
||||
@PostMapping("/{orderId}/internal-notes")
|
||||
@BusinessAudit(event = "ORDER_INTERNAL_NOTE", resourceType = "FIRST_LEG_ORDER", resourceId = "#orderId", description = "Add internal note / 添加内部备注")
|
||||
@PreAuthorize("hasAuthority('platform:order:note')")
|
||||
@Operation(summary = "添加订单内部备注", description = "添加仅平台内部可见的订单备注。")
|
||||
public ApiResponse<Long> addInternalNote(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam long tenantId,
|
||||
@PathVariable long orderId,
|
||||
@Valid @RequestBody OrderRequests.NoteRequest request) {
|
||||
long scopedTenant = OrderScopeGuard.platform(user, tenantId);
|
||||
return ApiResponse.success(orderService.addNote(scopedTenant, user.userId(), orderId, request.content()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.baiyue.order.dto;
|
||||
import com.baiyue.order.entity.OrderStatus;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.AssertTrue;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.Max;
|
||||
@@ -55,8 +56,10 @@ public final class OrderRequests {
|
||||
@NotBlank @Size(max = 128) String receivingWarehouseName,
|
||||
@NotBlank @Size(max = 64) String channelCode,
|
||||
@NotBlank @Size(max = 128) String channelName,
|
||||
@NotNull Long carrierId,
|
||||
@NotBlank @Size(max = 128) String carrierName,
|
||||
@Schema(description = "Carrier ID snapshot; optional until the order channel resolves a carrier / 承运商 ID 快照,渠道明确承运商后可传")
|
||||
@Min(1) Long carrierId,
|
||||
@Schema(description = "Carrier name snapshot; optional until the order channel resolves a carrier / 承运商名称快照,渠道明确承运商后可传", maxLength = 128)
|
||||
@Size(max = 128) String carrierName,
|
||||
@NotBlank @Pattern(regexp = "BUY_DECLARATION|TAX_REFUND") String taxMode,
|
||||
@Pattern(regexp = "FULL_CONTAINER|LCL") String containerMode,
|
||||
@NotNull Boolean customsInspection,
|
||||
@@ -64,6 +67,17 @@ public final class OrderRequests {
|
||||
@Size(max = 32) String amazonWarehouseCode,
|
||||
@Size(max = 64) String shipmentId,
|
||||
@Size(max = 64) String referenceId
|
||||
) {
|
||||
@AssertTrue(message = "承运商 ID 和名称必须同时填写或同时留空")
|
||||
public boolean isCarrierSnapshotComplete() {
|
||||
return (carrierId == null) == (carrierName == null || carrierName.isBlank());
|
||||
}
|
||||
}
|
||||
|
||||
@Schema(name = "FirstLegOrderCarrierRequest", description = "Platform carrier assignment / 平台指派承运商")
|
||||
public record CarrierRequest(
|
||||
@Schema(description = "Active public carrier ID / 启用的公共承运商 ID", example = "193000000000300001", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull @Min(1) Long carrierId
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ public class OrderEntity extends BaseEntity {
|
||||
private Long id;
|
||||
private Long tenantId;
|
||||
private String orderNo;
|
||||
private String inboundCode;
|
||||
private Long customerId;
|
||||
private String customerName;
|
||||
private OrderStatus status;
|
||||
|
||||
@@ -161,6 +161,7 @@ public class OrderRepository {
|
||||
.eq(tenantId != null, OrderEntity::getTenantId, tenantId)
|
||||
.in(OrderEntity::getStatus, statuses)
|
||||
.like(StringUtils.hasText(query.orderNo()), OrderEntity::getOrderNo, query.orderNo())
|
||||
.like(StringUtils.hasText(query.inboundCode()), OrderEntity::getInboundCode, query.inboundCode())
|
||||
.eq(query.customerId() != null, OrderEntity::getCustomerId, query.customerId())
|
||||
.eq(query.receivingWarehouseId() != null, OrderEntity::getReceivingWarehouseId,
|
||||
query.receivingWarehouseId())
|
||||
|
||||
@@ -73,6 +73,19 @@ public class OrderApplicationService {
|
||||
updateOrderData(tenantId, userId, id, request, true);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void assignCarrier(long tenantId, long userId, long id, OrderRequests.CarrierRequest request) {
|
||||
OrderEntity order = require(tenantId, id);
|
||||
if (order.getStatus() != OrderStatus.SUBMITTED) {
|
||||
throw new BizException(com.baiyue.common.core.api.ResultCode.CONFLICT, "仅待审核订单可以指派承运商");
|
||||
}
|
||||
var carrier = masterDataGuard.validateCarrier(request.carrierId());
|
||||
order.setCarrierId(carrier.id());
|
||||
order.setCarrierName(carrier.partnerName());
|
||||
order.setUpdatedBy(userId);
|
||||
if (repository.saveOrder(tenantId, order) != 1) throw new BizException("Concurrent order update");
|
||||
}
|
||||
|
||||
private void updateOrderData(long tenantId, long userId, long id, OrderRequests.SaveRequest request,
|
||||
boolean allowSubmitted) {
|
||||
OrderEntity order = require(tenantId, id);
|
||||
@@ -84,6 +97,7 @@ public class OrderApplicationService {
|
||||
throw new BizException("当前订单状态不允许编辑订单资料");
|
||||
}
|
||||
apply(order, request, snapshots); order.setStatus(OrderStatus.DRAFT); order.setUpdatedBy(userId);
|
||||
if (before == OrderStatus.REJECTED) order.setInboundCode(null);
|
||||
if (before == OrderStatus.SUBMITTED) {
|
||||
order.setStatus(OrderStatus.SUBMITTED);
|
||||
}
|
||||
@@ -105,11 +119,19 @@ public class OrderApplicationService {
|
||||
masterDataGuard.validatePersisted(tenantId, order.getCustomerId(), order.getReceivingWarehouseId(),
|
||||
order.getDestinationWarehouseId(), order.getDestinationType());
|
||||
}
|
||||
if (target == OrderStatus.APPROVED && order.getCarrierId() != null) {
|
||||
var carrier = masterDataGuard.validateCarrier(order.getCarrierId());
|
||||
order.setCarrierName(carrier.partnerName());
|
||||
}
|
||||
if ((target == OrderStatus.REJECTED || target == OrderStatus.CANCELLED) && !StringUtils.hasText(reason)) {
|
||||
throw new BizException("Reason is required");
|
||||
}
|
||||
order.setStatus(target); order.setUpdatedBy(userId);
|
||||
if (target == OrderStatus.SUBMITTED) order.setSubmittedAt(LocalDateTime.now());
|
||||
if (target == OrderStatus.SUBMITTED) {
|
||||
if (!StringUtils.hasText(order.getInboundCode())) order.setInboundCode("RK-" + order.getId());
|
||||
order.setSubmittedAt(LocalDateTime.now());
|
||||
}
|
||||
if (target == OrderStatus.DRAFT) order.setInboundCode(null);
|
||||
if (target == OrderStatus.COMPLETED) order.setCompletedAt(LocalDateTime.now());
|
||||
if (repository.saveOrder(tenantId, order) != 1) throw new BizException("Concurrent order update");
|
||||
record(tenantId, id, from, target, target.name(), reason, userId, username);
|
||||
@@ -327,7 +349,9 @@ public class OrderApplicationService {
|
||||
order.setReceivingTime(formatReceivingTime(snapshots.receiving()));
|
||||
order.setChannelCode(request.channelCode());
|
||||
order.setChannelName(request.channelName());
|
||||
order.setCarrierId(request.carrierId()); order.setCarrierName(request.carrierName());
|
||||
order.setCarrierId(request.carrierId());
|
||||
order.setCarrierName(request.carrierId() == null || !StringUtils.hasText(request.carrierName())
|
||||
? null : request.carrierName().trim());
|
||||
order.setTaxMode(request.taxMode());
|
||||
order.setContainerMode(request.containerMode()); order.setCustomsInspection(request.customsInspection());
|
||||
order.setDestinationType(request.destinationType());
|
||||
@@ -400,7 +424,8 @@ public class OrderApplicationService {
|
||||
}
|
||||
private FirstlegInboundClient.OrderApprovedInboundCommand inboundCommand(OrderEntity order) {
|
||||
return new FirstlegInboundClient.OrderApprovedInboundCommand(
|
||||
order.getTenantId(), order.getId(), order.getOrderNo(), order.getCustomerId(), order.getCustomerName(),
|
||||
order.getTenantId(), order.getId(), order.getOrderNo(), order.getInboundCode(),
|
||||
order.getCustomerId(), order.getCustomerName(),
|
||||
order.getReceivingWarehouseId(), order.getReceivingWarehouseName(), order.getDestinationWarehouseId(),
|
||||
order.getDestinationWarehouseName(), order.getExpectedShipDate() == null ? null : order.getExpectedShipDate().atStartOfDay(),
|
||||
order.getDestinationType() + "_" + order.getTransportMode(), order.getChannelCode(), order.getChannelName(),
|
||||
|
||||
@@ -78,6 +78,37 @@ public class OrderMasterDataGuard {
|
||||
throw downstreamFailure(exception);
|
||||
}
|
||||
}
|
||||
public PartnerClient.Partner validateCarrier(long id) {
|
||||
try {
|
||||
ApiResponse<PartnerClient.Partner> response;
|
||||
try {
|
||||
response = partners.active(token, publicTenantId, id);
|
||||
} catch (FeignException.NotFound exception) {
|
||||
throw new BizException(ResultCode.NOT_FOUND, "承运商不存在或不可用");
|
||||
}
|
||||
requireSuccessful(response, "承运商");
|
||||
if (response.data() == null) throw unavailable("承运商");
|
||||
var value = response.data();
|
||||
if (!Long.valueOf(id).equals(value.id())) throw unavailable("承运商");
|
||||
if (!Long.valueOf(publicTenantId).equals(value.tenantId()))
|
||||
throw new BizException(ResultCode.FORBIDDEN, "承运商不属于平台公共主数据");
|
||||
if (!"ACTIVE".equals(value.status()))
|
||||
throw new BizException(ResultCode.CONFLICT, "承运商已停用");
|
||||
boolean hasCarrierType = value.types() != null && value.types().contains("CARRIER");
|
||||
boolean legacyCarrierType = (value.types() == null || value.types().isEmpty())
|
||||
&& "CARRIER".equals(value.partnerType());
|
||||
if (!hasCarrierType && !legacyCarrierType)
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED, "所选往来单位不具备承运商类型");
|
||||
if (!StringUtils.hasText(value.partnerName())) throw unavailable("承运商");
|
||||
return value;
|
||||
} catch (FeignException exception) {
|
||||
throw downstreamFailure(exception);
|
||||
} catch (BizException exception) {
|
||||
throw exception;
|
||||
} catch (RuntimeException exception) {
|
||||
throw downstreamFailure(exception);
|
||||
}
|
||||
}
|
||||
private PartnerClient.Partner loadPartner(long id) {
|
||||
ApiResponse<PartnerClient.Partner> response;
|
||||
try {
|
||||
|
||||
@@ -51,8 +51,9 @@ public class UnifiedOrderQueryService {
|
||||
List<OrderStatus> statuses = "PENDING_REVIEW".equals(query.mainStatus())
|
||||
? List.of(OrderStatus.SUBMITTED) : ACTIVE_ORDER_STATUSES;
|
||||
PageResult<OrderEntity> source = orders.unifiedPage(tenantId, query, statuses);
|
||||
Map<Long, FirstlegUnifiedOrderClient.Summary> inboundByOrder = summaries(
|
||||
tenantId, source.records().stream().map(OrderEntity::getId).toList());
|
||||
Map<Long, FirstlegUnifiedOrderClient.Summary> inboundByOrder = "PENDING_REVIEW".equals(query.mainStatus())
|
||||
? Map.of()
|
||||
: summaries(tenantId, source.records().stream().map(OrderEntity::getId).toList());
|
||||
List<UnifiedOrderResponse.Row> rows = source.records().stream()
|
||||
.map(order -> row(order, inboundByOrder.get(order.getId()))).toList();
|
||||
return new PageResult<>(rows, source.page(), source.size(), source.total(), source.pages());
|
||||
@@ -64,7 +65,8 @@ public class UnifiedOrderQueryService {
|
||||
OrderDetailResponse orderDetail = new OrderDetailResponse(order, orders.findCargo(tenantId, orderId),
|
||||
orders.findParties(tenantId, orderId), includeInternalNotes ? orders.findNotes(tenantId, orderId) : List.of(),
|
||||
orders.findHistory(tenantId, orderId));
|
||||
FirstlegUnifiedOrderClient.Detail inbound = firstlegDetail(tenantId, orderId);
|
||||
FirstlegUnifiedOrderClient.Detail inbound = order.getStatus() == OrderStatus.SUBMITTED
|
||||
? null : firstlegDetail(tenantId, orderId);
|
||||
UnifiedOrderResponse.Row summary = row(order, inbound == null ? null : inbound.summary());
|
||||
List<UnifiedOrderResponse.TimelineEvent> timeline = new ArrayList<>();
|
||||
orderDetail.statusHistory().forEach(item -> timeline.add(new UnifiedOrderResponse.TimelineEvent(
|
||||
@@ -121,7 +123,8 @@ public class UnifiedOrderQueryService {
|
||||
order.getStatus() == OrderStatus.SUBMITTED ? "APPROVE_ORDER" : null,
|
||||
order.getStatus(), order.getCustomerId(), order.getCustomerName(),
|
||||
order.getChannelName(), order.getReceivingWarehouseId(), order.getReceivingWarehouseName(),
|
||||
order.getDestinationWarehouseId(), order.getDestinationWarehouseName(), null, null, null,
|
||||
order.getDestinationWarehouseId(), order.getDestinationWarehouseName(), null, null,
|
||||
order.getInboundCode(),
|
||||
order.getExpectedShipDate(), null, null, null, null, null, null, null, null,
|
||||
order.getCreatedAt(), order.getUpdatedAt());
|
||||
}
|
||||
@@ -213,7 +216,7 @@ public class UnifiedOrderQueryService {
|
||||
|
||||
private boolean requiresFirstlegQuery(UnifiedOrderQuery query) {
|
||||
return (StringUtils.hasText(query.mainStatus()) && !"PENDING_REVIEW".equals(query.mainStatus()))
|
||||
|| StringUtils.hasText(query.inboundCode()) || query.expectedArrivalDate() != null
|
||||
|| query.expectedArrivalDate() != null
|
||||
|| StringUtils.hasText(query.feeReviewStatus()) || StringUtils.hasText(query.containerNo())
|
||||
|| StringUtils.hasText(query.cabinetNo()) || query.sailingDate() != null || query.loaded() != null
|
||||
|| StringUtils.hasText(query.measurementReviewStatus());
|
||||
|
||||
@@ -9,6 +9,7 @@ CREATE TABLE IF NOT EXISTS ord_order (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '订单ID(雪花ID)',
|
||||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||||
order_no VARCHAR(32) NOT NULL COMMENT '租户内唯一订单号',
|
||||
inbound_code VARCHAR(40) NULL COMMENT '客户提交后生成的入仓码,草稿为空',
|
||||
customer_id BIGINT UNSIGNED NULL COMMENT '客户逻辑ID',
|
||||
customer_name VARCHAR(128) NOT NULL COMMENT '下单时客户名称快照',
|
||||
status VARCHAR(24) NOT NULL DEFAULT 'DRAFT' COMMENT '订单业务状态',
|
||||
@@ -47,6 +48,7 @@ CREATE TABLE IF NOT EXISTS ord_order (
|
||||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_order_tenant_no (tenant_id, order_no),
|
||||
UNIQUE KEY uk_order_tenant_inbound_code (tenant_id, inbound_code),
|
||||
KEY idx_order_tenant_status_time (tenant_id, status, created_at),
|
||||
KEY idx_order_tenant_customer (tenant_id, customer_id),
|
||||
KEY idx_order_tenant_warehouse (tenant_id, destination_warehouse_id)
|
||||
|
||||
@@ -2,7 +2,7 @@ openapi: 3.0.3
|
||||
info:
|
||||
title: 柏悦头程订单 API
|
||||
description: 业务成功和失败均使用 HTTP 200;仅响应体 code 为字符串 "200" 时表示成功,其他 code 表示失败。
|
||||
version: 1.3.0
|
||||
version: 1.4.0
|
||||
security:
|
||||
- bearerAuth: []
|
||||
paths:
|
||||
@@ -11,7 +11,8 @@ paths:
|
||||
summary: 平台统一订单列表
|
||||
description: >-
|
||||
统一返回七态产品主状态、下一步动作及测量/预装/装柜/派送摘要,需要 platform:order:list。
|
||||
有入库单时同时返回 inboundId、inboundVersion、loadingVersion、pickingVersion;inboundVersion
|
||||
草稿不生成 inboundCode,客户提交进入待审核后即返回固定 inboundCode;有入库单时同时返回
|
||||
inboundId、inboundVersion、loadingVersion、pickingVersion;inboundVersion
|
||||
才是 C04 loading/complete 的 expectedVersion,loadingVersion 当前等于 pickingVersion(兼容别名)。
|
||||
tenantId 省略时跨全部客户;mainStatus 省略时按订单创建时间分页,指定 PENDING_REVIEW 时由 Order 查询,
|
||||
指定其他主状态时由 Firstleg 精确分页。旧 /orders/first-leg 接口保持兼容。
|
||||
@@ -45,13 +46,32 @@ paths:
|
||||
/api/platform/v1/orders/{orderId}:
|
||||
get:
|
||||
summary: 平台统一订单详情
|
||||
description: 合并 Order 与 Firstleg 时间线并按发生时间升序返回;平台可见内部备注。
|
||||
description: 合并 Order 与 Firstleg 时间线并按发生时间升序返回;待审核订单直接返回 Order 在提交时生成的 inboundCode;平台可见内部备注。
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/UnifiedOrderId'
|
||||
- $ref: '#/components/parameters/UnifiedTenantId'
|
||||
responses:
|
||||
'200': {description: 成功或业务失败,按响应体 code 判断}
|
||||
'403': {description: 需要平台身份和 platform:order:list 权限}
|
||||
/api/platform/v1/orders/{orderId}/internal-notes:
|
||||
post:
|
||||
summary: 添加订单内部备注
|
||||
description: 添加仅平台内部可见的订单备注,需要 platform:order:note 权限。
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/UnifiedOrderId'
|
||||
- $ref: '#/components/parameters/UnifiedTenantId'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [content]
|
||||
properties:
|
||||
content: {type: string, minLength: 1, maxLength: 2000}
|
||||
responses:
|
||||
'200': {description: 备注添加成功或业务失败,按响应体 code 判断}
|
||||
'403': {description: 需要 platform:order:note 权限}
|
||||
/api/merchant/v1/orders:
|
||||
get:
|
||||
summary: 客户统一订单列表
|
||||
@@ -200,6 +220,25 @@ paths:
|
||||
responses:
|
||||
'200': {description: 成功或业务失败,按响应体 code 判断}
|
||||
'403': {description: 需要 platform:order:edit 权限}
|
||||
/api/platform/v1/orders/first-leg/{id}/carrier:
|
||||
put:
|
||||
summary: 为待审核订单指派承运商
|
||||
description: 可选的独立指派动作;服务端从公共往来单位主数据校验 CARRIER 类型并写入可信名称快照,不作为审核通过的前置条件。
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/OrderId'
|
||||
- $ref: '#/components/parameters/TenantId'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [carrierId]
|
||||
properties:
|
||||
carrierId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
responses:
|
||||
'200': {description: 指派成功或业务失败,按响应体 code 判断}
|
||||
'403': {description: 需要 platform:order:approve 权限}
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
@@ -225,7 +264,7 @@ components:
|
||||
type: string
|
||||
enum: [PENDING_REVIEW, WAIT_MEASURE, INBOUNDED, WAIT_SPLIT, LOADING, LOADED, DELIVERED]
|
||||
UnifiedInboundCode:
|
||||
{name: inboundCode, in: query, required: false, schema: {type: string, maxLength: 64}}
|
||||
{name: inboundCode, in: query, required: false, description: 客户提交后生成的入仓码,待审核订单同样可查询, schema: {type: string, maxLength: 40}}
|
||||
UnifiedInternalOrderStatus:
|
||||
name: internalOrderStatus
|
||||
in: query
|
||||
|
||||
Reference in New Issue
Block a user