feat(m2): add SKU mapping between contract lines and license features

This commit is contained in:
2026-05-25 14:50:31 +08:00
parent 8d1081b2b9
commit 4dc8341e7e
10 changed files with 642 additions and 1 deletions
@@ -8,6 +8,8 @@ import cn.craftlabs.platform.api.web.dto.IntegrationEnvironmentResponse;
import cn.craftlabs.platform.api.web.dto.PageResponse;
import cn.craftlabs.platform.api.web.dto.ProductLineRequest;
import cn.craftlabs.platform.api.web.dto.ProductLineResponse;
import cn.craftlabs.platform.api.web.dto.SkuMappingRequest;
import cn.craftlabs.platform.api.web.dto.SkuMappingResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
@@ -147,4 +149,28 @@ public class IntegrationCatalogController {
integrationCatalogService.deleteJsonTemplate(id);
return ResponseEntity.ok().build();
}
@GetMapping("/sku-mappings")
public ResponseEntity<List<SkuMappingResponse>> listSkuMappings(
@RequestParam(required = false) Long contractLineId) {
return ResponseEntity.ok(integrationCatalogService.listSkuMappings(contractLineId));
}
@PostMapping("/sku-mappings")
public ResponseEntity<SkuMappingResponse> createSkuMapping(
@RequestParam Long contractLineId, @Valid @RequestBody SkuMappingRequest body) {
return ResponseEntity.ok(integrationCatalogService.createSkuMapping(contractLineId, body));
}
@PutMapping("/sku-mappings/{id}")
public ResponseEntity<SkuMappingResponse> updateSkuMapping(
@PathVariable Long id, @Valid @RequestBody SkuMappingRequest body) {
return ResponseEntity.ok(integrationCatalogService.updateSkuMapping(id, body));
}
@DeleteMapping("/sku-mappings/{id}")
public ResponseEntity<Void> deleteSkuMapping(@PathVariable Long id) {
integrationCatalogService.deleteSkuMapping(id);
return ResponseEntity.ok().build();
}
}
@@ -0,0 +1,122 @@
package cn.craftlabs.platform.api.persistence.integration;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.time.OffsetDateTime;
@TableName("platform_sku_mapping")
public class PlatformSkuMapping {
@TableId(type = IdType.AUTO)
private Long id;
@TableField("contract_line_id")
private Long contractLineId;
@TableField("sku_code")
private String skuCode;
@TableField("sku_name")
private String skuName;
@TableField("bitanswer_product_id")
private String bitanswerProductId;
@TableField("bitanswer_template_id")
private String bitanswerTemplateId;
@TableField("bitanswer_feature_id")
private String bitanswerFeatureId;
@TableField
private Integer quantity;
@TableField("created_at")
private OffsetDateTime createdAt;
@TableField("updated_at")
private OffsetDateTime updatedAt;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getContractLineId() {
return contractLineId;
}
public void setContractLineId(Long contractLineId) {
this.contractLineId = contractLineId;
}
public String getSkuCode() {
return skuCode;
}
public void setSkuCode(String skuCode) {
this.skuCode = skuCode;
}
public String getSkuName() {
return skuName;
}
public void setSkuName(String skuName) {
this.skuName = skuName;
}
public String getBitanswerProductId() {
return bitanswerProductId;
}
public void setBitanswerProductId(String bitanswerProductId) {
this.bitanswerProductId = bitanswerProductId;
}
public String getBitanswerTemplateId() {
return bitanswerTemplateId;
}
public void setBitanswerTemplateId(String bitanswerTemplateId) {
this.bitanswerTemplateId = bitanswerTemplateId;
}
public String getBitanswerFeatureId() {
return bitanswerFeatureId;
}
public void setBitanswerFeatureId(String bitanswerFeatureId) {
this.bitanswerFeatureId = bitanswerFeatureId;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
public OffsetDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(OffsetDateTime createdAt) {
this.createdAt = createdAt;
}
public OffsetDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(OffsetDateTime updatedAt) {
this.updatedAt = updatedAt;
}
}
@@ -0,0 +1,7 @@
package cn.craftlabs.platform.api.persistence.integration;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PlatformSkuMappingMapper extends BaseMapper<PlatformSkuMapping> {}
@@ -8,11 +8,15 @@ import cn.craftlabs.platform.api.persistence.integration.PlatformJsonTemplate;
import cn.craftlabs.platform.api.persistence.integration.PlatformJsonTemplateMapper;
import cn.craftlabs.platform.api.persistence.integration.PlatformProductLine;
import cn.craftlabs.platform.api.persistence.integration.PlatformProductLineMapper;
import cn.craftlabs.platform.api.persistence.integration.PlatformSkuMapping;
import cn.craftlabs.platform.api.persistence.integration.PlatformSkuMappingMapper;
import cn.craftlabs.platform.api.web.dto.IntegrationEnvironmentRequest;
import cn.craftlabs.platform.api.web.dto.IntegrationEnvironmentResponse;
import cn.craftlabs.platform.api.web.dto.PageResponse;
import cn.craftlabs.platform.api.web.dto.ProductLineRequest;
import cn.craftlabs.platform.api.web.dto.ProductLineResponse;
import cn.craftlabs.platform.api.web.dto.SkuMappingRequest;
import cn.craftlabs.platform.api.web.dto.SkuMappingResponse;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.http.HttpStatus;
@@ -30,16 +34,19 @@ public class IntegrationCatalogService {
private final PlatformIntegrationEnvironmentMapper environmentMapper;
private final PlatformBitanswerIdMappingMapper idMappingMapper;
private final PlatformJsonTemplateMapper jsonTemplateMapper;
private final PlatformSkuMappingMapper skuMappingMapper;
public IntegrationCatalogService(
PlatformProductLineMapper productLineMapper,
PlatformIntegrationEnvironmentMapper environmentMapper,
PlatformBitanswerIdMappingMapper idMappingMapper,
PlatformJsonTemplateMapper jsonTemplateMapper) {
PlatformJsonTemplateMapper jsonTemplateMapper,
PlatformSkuMappingMapper skuMappingMapper) {
this.productLineMapper = productLineMapper;
this.environmentMapper = environmentMapper;
this.idMappingMapper = idMappingMapper;
this.jsonTemplateMapper = jsonTemplateMapper;
this.skuMappingMapper = skuMappingMapper;
}
@Transactional(readOnly = true)
@@ -215,6 +222,55 @@ public class IntegrationCatalogService {
jsonTemplateMapper.deleteById(id);
}
@Transactional(readOnly = true)
public List<SkuMappingResponse> listSkuMappings(Long contractLineId) {
var qw = new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<PlatformSkuMapping>();
if (contractLineId != null) qw.eq(PlatformSkuMapping::getContractLineId, contractLineId);
qw.orderByDesc(PlatformSkuMapping::getCreatedAt);
return skuMappingMapper.selectList(qw).stream().map(this::toSkuMapping).collect(Collectors.toList());
}
@Transactional
public SkuMappingResponse createSkuMapping(Long contractLineId, SkuMappingRequest req) {
PlatformSkuMapping row = new PlatformSkuMapping();
row.setContractLineId(contractLineId);
row.setSkuCode(req.getSkuCode());
row.setSkuName(req.getSkuName());
row.setBitanswerProductId(req.getBitanswerProductId());
row.setBitanswerTemplateId(req.getBitanswerTemplateId());
row.setBitanswerFeatureId(req.getBitanswerFeatureId());
row.setQuantity(req.getQuantity() != null ? req.getQuantity() : 1);
row.setCreatedAt(java.time.OffsetDateTime.now());
row.setUpdatedAt(java.time.OffsetDateTime.now());
skuMappingMapper.insert(row);
return toSkuMapping(row);
}
@Transactional
public SkuMappingResponse updateSkuMapping(Long id, SkuMappingRequest req) {
PlatformSkuMapping row = skuMappingMapper.selectById(id);
if (row == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "sku mapping not found");
}
row.setSkuCode(req.getSkuCode());
row.setSkuName(req.getSkuName());
row.setBitanswerProductId(req.getBitanswerProductId());
row.setBitanswerTemplateId(req.getBitanswerTemplateId());
row.setBitanswerFeatureId(req.getBitanswerFeatureId());
row.setQuantity(req.getQuantity() != null ? req.getQuantity() : 1);
row.setUpdatedAt(java.time.OffsetDateTime.now());
skuMappingMapper.updateById(row);
return toSkuMapping(row);
}
@Transactional
public void deleteSkuMapping(Long id) {
if (skuMappingMapper.selectById(id) == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "sku mapping not found");
}
skuMappingMapper.deleteById(id);
}
private ProductLineResponse toProductLine(PlatformProductLine row) {
ProductLineResponse r = new ProductLineResponse();
r.setId(row.getId());
@@ -239,4 +295,18 @@ public class IntegrationCatalogService {
r.setUpdatedAt(row.getUpdatedAt());
return r;
}
private SkuMappingResponse toSkuMapping(PlatformSkuMapping row) {
SkuMappingResponse r = new SkuMappingResponse();
r.setId(row.getId());
r.setContractLineId(row.getContractLineId());
r.setSkuCode(row.getSkuCode());
r.setSkuName(row.getSkuName());
r.setBitanswerProductId(row.getBitanswerProductId());
r.setBitanswerTemplateId(row.getBitanswerTemplateId());
r.setBitanswerFeatureId(row.getBitanswerFeatureId());
r.setQuantity(row.getQuantity());
r.setCreatedAt(row.getCreatedAt());
return r;
}
}
@@ -0,0 +1,75 @@
package cn.craftlabs.platform.api.web.dto;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Size;
public class SkuMappingRequest {
@NotBlank
@Size(max = 64)
private String skuCode;
@Size(max = 256)
private String skuName;
@Size(max = 128)
private String bitanswerProductId;
@Size(max = 128)
private String bitanswerTemplateId;
@Size(max = 128)
private String bitanswerFeatureId;
@Min(1)
private Integer quantity;
public String getSkuCode() {
return skuCode;
}
public void setSkuCode(String skuCode) {
this.skuCode = skuCode;
}
public String getSkuName() {
return skuName;
}
public void setSkuName(String skuName) {
this.skuName = skuName;
}
public String getBitanswerProductId() {
return bitanswerProductId;
}
public void setBitanswerProductId(String bitanswerProductId) {
this.bitanswerProductId = bitanswerProductId;
}
public String getBitanswerTemplateId() {
return bitanswerTemplateId;
}
public void setBitanswerTemplateId(String bitanswerTemplateId) {
this.bitanswerTemplateId = bitanswerTemplateId;
}
public String getBitanswerFeatureId() {
return bitanswerFeatureId;
}
public void setBitanswerFeatureId(String bitanswerFeatureId) {
this.bitanswerFeatureId = bitanswerFeatureId;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
}
@@ -0,0 +1,88 @@
package cn.craftlabs.platform.api.web.dto;
import java.time.OffsetDateTime;
public class SkuMappingResponse {
private Long id;
private Long contractLineId;
private String skuCode;
private String skuName;
private String bitanswerProductId;
private String bitanswerTemplateId;
private String bitanswerFeatureId;
private Integer quantity;
private OffsetDateTime createdAt;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getContractLineId() {
return contractLineId;
}
public void setContractLineId(Long contractLineId) {
this.contractLineId = contractLineId;
}
public String getSkuCode() {
return skuCode;
}
public void setSkuCode(String skuCode) {
this.skuCode = skuCode;
}
public String getSkuName() {
return skuName;
}
public void setSkuName(String skuName) {
this.skuName = skuName;
}
public String getBitanswerProductId() {
return bitanswerProductId;
}
public void setBitanswerProductId(String bitanswerProductId) {
this.bitanswerProductId = bitanswerProductId;
}
public String getBitanswerTemplateId() {
return bitanswerTemplateId;
}
public void setBitanswerTemplateId(String bitanswerTemplateId) {
this.bitanswerTemplateId = bitanswerTemplateId;
}
public String getBitanswerFeatureId() {
return bitanswerFeatureId;
}
public void setBitanswerFeatureId(String bitanswerFeatureId) {
this.bitanswerFeatureId = bitanswerFeatureId;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
public OffsetDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(OffsetDateTime createdAt) {
this.createdAt = createdAt;
}
}
@@ -0,0 +1,13 @@
CREATE TABLE platform_sku_mapping (
id BIGSERIAL PRIMARY KEY,
contract_line_id BIGINT REFERENCES platform_contract_line(id),
sku_code VARCHAR(64) NOT NULL,
sku_name VARCHAR(256),
bitanswer_product_id VARCHAR(128),
bitanswer_template_id VARCHAR(128),
bitanswer_feature_id VARCHAR(128),
quantity INT NOT NULL DEFAULT 1,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_sku_contract_line ON platform_sku_mapping(contract_line_id);