diff --git a/backend/crm/src/main/java/cn/cordys/common/constants/FormKey.java b/backend/crm/src/main/java/cn/cordys/common/constants/FormKey.java index 07b36003f..5200e8693 100644 --- a/backend/crm/src/main/java/cn/cordys/common/constants/FormKey.java +++ b/backend/crm/src/main/java/cn/cordys/common/constants/FormKey.java @@ -48,7 +48,11 @@ public enum FormKey { /** * 报价单 */ - QUOTATION("quotation"); + QUOTATION("quotation"), + /** + * 合同 + */ + CONTRACT("contract"); private final String key; diff --git a/backend/crm/src/main/java/cn/cordys/crm/contract/constants/ArchivedStatus.java b/backend/crm/src/main/java/cn/cordys/crm/contract/constants/ArchivedStatus.java new file mode 100644 index 000000000..f7cdf539b --- /dev/null +++ b/backend/crm/src/main/java/cn/cordys/crm/contract/constants/ArchivedStatus.java @@ -0,0 +1,17 @@ +package cn.cordys.crm.contract.constants; + +/** + * 合同归档状态 + */ +public enum ArchivedStatus { + + /** + * 已归档 + */ + ARCHIVED, + + /** + * 未归档 + */ + UN_ARCHIVED, +} diff --git a/backend/crm/src/main/java/cn/cordys/crm/contract/constants/ContractStatus.java b/backend/crm/src/main/java/cn/cordys/crm/contract/constants/ContractStatus.java new file mode 100644 index 000000000..41f8dab57 --- /dev/null +++ b/backend/crm/src/main/java/cn/cordys/crm/contract/constants/ContractStatus.java @@ -0,0 +1,29 @@ +package cn.cordys.crm.contract.constants; + + +/** + * 合同状态 + */ +public enum ContractStatus { + + + /** + * 已签署 + */ + SIGNED, + + /** + * 履行中 + */ + IN_PROGRESS, + + /** + * 履行完毕 + */ + COMPLETED_PERFORMANCE, + + /** + * 作废 + */ + VOID, +} diff --git a/backend/crm/src/main/java/cn/cordys/crm/contract/constants/ReviewStatus.java b/backend/crm/src/main/java/cn/cordys/crm/contract/constants/ReviewStatus.java new file mode 100644 index 000000000..b33f072b2 --- /dev/null +++ b/backend/crm/src/main/java/cn/cordys/crm/contract/constants/ReviewStatus.java @@ -0,0 +1,25 @@ +package cn.cordys.crm.contract.constants; + + +/** + * 合同审核状态 + */ +public enum ReviewStatus { + + /** + * 审核中 + */ + UNDER_REVIEW, + + /** + * 通过 + */ + PASS, + + /** + * 不通过 + */ + NOT_PASSED, + + +} diff --git a/backend/crm/src/main/java/cn/cordys/crm/contract/controller/ContractController.java b/backend/crm/src/main/java/cn/cordys/crm/contract/controller/ContractController.java new file mode 100644 index 000000000..95f42eb78 --- /dev/null +++ b/backend/crm/src/main/java/cn/cordys/crm/contract/controller/ContractController.java @@ -0,0 +1,63 @@ +package cn.cordys.crm.contract.controller; + +import cn.cordys.common.constants.FormKey; +import cn.cordys.common.constants.PermissionConstants; +import cn.cordys.context.OrganizationContext; +import cn.cordys.crm.contract.domain.Contract; +import cn.cordys.crm.contract.dto.request.ContractAddRequest; +import cn.cordys.crm.contract.dto.request.ContractUpdateRequest; +import cn.cordys.crm.contract.service.ContractService; +import cn.cordys.crm.opportunity.domain.Opportunity; +import cn.cordys.crm.opportunity.dto.request.OpportunityAddRequest; +import cn.cordys.crm.opportunity.dto.request.OpportunityUpdateRequest; +import cn.cordys.crm.system.dto.response.ModuleFormConfigDTO; +import cn.cordys.crm.system.service.ModuleFormCacheService; +import cn.cordys.security.SessionUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + + +@Tag(name = "合同") +@RestController +@RequestMapping("/contract") +public class ContractController { + @Resource + private ModuleFormCacheService moduleFormCacheService; + @Resource + private ContractService contractService; + + + @GetMapping("/module/form") + @RequiresPermissions(PermissionConstants.CONTRACT_READ) + @Operation(summary = "获取表单配置") + public ModuleFormConfigDTO getModuleFormConfig() { + return moduleFormCacheService.getBusinessFormConfig(FormKey.CONTRACT.getKey(), OrganizationContext.getOrganizationId()); + } + + + @PostMapping("/add") + @RequiresPermissions(PermissionConstants.CONTRACT_ADD) + @Operation(summary = "创建") + public Contract add(@Validated @RequestBody ContractAddRequest request) { + return contractService.add(request, SessionUtils.getUserId(), OrganizationContext.getOrganizationId()); + } + + @PostMapping("/update") + @RequiresPermissions(PermissionConstants.CONTRACT_UPDATE) + @Operation(summary = "更新") + public Contract update(@Validated @RequestBody ContractUpdateRequest request) { + return contractService.update(request, SessionUtils.getUserId(), OrganizationContext.getOrganizationId()); + } + + + @GetMapping("/delete/{id}") + @RequiresPermissions(PermissionConstants.CONTRACT_DELETE) + @Operation(summary = "删除") + public void delete(@PathVariable("id") String id) { + contractService.delete(id); + } +} diff --git a/backend/crm/src/main/java/cn/cordys/crm/contract/domain/Contract.java b/backend/crm/src/main/java/cn/cordys/crm/contract/domain/Contract.java index 9fbf615e4..a570cdd65 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/contract/domain/Contract.java +++ b/backend/crm/src/main/java/cn/cordys/crm/contract/domain/Contract.java @@ -32,8 +32,8 @@ public class Contract extends BaseModel { @Schema(description = "归档状态") private String archivedStatus; - @Schema(description = "作废状态") - private String voidedStatus; + @Schema(description = "合同状态") + private String status; @Schema(description = "组织id") private String organizationId; diff --git a/backend/crm/src/main/java/cn/cordys/crm/contract/domain/ContractSnapshot.java b/backend/crm/src/main/java/cn/cordys/crm/contract/domain/ContractSnapshot.java new file mode 100644 index 000000000..555a7ddcd --- /dev/null +++ b/backend/crm/src/main/java/cn/cordys/crm/contract/domain/ContractSnapshot.java @@ -0,0 +1,31 @@ +package cn.cordys.crm.contract.domain; + +import jakarta.persistence.Table; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +@Data +@Table(name = "contract_snapshot") +public class ContractSnapshot implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String id; + + @Schema(description = "合同id") + private String contractId; + + @Schema(description = "表单属性快照") + private String contractProp; + + @Schema(description = "表单值快照") + private String contractValue; +} diff --git a/backend/crm/src/main/java/cn/cordys/crm/contract/dto/request/ContractAddRequest.java b/backend/crm/src/main/java/cn/cordys/crm/contract/dto/request/ContractAddRequest.java new file mode 100644 index 000000000..b688c6db9 --- /dev/null +++ b/backend/crm/src/main/java/cn/cordys/crm/contract/dto/request/ContractAddRequest.java @@ -0,0 +1,37 @@ +package cn.cordys.crm.contract.dto.request; + +import cn.cordys.common.domain.BaseModuleFieldValue; +import cn.cordys.crm.system.dto.response.ModuleFormConfigDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class ContractAddRequest { + + @NotBlank + @Size(max = 255) + @Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED) + private String name; + + @Size(max = 32) + @Schema(description = "客户id", requiredMode = Schema.RequiredMode.REQUIRED) + private String customerId; + + @Schema(description = "金额") + private BigDecimal amount; + + @Size(max = 32) + @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED) + private String owner; + + @Schema(description = "自定义字段") + private List moduleFields; + + @Schema(description = "表单配置") + private ModuleFormConfigDTO moduleFormConfigDTO; +} diff --git a/backend/crm/src/main/java/cn/cordys/crm/contract/dto/request/ContractUpdateRequest.java b/backend/crm/src/main/java/cn/cordys/crm/contract/dto/request/ContractUpdateRequest.java new file mode 100644 index 000000000..f84675906 --- /dev/null +++ b/backend/crm/src/main/java/cn/cordys/crm/contract/dto/request/ContractUpdateRequest.java @@ -0,0 +1,15 @@ +package cn.cordys.crm.contract.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +@Data +public class ContractUpdateRequest extends ContractAddRequest { + + @NotBlank + @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED) + @Size(max = 32) + private String id; +} diff --git a/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractFieldService.java b/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractFieldService.java new file mode 100644 index 000000000..d54b4c904 --- /dev/null +++ b/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractFieldService.java @@ -0,0 +1,35 @@ +package cn.cordys.crm.contract.service; + +import cn.cordys.common.constants.FormKey; +import cn.cordys.common.service.BaseResourceFieldService; +import cn.cordys.crm.contract.domain.ContractField; +import cn.cordys.crm.contract.domain.ContractFieldBlob; +import cn.cordys.mybatis.BaseMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(rollbackFor = Exception.class) +public class ContractFieldService extends BaseResourceFieldService { + + @Resource + private BaseMapper contractFieldMapper; + @Resource + private BaseMapper contractFieldBlobMapper; + + @Override + protected String getFormKey() { + return FormKey.CONTRACT.getKey(); + } + + @Override + protected BaseMapper getResourceFieldMapper() { + return contractFieldMapper; + } + + @Override + protected BaseMapper getResourceFieldBlobMapper() { + return contractFieldBlobMapper; + } +} diff --git a/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractService.java b/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractService.java new file mode 100644 index 000000000..e45ba2760 --- /dev/null +++ b/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractService.java @@ -0,0 +1,215 @@ +package cn.cordys.crm.contract.service; + +import cn.cordys.aspectj.annotation.OperationLog; +import cn.cordys.aspectj.constants.LogModule; +import cn.cordys.aspectj.constants.LogType; +import cn.cordys.aspectj.context.OperationLogContext; +import cn.cordys.common.domain.BaseModuleFieldValue; +import cn.cordys.common.dto.OptionDTO; +import cn.cordys.common.exception.GenericException; +import cn.cordys.common.service.BaseService; +import cn.cordys.common.uid.IDGenerator; +import cn.cordys.common.util.BeanUtils; +import cn.cordys.common.util.JSON; +import cn.cordys.common.util.Translator; +import cn.cordys.crm.contract.constants.ArchivedStatus; +import cn.cordys.crm.contract.constants.ContractStatus; +import cn.cordys.crm.contract.domain.Contract; +import cn.cordys.crm.contract.domain.ContractSnapshot; +import cn.cordys.crm.contract.dto.request.ContractAddRequest; +import cn.cordys.crm.contract.dto.request.ContractUpdateRequest; +import cn.cordys.crm.opportunity.constants.ApprovalState; +import cn.cordys.crm.opportunity.domain.OpportunityQuotation; +import cn.cordys.crm.opportunity.domain.OpportunityQuotationSnapshot; +import cn.cordys.crm.opportunity.dto.response.OpportunityQuotationGetResponse; +import cn.cordys.crm.system.domain.Attachment; +import cn.cordys.crm.system.dto.response.ModuleFormConfigDTO; +import cn.cordys.crm.system.service.ModuleFormService; +import cn.cordys.mybatis.BaseMapper; +import cn.cordys.mybatis.lambda.LambdaQueryWrapper; +import jakarta.annotation.Resource; +import org.apache.commons.lang3.Strings; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Service +@Transactional(rollbackFor = Exception.class) +public class ContractService { + + @Resource + private ContractFieldService contractFieldService; + @Resource + private BaseMapper contractMapper; + @Resource + private BaseService baseService; + @Resource + private ModuleFormService moduleFormService; + @Resource + private BaseMapper snapshotBaseMapper; + + /** + * 新建合同 + * + * @param request + * @param operatorId + * @param orgId + * @return + */ + @OperationLog(module = LogModule.CONTRACT_INDEX, type = LogType.ADD, resourceName = "{#request.name}") + public Contract add(ContractAddRequest request, String operatorId, String orgId) { + List moduleFields = request.getModuleFields(); + ModuleFormConfigDTO moduleFormConfigDTO = request.getModuleFormConfigDTO(); + Contract contract = new Contract(); + String id = IDGenerator.nextStr(); + contract.setId(id); + contract.setName(request.getName()); + contract.setCustomerId(request.getCustomerId()); + contract.setAmount(request.getAmount()); + contract.setOwner(request.getOwner()); + //todo number + contract.setNumber(id); + contract.setStatus(ContractStatus.SIGNED.name()); + contract.setArchivedStatus(ArchivedStatus.UN_ARCHIVED.name()); + contract.setCreateTime(System.currentTimeMillis()); + contract.setCreateUser(operatorId); + contract.setUpdateTime(System.currentTimeMillis()); + contract.setUpdateUser(operatorId); + + //自定义字段 + contractFieldService.saveModuleField(contract, orgId, operatorId, moduleFields, false); + contractMapper.insert(contract); + + baseService.handleAddLog(contract, request.getModuleFields()); + + // 保存表单配置快照 + OpportunityQuotationGetResponse response = getContractResponse(contract, moduleFields, moduleFormConfigDTO); + saveSnapshot(contract, moduleFormConfigDTO, response); + + return contract; + } + + + /** + * 保存合同快照 + * @param contract + * @param moduleFormConfigDTO + * @param response + */ + private void saveSnapshot(Contract contract, ModuleFormConfigDTO moduleFormConfigDTO, OpportunityQuotationGetResponse response) { + ContractSnapshot snapshot = new ContractSnapshot(); + snapshot.setId(IDGenerator.nextStr()); + snapshot.setContractId(contract.getId()); + snapshot.setContractProp(JSON.toJSONString(moduleFormConfigDTO)); + snapshot.setContractValue(JSON.toJSONString(response)); + snapshotBaseMapper.insert(snapshot); + + } + + + /** + * 获取合同详情 + * @param contract + * @param moduleFields + * @param moduleFormConfigDTO + * @return + */ + private OpportunityQuotationGetResponse getContractResponse(Contract contract, List moduleFields, ModuleFormConfigDTO moduleFormConfigDTO) { + OpportunityQuotationGetResponse response = BeanUtils.copyBean(new OpportunityQuotationGetResponse(), contract); + response.setModuleFields(moduleFields); + Map> optionMap = moduleFormService.getOptionMap(moduleFormConfigDTO, moduleFields); + response.setOptionMap(optionMap); + Map> attachmentMap = moduleFormService.getAttachmentMap(moduleFormConfigDTO, moduleFields); + response.setAttachmentMap(attachmentMap); + return baseService.setCreateAndUpdateUserName(response); + } + + + /** + * 编辑合同 + * + * @param request + * @param userId + * @param orgId + * @return + */ + @OperationLog(module = LogModule.CONTRACT_INDEX, type = LogType.UPDATE, resourceId = "{#request.id}") + public Contract update(ContractUpdateRequest request, String userId, String orgId) { + Contract oldContract = contractMapper.selectByPrimaryKey(request.getId()); + List moduleFields = request.getModuleFields(); + Optional.ofNullable(oldContract).ifPresentOrElse(item -> { + if (Strings.CI.equals(oldContract.getArchivedStatus(), ArchivedStatus.ARCHIVED.name())) { + throw new GenericException(Translator.get("contract.archived.cannot.edit")); + } + if (Strings.CI.equals((oldContract.getStatus()), ContractStatus.VOID.name())) { + throw new GenericException(Translator.get("contract.void.cannot.edit")); + } + List originFields = contractFieldService.getModuleFieldValuesByResourceId(request.getId()); + Contract contract = BeanUtils.copyBean(new Contract(), request); + contract.setUpdateTime(System.currentTimeMillis()); + contract.setUpdateUser(userId); + updateFields(moduleFields, contract, orgId, userId); + contractMapper.update(contract); + // 处理日志上下文 + baseService.handleUpdateLog(oldContract, contract, originFields, moduleFields, request.getId(), contract.getName()); + + //删除快照 + LambdaQueryWrapper delWrapper = new LambdaQueryWrapper<>(); + delWrapper.eq(ContractSnapshot::getContractId, request.getId()); + snapshotBaseMapper.deleteByLambda(delWrapper); + //保存快照 + OpportunityQuotationGetResponse response = getContractResponse(contract, moduleFields, request.getModuleFormConfigDTO()); + saveSnapshot(contract, request.getModuleFormConfigDTO(), response); + + + }, () -> { + throw new GenericException(Translator.get("contract.not.exist")); + }); + return contractMapper.selectByPrimaryKey(request.getId()); + } + + + /** + * 更新自定义字段 + * @param moduleFields + * @param contract + * @param orgId + * @param userId + */ + private void updateFields(List moduleFields, Contract contract, String orgId, String userId) { + if (moduleFields == null) { + return; + } + contractFieldService.deleteByResourceId(contract.getId()); + contractFieldService.saveModuleField(contract, orgId, userId, moduleFields, false); + } + + + /** + * 删除合同 + * @param id + */ + @OperationLog(module = LogModule.CONTRACT_INDEX, type = LogType.DELETE, resourceId = "{#id}") + public void delete(String id) { + Contract contract = contractMapper.selectByPrimaryKey(id); + if(contract == null){ + throw new GenericException(Translator.get("contract.not.exist")); + } + if (Strings.CI.equals(contract.getArchivedStatus(), ArchivedStatus.ARCHIVED.name())) { + throw new GenericException(Translator.get("contract.archived.cannot.delete")); + } + + contractFieldService.deleteByResourceId(id); + contractMapper.deleteByPrimaryKey(id); + + //删除快照 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(ContractSnapshot::getContractId, id); + snapshotBaseMapper.deleteByLambda(wrapper); + // 添加日志上下文 + OperationLogContext.setResourceName(contract.getName()); + } +} diff --git a/backend/crm/src/main/java/cn/cordys/crm/system/service/ModuleFieldService.java b/backend/crm/src/main/java/cn/cordys/crm/system/service/ModuleFieldService.java index 31ebe2da4..dec3d12a7 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/system/service/ModuleFieldService.java +++ b/backend/crm/src/main/java/cn/cordys/crm/system/service/ModuleFieldService.java @@ -41,6 +41,7 @@ public class ModuleFieldService { FORM_TABLE.put(FormKey.PRODUCT.getKey(), "product"); FORM_TABLE.put(FormKey.FOLLOW_RECORD.getKey(), "follow_up_record"); FORM_TABLE.put(FormKey.FOLLOW_PLAN.getKey(), "follow_up_plan"); + FORM_TABLE.put(FormKey.CONTRACT.getKey(), "contract"); } @Resource diff --git a/backend/crm/src/main/resources/form/field.json b/backend/crm/src/main/resources/form/field.json index 9f3eb7321..0a70e2089 100644 --- a/backend/crm/src/main/resources/form/field.json +++ b/backend/crm/src/main/resources/form/field.json @@ -1214,5 +1214,58 @@ } ] } + ], + "contract": [ + { + "name": "基本信息", + "internalKey": "contractBasicInfo", + "type": "DIVIDER", + "showLabel": true, + "readable": true, + "fieldWidth": 1, + "dividerClass": "divider--normal", + "dividerColor": "#edf0f1", + "titleColor": "#323535" + }, + { + "name": "合同", + "internalKey": "contractName", + "type": "INPUT", + "showLabel": true, + "readable": true, + "editable": true, + "fieldWidth": 1, + "rules": [ + {"key": "required"}, + {"key": "unique"} + ] + }, + { + "name": "客户名称", + "internalKey": "contractOpportunity", + "type": "DATA_SOURCE", + "dataSourceType": "CUSTOMER", + "showLabel": true, + "readable": true, + "editable": true, + "fieldWidth": 1, + "rules": [ + {"key": "required"} + ], + "mobile": true + }, + { + "name": "负责人", + "internalKey": "contractOwner", + "type": "MEMBER", + "hasCurrentUser": true, + "showLabel": true, + "readable": true, + "editable": true, + "fieldWidth": 1, + "rules": [ + {"key": "required"} + ] + } ] } \ No newline at end of file diff --git a/backend/crm/src/main/resources/i18n/cordys-crm_en_US.properties b/backend/crm/src/main/resources/i18n/cordys-crm_en_US.properties index d32390133..e9f6c36d3 100644 --- a/backend/crm/src/main/resources/i18n/cordys-crm_en_US.properties +++ b/backend/crm/src/main/resources/i18n/cordys-crm_en_US.properties @@ -623,4 +623,10 @@ log.endRollBack=Final stage rollback dashboard_url_not_allowed=Dashboard address denied access log.mkAddress=MaxKB Address log.apikey=API Key -log.mkEnable=Status \ No newline at end of file +log.mkEnable=Status + +#contract +contract.not.exist=Contract does not exist +contract.archived.cannot.edit=Archived contracts cannot be edited! +contract.void.cannot.edit=Voided contracts cannot be edited! +contract.archived.cannot.delete=Archived contracts cannot be deleted! \ No newline at end of file diff --git a/backend/crm/src/main/resources/i18n/cordys-crm_zh_CN.properties b/backend/crm/src/main/resources/i18n/cordys-crm_zh_CN.properties index 1577d449e..fc82b1cf3 100644 --- a/backend/crm/src/main/resources/i18n/cordys-crm_zh_CN.properties +++ b/backend/crm/src/main/resources/i18n/cordys-crm_zh_CN.properties @@ -624,3 +624,9 @@ dashboard_url_not_allowed=仪表板地址拒绝访问 log.mkAddress=MaxKB 地址 log.apiKey=API Key log.mkEnable=状态 + +#contract +contract.not.exist=合同不存在 +contract.archived.cannot.edit=合同已归档,无法编辑! +contract.void.cannot.edit=合同已作废,无法编辑! +contract.archived.cannot.delete=合同已归档,无法删除! \ No newline at end of file diff --git a/backend/crm/src/main/resources/migration/1.4.0/ddl/V1.4.0_2__ga_ddl.sql b/backend/crm/src/main/resources/migration/1.4.0/ddl/V1.4.0_2__ga_ddl.sql index f180117ba..60c507705 100644 --- a/backend/crm/src/main/resources/migration/1.4.0/ddl/V1.4.0_2__ga_ddl.sql +++ b/backend/crm/src/main/resources/migration/1.4.0/ddl/V1.4.0_2__ga_ddl.sql @@ -88,20 +88,20 @@ CREATE INDEX idx_quotation_id ON opportunity_quotation_snapshot (quotation_id AS CREATE TABLE contract ( - `id` VARCHAR(32) NOT NULL COMMENT 'id', - `name` VARCHAR(255) NOT NULL COMMENT '合同名称', - `customer_id` VARCHAR(32) NOT NULL COMMENT '客户id', - `owner` VARCHAR(32) NOT NULL COMMENT '合同负责人', - `amount` DECIMAL(20, 10) COMMENT '金额', - `number` VARCHAR(50) NOT NULL COMMENT '编号', - `review_status` VARCHAR(50) NOT NULL COMMENT '审核状态', - `archived_status` VARCHAR(50) NOT NULL COMMENT '归档状态', - `voided_status` VARCHAR(50) NOT NULL COMMENT '作废状态', - `organization_id` VARCHAR(32) NOT NULL COMMENT '组织id', - `create_time` BIGINT NOT NULL COMMENT '创建时间', - `update_time` BIGINT NOT NULL COMMENT '更新时间', - `create_user` VARCHAR(32) NOT NULL COMMENT '创建人', - `update_user` VARCHAR(32) NOT NULL COMMENT '更新人', + `id` VARCHAR(32) NOT NULL COMMENT 'id', + `name` VARCHAR(255) NOT NULL COMMENT '合同名称', + `customer_id` VARCHAR(32) NOT NULL COMMENT '客户id', + `owner` VARCHAR(32) NOT NULL COMMENT '合同负责人', + `amount` DECIMAL(20, 10) COMMENT '金额', + `number` VARCHAR(50) NOT NULL COMMENT '编号', + `review_status` VARCHAR(50) COMMENT '审核状态', + `archived_status` VARCHAR(50) NOT NULL COMMENT '归档状态', + `status` VARCHAR(50) NOT NULL COMMENT '合同状态', + `organization_id` VARCHAR(32) NOT NULL COMMENT '组织id', + `create_time` BIGINT NOT NULL COMMENT '创建时间', + `update_time` BIGINT NOT NULL COMMENT '更新时间', + `create_user` VARCHAR(32) NOT NULL COMMENT '创建人', + `update_user` VARCHAR(32) NOT NULL COMMENT '更新人', PRIMARY KEY (id) ) COMMENT = '合同' ENGINE = InnoDB @@ -115,17 +115,17 @@ CREATE INDEX idx_number ON contract (number ASC); CREATE INDEX idx_organization_id ON contract (organization_id ASC); CREATE INDEX idx_review_status ON contract (review_status ASC); CREATE INDEX idx_archived_status ON contract (archived_status ASC); -CREATE INDEX idx_voided_status ON contract (voided_status ASC); +CREATE INDEX idx_status ON contract (status ASC); CREATE TABLE contract_field ( - `id` VARCHAR(32) NOT NULL COMMENT 'id', - `resource_id` VARCHAR(32) NOT NULL COMMENT '合同id', - `field_id` VARCHAR(32) NOT NULL COMMENT '自定义属性id', - `field_value` VARCHAR(255) NOT NULL COMMENT '自定义属性值', - `ref_sub_id` VARCHAR(32) COMMENT '引用子表格ID;关联的子表格字段ID', - `row_id` VARCHAR(32) COMMENT '子表格行实例ID;行实例数据ID', + `id` VARCHAR(32) NOT NULL COMMENT 'id', + `resource_id` VARCHAR(32) NOT NULL COMMENT '合同id', + `field_id` VARCHAR(32) NOT NULL COMMENT '自定义属性id', + `field_value` VARCHAR(255) NOT NULL COMMENT '自定义属性值', + `ref_sub_id` VARCHAR(32) COMMENT '引用子表格ID;关联的子表格字段ID', + `row_id` VARCHAR(32) COMMENT '子表格行实例ID;行实例数据ID', PRIMARY KEY (id) ) COMMENT = '合同自定义属性' ENGINE = InnoDB @@ -153,54 +153,73 @@ COLLATE = utf8mb4_general_ci; CREATE INDEX idx_resource_id ON contract_field_blob (resource_id ASC); CREATE INDEX idx_ref_sub_id ON contract_field_blob (ref_sub_id ASC); + +CREATE TABLE contract_snapshot +( + `id` VARCHAR(32) NOT NULL COMMENT 'id', + `contract_id` VARCHAR(32) NOT NULL COMMENT '合同id', + `contract_prop` TEXT(255) COMMENT '表单属性快照', + `contract_value` TEXT(255) COMMENT '表单值快照', + PRIMARY KEY (id) +) COMMENT = '合同快照' +ENGINE = InnoDB +DEFAULT CHARSET = utf8mb4 +COLLATE = utf8mb4_general_ci; + + +CREATE INDEX idx_contract_id ON contract_snapshot (contract_id ASC); + -- 回款计划 -CREATE TABLE contract_payment_plan( - `id` VARCHAR(32) NOT NULL COMMENT 'id' , - `contract_id` VARCHAR(32) NOT NULL COMMENT '合同ID' , - `owner` VARCHAR(32) NOT NULL COMMENT '负责人' , - `plan_status` VARCHAR(32) NOT NULL COMMENT '计划状态' , - `plan_amount` DECIMAL(20,10) COMMENT '计划回款金额' , - `plan_end_time` BIGINT COMMENT '计划回款时间' , - `organization_id` VARCHAR(32) NOT NULL COMMENT '组织id' , - `create_time` BIGINT NOT NULL COMMENT '创建时间' , - `update_time` BIGINT NOT NULL COMMENT '更新时间' , - `create_user` VARCHAR(32) NOT NULL COMMENT '创建人' , - `update_user` VARCHAR(32) NOT NULL COMMENT '更新人' , +CREATE TABLE contract_payment_plan +( + `id` VARCHAR(32) NOT NULL COMMENT 'id', + `contract_id` VARCHAR(32) NOT NULL COMMENT '合同ID', + `owner` VARCHAR(32) NOT NULL COMMENT '负责人', + `plan_status` VARCHAR(32) NOT NULL COMMENT '计划状态', + `plan_amount` DECIMAL(20, 10) COMMENT '计划回款金额', + `plan_end_time` BIGINT COMMENT '计划回款时间', + `organization_id` VARCHAR(32) NOT NULL COMMENT '组织id', + `create_time` BIGINT NOT NULL COMMENT '创建时间', + `update_time` BIGINT NOT NULL COMMENT '更新时间', + `create_user` VARCHAR(32) NOT NULL COMMENT '创建人', + `update_user` VARCHAR(32) NOT NULL COMMENT '更新人', PRIMARY KEY (id) -) COMMENT = '合同回款计划' +) COMMENT = '合同回款计划' ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci; -CREATE INDEX idx_contract_id ON contract_payment_plan(contract_id ASC); -CREATE INDEX idx_create_time ON contract_payment_plan(create_time ASC); -CREATE INDEX idx_owner ON contract_payment_plan(owner ASC); +CREATE INDEX idx_contract_id ON contract_payment_plan (contract_id ASC); +CREATE INDEX idx_create_time ON contract_payment_plan (create_time ASC); +CREATE INDEX idx_owner ON contract_payment_plan (owner ASC); -CREATE TABLE contract_payment_plan_field( - `id` VARCHAR(32) NOT NULL COMMENT 'id' , - `resource_id` VARCHAR(32) NOT NULL COMMENT '回款计划id' , - `field_id` VARCHAR(32) NOT NULL COMMENT '自定义属性id' , - `field_value` VARCHAR(255) NOT NULL COMMENT '自定义属性值', +CREATE TABLE contract_payment_plan_field +( + `id` VARCHAR(32) NOT NULL COMMENT 'id', + `resource_id` VARCHAR(32) NOT NULL COMMENT '回款计划id', + `field_id` VARCHAR(32) NOT NULL COMMENT '自定义属性id', + `field_value` VARCHAR(255) NOT NULL COMMENT '自定义属性值', PRIMARY KEY (id) -) COMMENT = '回款计划自定义属性' +) COMMENT = '回款计划自定义属性' ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci; -CREATE INDEX idx_resource_id ON contract_payment_plan_field(resource_id ASC); +CREATE INDEX idx_resource_id ON contract_payment_plan_field (resource_id ASC); -CREATE TABLE contract_payment_plan_field_blob( - `id` VARCHAR(32) NOT NULL COMMENT 'id' , - `resource_id` VARCHAR(32) NOT NULL COMMENT '回款计划id' , - `field_id` VARCHAR(32) NOT NULL COMMENT '自定义属性id' , - `field_value` TEXT NOT NULL COMMENT '自定义属性值' , +CREATE TABLE contract_payment_plan_field_blob +( + `id` VARCHAR(32) NOT NULL COMMENT 'id', + `resource_id` VARCHAR(32) NOT NULL COMMENT '回款计划id', + `field_id` VARCHAR(32) NOT NULL COMMENT '自定义属性id', + `field_value` TEXT NOT NULL COMMENT '自定义属性值', PRIMARY KEY (id) -) COMMENT = '回款计划自定义属性大文本' +) COMMENT = '回款计划自定义属性大文本' ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci; -CREATE INDEX idx_resource_id ON contract_payment_plan_field_blob(resource_id ASC); +CREATE INDEX idx_resource_id ON contract_payment_plan_field_blob (resource_id ASC); -- set innodb lock wait timeout to default diff --git a/backend/framework/src/main/java/cn/cordys/aspectj/constants/LogModule.java b/backend/framework/src/main/java/cn/cordys/aspectj/constants/LogModule.java index 403c16ef9..cb6c11bd5 100644 --- a/backend/framework/src/main/java/cn/cordys/aspectj/constants/LogModule.java +++ b/backend/framework/src/main/java/cn/cordys/aspectj/constants/LogModule.java @@ -125,4 +125,6 @@ public class LogModule { */ public static final String DASHBOARD = "DASHBOARD"; public static final String AGENT = "AGENT"; + + public static final String CONTRACT_INDEX = "CONTRACT_INDEX"; }