暂存提交
This commit is contained in:
+114
@@ -0,0 +1,114 @@
|
||||
package com.baiyue.warehouse.controller;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.ExpressCompanyPageQuery;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.ExpressCompanySaveRequest;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.StatusRequest;
|
||||
import com.baiyue.warehouse.entity.ExpressCompanyEntity;
|
||||
import com.baiyue.warehouse.service.ExpressCompanyQueryService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/** 平台快递公司管理接口。 */
|
||||
@Validated
|
||||
@Tag(name = "平台快递公司", description = "按目标租户分页查询快递公司主数据")
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/express-companies")
|
||||
public class PlatformExpressCompanyController {
|
||||
private final ExpressCompanyQueryService service;
|
||||
|
||||
public PlatformExpressCompanyController(ExpressCompanyQueryService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@PreAuthorize("hasAuthority('platform:express:list')")
|
||||
@Operation(summary = "分页查询快递公司", description = "按目标租户、关键字和状态分页查询快递公司")
|
||||
@ApiResponses({
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "查询成功"),
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "查询条件无效"),
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "需要登录"),
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "需要平台快递公司查询权限")
|
||||
})
|
||||
public ApiResponse<PageResult<ExpressCompanyEntity>> page(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam @Min(1) long tenantId,
|
||||
@Valid @ParameterObject ExpressCompanyPageQuery query) {
|
||||
requirePlatform(user);
|
||||
return ApiResponse.success(service.page(tenantId, query));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@PreAuthorize("hasAuthority('platform:express:list')")
|
||||
@Operation(summary = "查询快递公司详情", description = "查询目标租户内的快递公司详情")
|
||||
public ApiResponse<ExpressCompanyEntity> detail(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam @Min(1) long tenantId,
|
||||
@PathVariable long id) {
|
||||
requirePlatform(user);
|
||||
return ApiResponse.success(service.detail(tenantId, id));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@PreAuthorize("hasAuthority('platform:express:create')")
|
||||
@Operation(summary = "新增快递公司", description = "在目标租户内新增快递公司")
|
||||
public ApiResponse<Long> create(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam @Min(1) long tenantId,
|
||||
@Valid @RequestBody ExpressCompanySaveRequest request) {
|
||||
requirePlatform(user);
|
||||
return ApiResponse.success(service.create(tenantId, request));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@PreAuthorize("hasAuthority('platform:express:edit')")
|
||||
@Operation(summary = "编辑快递公司", description = "编辑目标租户内的快递公司")
|
||||
public ApiResponse<Void> update(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam @Min(1) long tenantId,
|
||||
@PathVariable long id,
|
||||
@Valid @RequestBody ExpressCompanySaveRequest request) {
|
||||
requirePlatform(user);
|
||||
service.update(tenantId, id, request);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@PatchMapping("/{id}/status")
|
||||
@PreAuthorize("hasAuthority('platform:express:status')")
|
||||
@Operation(summary = "启用或停用快递公司", description = "通过状态变更停用主数据,不物理删除历史记录")
|
||||
public ApiResponse<Void> changeStatus(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam @Min(1) long tenantId,
|
||||
@PathVariable long id,
|
||||
@Valid @RequestBody StatusRequest request) {
|
||||
requirePlatform(user);
|
||||
service.changeStatus(tenantId, id, request.status());
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
private static void requirePlatform(AuthenticatedUser user) {
|
||||
if (user == null || !"PLATFORM".equals(user.appCode())) {
|
||||
throw new BizException(ResultCode.FORBIDDEN, "仅允许平台端访问");
|
||||
}
|
||||
}
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
package com.baiyue.warehouse.controller;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.PartnerPageQuery;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.PartnerSaveRequest;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.StatusRequest;
|
||||
import com.baiyue.warehouse.entity.PartnerEntity;
|
||||
import com.baiyue.warehouse.service.PlatformPartnerQueryService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/** 平台往来单位管理接口。 */
|
||||
@Validated
|
||||
@Tag(name = "平台往来单位", description = "按目标租户分页查询往来单位主数据")
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/partners")
|
||||
public class PlatformPartnerController {
|
||||
private final PlatformPartnerQueryService service;
|
||||
|
||||
public PlatformPartnerController(PlatformPartnerQueryService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@PreAuthorize("hasAuthority('platform:counterparty:list')")
|
||||
@Operation(summary = "分页查询往来单位", description = "按目标租户、关键字、类型和状态分页查询往来单位")
|
||||
@ApiResponses({
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "查询成功"),
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "查询条件无效"),
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "需要登录"),
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "需要平台往来单位查询权限")
|
||||
})
|
||||
public ApiResponse<PageResult<PartnerEntity>> page(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam @Min(1) long tenantId,
|
||||
@Valid @ParameterObject PartnerPageQuery query) {
|
||||
requirePlatform(user);
|
||||
return ApiResponse.success(service.page(tenantId, query));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@PreAuthorize("hasAuthority('platform:counterparty:list')")
|
||||
@Operation(summary = "查询往来单位详情", description = "查询目标租户内的往来单位详情")
|
||||
public ApiResponse<PartnerEntity> detail(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam @Min(1) long tenantId,
|
||||
@PathVariable long id) {
|
||||
requirePlatform(user);
|
||||
return ApiResponse.success(service.detail(tenantId, id));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@PreAuthorize("hasAuthority('platform:counterparty:create')")
|
||||
@Operation(summary = "新增往来单位", description = "在目标租户内新增往来单位")
|
||||
public ApiResponse<Long> create(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam @Min(1) long tenantId,
|
||||
@Valid @RequestBody PartnerSaveRequest request) {
|
||||
requirePlatform(user);
|
||||
return ApiResponse.success(service.create(tenantId, request));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@PreAuthorize("hasAuthority('platform:counterparty:edit')")
|
||||
@Operation(summary = "编辑往来单位", description = "编辑目标租户内的往来单位")
|
||||
public ApiResponse<Void> update(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam @Min(1) long tenantId,
|
||||
@PathVariable long id,
|
||||
@Valid @RequestBody PartnerSaveRequest request) {
|
||||
requirePlatform(user);
|
||||
service.update(tenantId, id, request);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@PatchMapping("/{id}/status")
|
||||
@PreAuthorize("hasAuthority('platform:counterparty:status')")
|
||||
@Operation(summary = "启用或停用往来单位", description = "通过状态变更停用主数据,不物理删除历史记录")
|
||||
public ApiResponse<Void> changeStatus(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam @Min(1) long tenantId,
|
||||
@PathVariable long id,
|
||||
@Valid @RequestBody StatusRequest request) {
|
||||
requirePlatform(user);
|
||||
service.changeStatus(tenantId, id, request.status());
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
private static void requirePlatform(AuthenticatedUser user) {
|
||||
if (user == null || !"PLATFORM".equals(user.appCode())) {
|
||||
throw new BizException(ResultCode.FORBIDDEN, "仅允许平台端访问");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.baiyue.warehouse.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
/** 平台基础资料请求契约。 */
|
||||
public final class MasterDataQueries {
|
||||
private MasterDataQueries() {
|
||||
}
|
||||
|
||||
@Schema(name = "PartnerPageQuery", description = "平台往来单位分页查询条件")
|
||||
public record PartnerPageQuery(
|
||||
@Schema(description = "页码,从 1 开始", example = "1", defaultValue = "1")
|
||||
@Min(1) long page,
|
||||
@Schema(description = "每页条数", example = "20", defaultValue = "20")
|
||||
@Min(1) @Max(200) long size,
|
||||
@Schema(description = "编码、名称、联系人或联系电话关键字", example = "示例客户")
|
||||
@Size(max = 128) String keyword,
|
||||
@Schema(description = "往来单位类型", allowableValues = {"CUSTOMER", "SUPPLIER", "BOTH"})
|
||||
@Pattern(regexp = "^(CUSTOMER|SUPPLIER|BOTH)$") String type,
|
||||
@Schema(description = "状态", allowableValues = {"ACTIVE", "INACTIVE"})
|
||||
@Pattern(regexp = "^(ACTIVE|INACTIVE)$") String status
|
||||
) {
|
||||
public PartnerPageQuery {
|
||||
if (page == 0) {
|
||||
page = 1;
|
||||
}
|
||||
if (size == 0) {
|
||||
size = 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Schema(name = "ExpressCompanyPageQuery", description = "平台快递公司分页查询条件")
|
||||
public record ExpressCompanyPageQuery(
|
||||
@Schema(description = "页码,从 1 开始", example = "1", defaultValue = "1")
|
||||
@Min(1) long page,
|
||||
@Schema(description = "每页条数", example = "20", defaultValue = "20")
|
||||
@Min(1) @Max(200) long size,
|
||||
@Schema(description = "快递公司编码或名称关键字", example = "顺丰")
|
||||
@Size(max = 128) String keyword,
|
||||
@Schema(description = "状态", allowableValues = {"ACTIVE", "INACTIVE"})
|
||||
@Pattern(regexp = "^(ACTIVE|INACTIVE)$") String status
|
||||
) {
|
||||
public ExpressCompanyPageQuery {
|
||||
if (page == 0) {
|
||||
page = 1;
|
||||
}
|
||||
if (size == 0) {
|
||||
size = 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Schema(name = "PartnerSaveRequest", description = "平台往来单位保存请求")
|
||||
public record PartnerSaveRequest(
|
||||
@Schema(description = "租户内唯一往来单位编码", example = "CUS-001")
|
||||
@NotBlank @Size(max = 50) String partnerCode,
|
||||
@Schema(description = "往来单位名称", example = "深圳示例贸易有限公司")
|
||||
@NotBlank @Size(max = 128) String partnerName,
|
||||
@Schema(description = "往来单位类型", allowableValues = {"CUSTOMER", "SUPPLIER", "BOTH"})
|
||||
@NotBlank @Pattern(regexp = "^(CUSTOMER|SUPPLIER|BOTH)$") String partnerType,
|
||||
@Schema(description = "联系人", example = "张三")
|
||||
@NotBlank @Size(max = 64) String contactName,
|
||||
@Schema(description = "联系电话", example = "13800138000")
|
||||
@NotBlank @Size(max = 32) String contactPhone,
|
||||
@Schema(description = "联系邮箱", example = "contact@example.com")
|
||||
@Email @Size(max = 128) String contactEmail,
|
||||
@Schema(description = "国家二字码", example = "CN")
|
||||
@NotBlank @Pattern(regexp = "^[A-Z]{2}$") String countryCode,
|
||||
@Schema(description = "省或州", example = "广东省")
|
||||
@Size(max = 64) String province,
|
||||
@Schema(description = "城市", example = "深圳市")
|
||||
@NotBlank @Size(max = 64) String city,
|
||||
@Schema(description = "区县", example = "宝安区")
|
||||
@Size(max = 64) String district,
|
||||
@Schema(description = "详细地址", example = "航城街道示例路 1 号")
|
||||
@NotBlank @Size(max = 255) String addressLine,
|
||||
@Schema(description = "邮政编码", example = "518000")
|
||||
@Size(max = 20) String postalCode,
|
||||
@Schema(description = "状态", allowableValues = {"ACTIVE", "INACTIVE"})
|
||||
@NotBlank @Pattern(regexp = "^(ACTIVE|INACTIVE)$") String status
|
||||
) {
|
||||
}
|
||||
|
||||
@Schema(name = "ExpressCompanySaveRequest", description = "平台快递公司保存请求")
|
||||
public record ExpressCompanySaveRequest(
|
||||
@Schema(description = "租户内唯一快递公司编码", example = "SF")
|
||||
@NotBlank @Size(max = 50) String companyCode,
|
||||
@Schema(description = "快递公司名称", example = "顺丰速运")
|
||||
@NotBlank @Size(max = 128) String companyName,
|
||||
@Schema(description = "客服电话", example = "95338")
|
||||
@Size(max = 32) String servicePhone,
|
||||
@Schema(description = "官方网站", example = "https://www.sf-express.com")
|
||||
@Size(max = 255) String website,
|
||||
@Schema(description = "轨迹查询地址模板,可包含 {trackingNo}")
|
||||
@Size(max = 500) String trackingUrlTemplate,
|
||||
@Schema(description = "状态", allowableValues = {"ACTIVE", "INACTIVE"})
|
||||
@NotBlank @Pattern(regexp = "^(ACTIVE|INACTIVE)$") String status,
|
||||
@Schema(description = "备注")
|
||||
@Size(max = 500) String remark
|
||||
) {
|
||||
}
|
||||
|
||||
@Schema(name = "MasterDataStatusRequest", description = "基础资料状态变更请求")
|
||||
public record StatusRequest(
|
||||
@Schema(description = "目标状态", allowableValues = {"ACTIVE", "INACTIVE"})
|
||||
@NotBlank @Pattern(regexp = "^(ACTIVE|INACTIVE)$") String status
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.baiyue.warehouse.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baiyue.common.core.model.BaseEntity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/** 租户维度快递公司主数据。 */
|
||||
@Schema(name = "ExpressCompany", description = "租户维度快递公司主数据")
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("wh_express_company")
|
||||
public class ExpressCompanyEntity extends BaseEntity {
|
||||
@Schema(description = "快递公司记录 ID", example = "192000000000000001")
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
@Schema(description = "所属租户 ID", example = "10001")
|
||||
private Long tenantId;
|
||||
@Schema(description = "租户内唯一快递公司编码", example = "SF")
|
||||
private String companyCode;
|
||||
@Schema(description = "快递公司名称", example = "顺丰速运")
|
||||
private String companyName;
|
||||
@Schema(description = "客服电话", example = "95338")
|
||||
private String servicePhone;
|
||||
@Schema(description = "官方网站", example = "https://www.sf-express.com")
|
||||
private String website;
|
||||
@Schema(description = "轨迹查询地址模板,可包含 {trackingNo}")
|
||||
private String trackingUrlTemplate;
|
||||
@Schema(description = "状态", example = "ACTIVE", allowableValues = {"ACTIVE", "INACTIVE"})
|
||||
private String status;
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.baiyue.warehouse.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baiyue.warehouse.entity.ExpressCompanyEntity;
|
||||
|
||||
/** 快递公司持久化映射。 */
|
||||
public interface ExpressCompanyMapper extends BaseMapper<ExpressCompanyEntity> {
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.baiyue.warehouse.repository;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.ExpressCompanyPageQuery;
|
||||
import com.baiyue.warehouse.entity.ExpressCompanyEntity;
|
||||
import com.baiyue.warehouse.mapper.ExpressCompanyMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/** 快递公司主数据仓储。 */
|
||||
@Repository
|
||||
public class ExpressCompanyRepository {
|
||||
private final ExpressCompanyMapper mapper;
|
||||
|
||||
public ExpressCompanyRepository(ExpressCompanyMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
public PageResult<ExpressCompanyEntity> page(long tenantId, ExpressCompanyPageQuery query) {
|
||||
LambdaQueryWrapper<ExpressCompanyEntity> wrapper = new LambdaQueryWrapper<ExpressCompanyEntity>()
|
||||
.eq(ExpressCompanyEntity::getTenantId, tenantId)
|
||||
.eq(StringUtils.hasText(query.status()), ExpressCompanyEntity::getStatus, query.status())
|
||||
.and(StringUtils.hasText(query.keyword()), condition -> condition
|
||||
.like(ExpressCompanyEntity::getCompanyCode, query.keyword())
|
||||
.or()
|
||||
.like(ExpressCompanyEntity::getCompanyName, query.keyword()))
|
||||
.orderByAsc(ExpressCompanyEntity::getCompanyName)
|
||||
.orderByAsc(ExpressCompanyEntity::getId);
|
||||
return PageResult.from(mapper.selectPage(new Page<>(query.page(), query.size()), wrapper));
|
||||
}
|
||||
|
||||
public ExpressCompanyEntity findOwned(long tenantId, long id) {
|
||||
return mapper.selectOne(new LambdaQueryWrapper<ExpressCompanyEntity>()
|
||||
.eq(ExpressCompanyEntity::getTenantId, tenantId)
|
||||
.eq(ExpressCompanyEntity::getId, id));
|
||||
}
|
||||
|
||||
public boolean existsCode(long tenantId, String code, Long excludedId) {
|
||||
return mapper.selectCount(new LambdaQueryWrapper<ExpressCompanyEntity>()
|
||||
.eq(ExpressCompanyEntity::getTenantId, tenantId)
|
||||
.eq(ExpressCompanyEntity::getCompanyCode, code)
|
||||
.ne(excludedId != null, ExpressCompanyEntity::getId, excludedId)) > 0;
|
||||
}
|
||||
|
||||
public void insert(ExpressCompanyEntity entity) {
|
||||
mapper.insert(entity);
|
||||
}
|
||||
|
||||
public void save(ExpressCompanyEntity entity) {
|
||||
mapper.updateById(entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.baiyue.warehouse.service;
|
||||
|
||||
import com.baiyue.common.audit.BusinessAudit;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.ExpressCompanyPageQuery;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.ExpressCompanySaveRequest;
|
||||
import com.baiyue.warehouse.entity.ExpressCompanyEntity;
|
||||
import com.baiyue.warehouse.repository.ExpressCompanyRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/** 平台快递公司管理服务。 */
|
||||
@Service
|
||||
public class ExpressCompanyQueryService {
|
||||
private final ExpressCompanyRepository repository;
|
||||
|
||||
public ExpressCompanyQueryService(ExpressCompanyRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public PageResult<ExpressCompanyEntity> page(long tenantId, ExpressCompanyPageQuery query) {
|
||||
return repository.page(tenantId, query);
|
||||
}
|
||||
|
||||
public ExpressCompanyEntity detail(long tenantId, long id) {
|
||||
return owned(tenantId, id);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@BusinessAudit(event = "EXPRESS_COMPANY_CREATE", resourceType = "EXPRESS_COMPANY", description = "新增快递公司", captureBefore = false)
|
||||
public Long create(long tenantId, ExpressCompanySaveRequest request) {
|
||||
ensureCodeUnique(tenantId, request.companyCode(), null);
|
||||
ExpressCompanyEntity entity = new ExpressCompanyEntity();
|
||||
entity.setTenantId(tenantId);
|
||||
copy(entity, request);
|
||||
try {
|
||||
repository.insert(entity);
|
||||
} catch (DataIntegrityViolationException exception) {
|
||||
throw new BizException(ResultCode.CONFLICT, "快递公司编码已存在");
|
||||
}
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@BusinessAudit(event = "EXPRESS_COMPANY_UPDATE", resourceType = "EXPRESS_COMPANY", resourceId = "#id", description = "编辑快递公司")
|
||||
public void update(long tenantId, long id, ExpressCompanySaveRequest request) {
|
||||
ExpressCompanyEntity entity = owned(tenantId, id);
|
||||
ensureCodeUnique(tenantId, request.companyCode(), id);
|
||||
copy(entity, request);
|
||||
try {
|
||||
repository.save(entity);
|
||||
} catch (DataIntegrityViolationException exception) {
|
||||
throw new BizException(ResultCode.CONFLICT, "快递公司编码已存在");
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@BusinessAudit(event = "EXPRESS_COMPANY_STATUS_CHANGE", resourceType = "EXPRESS_COMPANY", resourceId = "#id", description = "启停快递公司")
|
||||
public void changeStatus(long tenantId, long id, String status) {
|
||||
requireStatus(status);
|
||||
ExpressCompanyEntity entity = owned(tenantId, id);
|
||||
entity.setStatus(status);
|
||||
repository.save(entity);
|
||||
}
|
||||
|
||||
private ExpressCompanyEntity owned(long tenantId, long id) {
|
||||
ExpressCompanyEntity entity = repository.findOwned(tenantId, id);
|
||||
if (entity == null) {
|
||||
throw new BizException(ResultCode.NOT_FOUND, "快递公司不存在");
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
private void ensureCodeUnique(long tenantId, String code, Long excludedId) {
|
||||
if (repository.existsCode(tenantId, code, excludedId)) {
|
||||
throw new BizException(ResultCode.CONFLICT, "快递公司编码已存在");
|
||||
}
|
||||
}
|
||||
|
||||
private static void requireStatus(String status) {
|
||||
if (!"ACTIVE".equals(status) && !"INACTIVE".equals(status)) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "状态只能设置为 ACTIVE 或 INACTIVE");
|
||||
}
|
||||
}
|
||||
|
||||
private static void copy(ExpressCompanyEntity entity, ExpressCompanySaveRequest request) {
|
||||
entity.setCompanyCode(request.companyCode());
|
||||
entity.setCompanyName(request.companyName());
|
||||
entity.setServicePhone(request.servicePhone());
|
||||
entity.setWebsite(request.website());
|
||||
entity.setTrackingUrlTemplate(request.trackingUrlTemplate());
|
||||
entity.setStatus(request.status());
|
||||
entity.setRemark(request.remark());
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package com.baiyue.warehouse.service;
|
||||
|
||||
import com.baiyue.common.audit.BusinessAudit;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.PartnerPageQuery;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.PartnerSaveRequest;
|
||||
import com.baiyue.warehouse.entity.PartnerEntity;
|
||||
import com.baiyue.warehouse.repository.PartnerRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/** 平台往来单位管理服务。 */
|
||||
@Service
|
||||
public class PlatformPartnerQueryService {
|
||||
private final PartnerRepository repository;
|
||||
|
||||
public PlatformPartnerQueryService(PartnerRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public PageResult<PartnerEntity> page(long tenantId, PartnerPageQuery query) {
|
||||
return repository.page(tenantId, query);
|
||||
}
|
||||
|
||||
public PartnerEntity detail(long tenantId, long id) {
|
||||
return owned(tenantId, id);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@BusinessAudit(event = "PARTNER_CREATE", resourceType = "PARTNER", description = "新增往来单位", captureBefore = false)
|
||||
public Long create(long tenantId, PartnerSaveRequest request) {
|
||||
ensureCodeUnique(tenantId, request.partnerCode(), null);
|
||||
PartnerEntity entity = new PartnerEntity();
|
||||
entity.setTenantId(tenantId);
|
||||
copy(entity, request);
|
||||
try {
|
||||
repository.insert(entity);
|
||||
} catch (DataIntegrityViolationException exception) {
|
||||
throw new BizException(ResultCode.CONFLICT, "往来单位编码已存在");
|
||||
}
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@BusinessAudit(event = "PARTNER_UPDATE", resourceType = "PARTNER", resourceId = "#id", description = "编辑往来单位")
|
||||
public void update(long tenantId, long id, PartnerSaveRequest request) {
|
||||
PartnerEntity entity = owned(tenantId, id);
|
||||
ensureCodeUnique(tenantId, request.partnerCode(), id);
|
||||
copy(entity, request);
|
||||
try {
|
||||
repository.save(entity);
|
||||
} catch (DataIntegrityViolationException exception) {
|
||||
throw new BizException(ResultCode.CONFLICT, "往来单位编码已存在");
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@BusinessAudit(event = "PARTNER_STATUS_CHANGE", resourceType = "PARTNER", resourceId = "#id", description = "启停往来单位")
|
||||
public void changeStatus(long tenantId, long id, String status) {
|
||||
requireStatus(status);
|
||||
PartnerEntity entity = owned(tenantId, id);
|
||||
entity.setStatus(status);
|
||||
repository.save(entity);
|
||||
}
|
||||
|
||||
private PartnerEntity owned(long tenantId, long id) {
|
||||
PartnerEntity entity = repository.findOwned(tenantId, id);
|
||||
if (entity == null) {
|
||||
throw new BizException(ResultCode.NOT_FOUND, "往来单位不存在");
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
private void ensureCodeUnique(long tenantId, String code, Long excludedId) {
|
||||
if (repository.existsCode(tenantId, code, excludedId)) {
|
||||
throw new BizException(ResultCode.CONFLICT, "往来单位编码已存在");
|
||||
}
|
||||
}
|
||||
|
||||
private static void requireStatus(String status) {
|
||||
if (!"ACTIVE".equals(status) && !"INACTIVE".equals(status)) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "状态只能设置为 ACTIVE 或 INACTIVE");
|
||||
}
|
||||
}
|
||||
|
||||
private static void copy(PartnerEntity entity, PartnerSaveRequest request) {
|
||||
entity.setPartnerCode(request.partnerCode());
|
||||
entity.setPartnerName(request.partnerName());
|
||||
entity.setPartnerType(request.partnerType());
|
||||
entity.setContactName(request.contactName());
|
||||
entity.setContactPhone(request.contactPhone());
|
||||
entity.setContactEmail(request.contactEmail());
|
||||
entity.setCountryCode(request.countryCode());
|
||||
entity.setProvince(request.province());
|
||||
entity.setCity(request.city());
|
||||
entity.setDistrict(request.district());
|
||||
entity.setAddressLine(request.addressLine());
|
||||
entity.setPostalCode(request.postalCode());
|
||||
entity.setStatus(request.status());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
SET NAMES utf8mb4;
|
||||
USE baiyue_warehouse;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS wh_express_company (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '快递公司记录ID',
|
||||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '所属租户ID',
|
||||
company_code VARCHAR(50) NOT NULL COMMENT '租户内唯一快递公司编码',
|
||||
company_name VARCHAR(128) NOT NULL COMMENT '快递公司名称',
|
||||
service_phone VARCHAR(32) DEFAULT NULL COMMENT '客服电话',
|
||||
website VARCHAR(255) DEFAULT NULL COMMENT '官方网站',
|
||||
tracking_url_template VARCHAR(500) DEFAULT NULL COMMENT '轨迹查询地址模板,可包含{trackingNo}',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '快递公司状态',
|
||||
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||
created_by BIGINT UNSIGNED DEFAULT NULL COMMENT '创建人ID',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||
updated_by BIGINT UNSIGNED DEFAULT NULL COMMENT '最后修改人ID',
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_wh_express_tenant_code (tenant_id, company_code, deleted),
|
||||
KEY idx_wh_express_tenant_status (tenant_id, status, deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='租户维度快递公司主数据';
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.baiyue.warehouse.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class PlatformMasterDataControllerContractTest {
|
||||
@Test
|
||||
void 往来单位分页路径权限和接口说明完整() throws Exception {
|
||||
assertContract(PlatformPartnerController.class, "platform:counterparty:list", "/api/platform/v1/partners");
|
||||
assertMethod(PlatformPartnerController.class, "detail", GetMapping.class, "platform:counterparty:list");
|
||||
assertMethod(PlatformPartnerController.class, "create", PostMapping.class, "platform:counterparty:create");
|
||||
assertMethod(PlatformPartnerController.class, "update", PutMapping.class, "platform:counterparty:edit");
|
||||
assertMethod(PlatformPartnerController.class, "changeStatus", PatchMapping.class, "platform:counterparty:status");
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司分页路径权限和接口说明完整() throws Exception {
|
||||
assertContract(PlatformExpressCompanyController.class, "platform:express:list", "/api/platform/v1/express-companies");
|
||||
assertMethod(PlatformExpressCompanyController.class, "detail", GetMapping.class, "platform:express:list");
|
||||
assertMethod(PlatformExpressCompanyController.class, "create", PostMapping.class, "platform:express:create");
|
||||
assertMethod(PlatformExpressCompanyController.class, "update", PutMapping.class, "platform:express:edit");
|
||||
assertMethod(PlatformExpressCompanyController.class, "changeStatus", PatchMapping.class, "platform:express:status");
|
||||
}
|
||||
|
||||
private static void assertContract(Class<?> controller, String authority, String path) throws Exception {
|
||||
RequestMapping mapping = controller.getAnnotation(RequestMapping.class);
|
||||
assertThat(mapping.value()).containsExactly(path);
|
||||
|
||||
Method page = controller.getDeclaredMethod("page",
|
||||
com.baiyue.common.security.AuthenticatedUser.class,
|
||||
long.class,
|
||||
controller == PlatformPartnerController.class
|
||||
? com.baiyue.warehouse.dto.MasterDataQueries.PartnerPageQuery.class
|
||||
: com.baiyue.warehouse.dto.MasterDataQueries.ExpressCompanyPageQuery.class);
|
||||
assertThat(page.getAnnotation(GetMapping.class)).isNotNull();
|
||||
assertThat(page.getAnnotation(PreAuthorize.class).value()).contains(authority);
|
||||
assertThat(page.getAnnotation(Operation.class).summary()).contains("分页查询");
|
||||
}
|
||||
|
||||
private static void assertMethod(Class<?> controller, String methodName,
|
||||
Class<? extends java.lang.annotation.Annotation> mapping,
|
||||
String authority) {
|
||||
Method method = java.util.Arrays.stream(controller.getDeclaredMethods())
|
||||
.filter(candidate -> candidate.getName().equals(methodName))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
assertThat(method.getAnnotation(mapping)).isNotNull();
|
||||
assertThat(method.getAnnotation(PreAuthorize.class).value()).contains(authority);
|
||||
assertThat(method.getAnnotation(Operation.class).summary()).isNotBlank();
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.baiyue.warehouse.repository;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.ExpressCompanyPageQuery;
|
||||
import com.baiyue.warehouse.entity.ExpressCompanyEntity;
|
||||
import com.baiyue.warehouse.mapper.ExpressCompanyMapper;
|
||||
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||
import org.apache.ibatis.session.Configuration;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class ExpressCompanyRepositoryTest {
|
||||
@BeforeAll
|
||||
static void 初始化实体字段缓存() {
|
||||
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new Configuration(), "test"), ExpressCompanyEntity.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 平台分页强制租户并支持筛选() {
|
||||
ExpressCompanyMapper mapper = mock(ExpressCompanyMapper.class);
|
||||
when(mapper.selectPage(any(Page.class), any())).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
new ExpressCompanyRepository(mapper).page(10001L,
|
||||
new ExpressCompanyPageQuery(1, 20, "顺丰", "ACTIVE"));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<LambdaQueryWrapper<ExpressCompanyEntity>> wrapper =
|
||||
ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
||||
verify(mapper).selectPage(any(Page.class), wrapper.capture());
|
||||
wrapper.getValue().getSqlSegment();
|
||||
assertThat(wrapper.getValue().getParamNameValuePairs().values())
|
||||
.contains(10001L, "ACTIVE", "%顺丰%");
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.baiyue.warehouse.repository;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class WarehouseSchemaContractTest {
|
||||
@Test
|
||||
void 仓库三张表包含实体全部持久化字段() throws IOException {
|
||||
String sql = read("warehouse.sql");
|
||||
assertColumns(sql, "wh_warehouse", "warehouse_code", "warehouse_name", "warehouse_type", "country_code",
|
||||
"timezone", "contact_name", "contact_phone", "contact_email", "status", "remark");
|
||||
assertColumns(sql, "wh_warehouse_address", "warehouse_id", "address_type", "country_code", "state_province",
|
||||
"city", "district", "postal_code", "address_line1", "address_line2", "latitude", "longitude");
|
||||
assertColumns(sql, "wh_service_capability", "warehouse_id", "capability_code", "capability_name", "enabled",
|
||||
"cutoff_time", "description");
|
||||
assertBaseColumns(sql);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 往来单位表包含实体全部持久化字段() throws IOException {
|
||||
String sql = read("warehouse-partner.sql");
|
||||
assertColumns(sql, "wh_partner", "partner_code", "partner_name", "partner_type", "contact_name",
|
||||
"contact_phone", "contact_email", "country_code", "province", "city", "district", "address_line",
|
||||
"postal_code", "status");
|
||||
assertBaseColumns(sql);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司表包含实体全部持久化字段() throws IOException {
|
||||
String sql = read("warehouse-express-company.sql");
|
||||
assertColumns(sql, "wh_express_company", "company_code", "company_name", "service_phone", "website",
|
||||
"tracking_url_template", "status", "remark");
|
||||
assertBaseColumns(sql);
|
||||
}
|
||||
|
||||
private static String read(String file) throws IOException {
|
||||
return Files.readString(Path.of("src/main/resources/db", file));
|
||||
}
|
||||
|
||||
private static void assertColumns(String sql, String table, String... columns) {
|
||||
assertThat(sql).contains("CREATE TABLE IF NOT EXISTS " + table);
|
||||
for (String column : columns) {
|
||||
assertThat(sql).contains(column + " ");
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertBaseColumns(String sql) {
|
||||
assertColumns(sql, tableName(sql), "tenant_id", "created_by", "created_at", "updated_by", "updated_at",
|
||||
"deleted", "version");
|
||||
}
|
||||
|
||||
private static String tableName(String sql) {
|
||||
int start = sql.indexOf("CREATE TABLE IF NOT EXISTS ") + "CREATE TABLE IF NOT EXISTS ".length();
|
||||
int end = sql.indexOf(' ', start);
|
||||
return sql.substring(start, end);
|
||||
}
|
||||
}
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
package com.baiyue.warehouse.service;
|
||||
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.ExpressCompanySaveRequest;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.PartnerSaveRequest;
|
||||
import com.baiyue.warehouse.entity.ExpressCompanyEntity;
|
||||
import com.baiyue.warehouse.entity.PartnerEntity;
|
||||
import com.baiyue.warehouse.repository.ExpressCompanyRepository;
|
||||
import com.baiyue.warehouse.repository.PartnerRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class PlatformMasterDataManagementServiceTest {
|
||||
@Test
|
||||
void 往来单位详情强制租户隔离() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
PlatformPartnerQueryService service = new PlatformPartnerQueryService(repository);
|
||||
|
||||
assertThatThrownBy(() -> service.detail(10002L, 1L)).isInstanceOf(BizException.class);
|
||||
verify(repository).findOwned(10002L, 1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 往来单位编码在租户内必须唯一() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
when(repository.existsCode(10001L, "CUS-001", null)).thenReturn(true);
|
||||
PlatformPartnerQueryService service = new PlatformPartnerQueryService(repository);
|
||||
|
||||
assertThatThrownBy(() -> service.create(10001L, partnerRequest()))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("编码");
|
||||
verify(repository, never()).insert(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void 往来单位并发重复编码统一返回业务冲突() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
doThrow(new DataIntegrityViolationException("duplicate")).when(repository).insert(any());
|
||||
PlatformPartnerQueryService service = new PlatformPartnerQueryService(repository);
|
||||
|
||||
assertThatThrownBy(() -> service.create(10001L, partnerRequest()))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("编码");
|
||||
}
|
||||
|
||||
@Test
|
||||
void 往来单位新增写入租户和请求字段() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
doAnswer(invocation -> {
|
||||
PartnerEntity entity = invocation.getArgument(0);
|
||||
entity.setId(18L);
|
||||
return null;
|
||||
}).when(repository).insert(any());
|
||||
PlatformPartnerQueryService service = new PlatformPartnerQueryService(repository);
|
||||
|
||||
assertThat(service.create(10001L, partnerRequest())).isEqualTo(18L);
|
||||
|
||||
org.mockito.ArgumentCaptor<PartnerEntity> entity = org.mockito.ArgumentCaptor.forClass(PartnerEntity.class);
|
||||
verify(repository).insert(entity.capture());
|
||||
assertThat(entity.getValue().getTenantId()).isEqualTo(10001L);
|
||||
assertThat(entity.getValue().getPartnerCode()).isEqualTo("CUS-001");
|
||||
assertThat(entity.getValue().getPartnerName()).isEqualTo("示例客户");
|
||||
}
|
||||
|
||||
@Test
|
||||
void 往来单位编辑保留归属并更新字段() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
PartnerEntity entity = new PartnerEntity();
|
||||
entity.setId(19L);
|
||||
entity.setTenantId(10001L);
|
||||
when(repository.findOwned(10001L, 19L)).thenReturn(entity);
|
||||
PlatformPartnerQueryService service = new PlatformPartnerQueryService(repository);
|
||||
|
||||
service.update(10001L, 19L, partnerRequest());
|
||||
|
||||
assertThat(entity.getTenantId()).isEqualTo(10001L);
|
||||
assertThat(entity.getPartnerName()).isEqualTo("示例客户");
|
||||
verify(repository).save(entity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 往来单位停用保留主数据() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
PartnerEntity entity = new PartnerEntity();
|
||||
entity.setId(8L);
|
||||
entity.setTenantId(10001L);
|
||||
entity.setStatus("ACTIVE");
|
||||
when(repository.findOwned(10001L, 8L)).thenReturn(entity);
|
||||
PlatformPartnerQueryService service = new PlatformPartnerQueryService(repository);
|
||||
|
||||
service.changeStatus(10001L, 8L, "INACTIVE");
|
||||
|
||||
assertThat(entity.getStatus()).isEqualTo("INACTIVE");
|
||||
verify(repository).save(entity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司详情强制租户隔离() {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
ExpressCompanyQueryService service = new ExpressCompanyQueryService(repository);
|
||||
|
||||
assertThatThrownBy(() -> service.detail(10002L, 1L)).isInstanceOf(BizException.class);
|
||||
verify(repository).findOwned(10002L, 1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司编码在租户内必须唯一() {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
when(repository.existsCode(10001L, "SF", null)).thenReturn(true);
|
||||
ExpressCompanyQueryService service = new ExpressCompanyQueryService(repository);
|
||||
|
||||
assertThatThrownBy(() -> service.create(10001L, expressRequest()))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("编码");
|
||||
verify(repository, never()).insert(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司并发重复编码统一返回业务冲突() {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
doThrow(new DataIntegrityViolationException("duplicate")).when(repository).insert(any());
|
||||
ExpressCompanyQueryService service = new ExpressCompanyQueryService(repository);
|
||||
|
||||
assertThatThrownBy(() -> service.create(10001L, expressRequest()))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("编码");
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司新增写入租户和请求字段() {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
doAnswer(invocation -> {
|
||||
ExpressCompanyEntity entity = invocation.getArgument(0);
|
||||
entity.setId(28L);
|
||||
return null;
|
||||
}).when(repository).insert(any());
|
||||
ExpressCompanyQueryService service = new ExpressCompanyQueryService(repository);
|
||||
|
||||
assertThat(service.create(10001L, expressRequest())).isEqualTo(28L);
|
||||
|
||||
org.mockito.ArgumentCaptor<ExpressCompanyEntity> entity =
|
||||
org.mockito.ArgumentCaptor.forClass(ExpressCompanyEntity.class);
|
||||
verify(repository).insert(entity.capture());
|
||||
assertThat(entity.getValue().getTenantId()).isEqualTo(10001L);
|
||||
assertThat(entity.getValue().getCompanyCode()).isEqualTo("SF");
|
||||
assertThat(entity.getValue().getCompanyName()).isEqualTo("顺丰速运");
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司编辑保留归属并更新字段() {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
ExpressCompanyEntity entity = new ExpressCompanyEntity();
|
||||
entity.setId(29L);
|
||||
entity.setTenantId(10001L);
|
||||
when(repository.findOwned(10001L, 29L)).thenReturn(entity);
|
||||
ExpressCompanyQueryService service = new ExpressCompanyQueryService(repository);
|
||||
|
||||
service.update(10001L, 29L, expressRequest());
|
||||
|
||||
assertThat(entity.getTenantId()).isEqualTo(10001L);
|
||||
assertThat(entity.getCompanyName()).isEqualTo("顺丰速运");
|
||||
verify(repository).save(entity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司停用保留主数据() {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
ExpressCompanyEntity entity = new ExpressCompanyEntity();
|
||||
entity.setId(9L);
|
||||
entity.setTenantId(10001L);
|
||||
entity.setStatus("ACTIVE");
|
||||
when(repository.findOwned(10001L, 9L)).thenReturn(entity);
|
||||
ExpressCompanyQueryService service = new ExpressCompanyQueryService(repository);
|
||||
|
||||
service.changeStatus(10001L, 9L, "INACTIVE");
|
||||
|
||||
assertThat(entity.getStatus()).isEqualTo("INACTIVE");
|
||||
verify(repository).save(entity);
|
||||
}
|
||||
|
||||
private static PartnerSaveRequest partnerRequest() {
|
||||
return new PartnerSaveRequest("CUS-001", "示例客户", "CUSTOMER", "张三", "13800138000",
|
||||
"test@example.com", "CN", "广东省", "深圳市", "南山区", "示例地址", "518000", "ACTIVE");
|
||||
}
|
||||
|
||||
private static ExpressCompanySaveRequest expressRequest() {
|
||||
return new ExpressCompanySaveRequest("SF", "顺丰速运", "95338", "https://www.sf-express.com",
|
||||
"https://example.com/{trackingNo}", "ACTIVE", null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user