diff --git a/backend/core/src/main/java/org/opencdmp/commons/types/planblueprint/importexport/BlueprintImportExport.java b/backend/core/src/main/java/org/opencdmp/commons/types/planblueprint/importexport/BlueprintImportExport.java index 534d6970a..c7caa37fa 100644 --- a/backend/core/src/main/java/org/opencdmp/commons/types/planblueprint/importexport/BlueprintImportExport.java +++ b/backend/core/src/main/java/org/opencdmp/commons/types/planblueprint/importexport/BlueprintImportExport.java @@ -17,6 +17,9 @@ public class BlueprintImportExport { @XmlElement(name = "label") private String label; + @XmlElement(name = "code") + private String code; + @XmlElement(name = "definition") private BlueprintDefinitionImportExport planBlueprintDefinition; @@ -39,6 +42,14 @@ public class BlueprintImportExport { this.label = label; } + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + public BlueprintDefinitionImportExport getPlanBlueprintDefinition() { return this.planBlueprintDefinition; } diff --git a/backend/core/src/main/java/org/opencdmp/data/PlanBlueprintEntity.java b/backend/core/src/main/java/org/opencdmp/data/PlanBlueprintEntity.java index 612fb012d..ebbedd977 100644 --- a/backend/core/src/main/java/org/opencdmp/data/PlanBlueprintEntity.java +++ b/backend/core/src/main/java/org/opencdmp/data/PlanBlueprintEntity.java @@ -31,6 +31,11 @@ public class PlanBlueprintEntity extends TenantScopedBaseEntity { public static final int _labelLength = 250; + @Column(name = "code", length = _codeLength, nullable = false) + private String code; + public final static String _code = "code"; + public final static int _codeLength = 200; + @Type(SQLXMLType.class) @Column(name = "definition", columnDefinition = "xml") private String definition; @@ -91,6 +96,14 @@ public class PlanBlueprintEntity extends TenantScopedBaseEntity { this.label = label; } + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + public String getDefinition() { return this.definition; } diff --git a/backend/core/src/main/java/org/opencdmp/errorcode/ErrorThesaurusProperties.java b/backend/core/src/main/java/org/opencdmp/errorcode/ErrorThesaurusProperties.java index cd0b52f2c..0a5048f0d 100644 --- a/backend/core/src/main/java/org/opencdmp/errorcode/ErrorThesaurusProperties.java +++ b/backend/core/src/main/java/org/opencdmp/errorcode/ErrorThesaurusProperties.java @@ -458,4 +458,24 @@ public class ErrorThesaurusProperties { public void setDescriptionTemplateImportNotFound(ErrorDescription descriptionTemplateImportNotFound) { this.descriptionTemplateImportNotFound = descriptionTemplateImportNotFound; } + + private ErrorDescription planBlueprintCodeExists; + + public ErrorDescription getPlanBlueprintCodeExists() { + return planBlueprintCodeExists; + } + + public void setPlanBlueprintCodeExists(ErrorDescription planBlueprintCodeExists) { + this.planBlueprintCodeExists = planBlueprintCodeExists; + } + + private ErrorDescription planBlueprintImportNotFound; + + public ErrorDescription getPlanBlueprintImportNotFound() { + return planBlueprintImportNotFound; + } + + public void setPlanBlueprintImportNotFound(ErrorDescription planBlueprintImportNotFound) { + this.planBlueprintImportNotFound = planBlueprintImportNotFound; + } } diff --git a/backend/core/src/main/java/org/opencdmp/model/builder/planblueprint/PlanBlueprintBuilder.java b/backend/core/src/main/java/org/opencdmp/model/builder/planblueprint/PlanBlueprintBuilder.java index 1085ed905..55b736e47 100644 --- a/backend/core/src/main/java/org/opencdmp/model/builder/planblueprint/PlanBlueprintBuilder.java +++ b/backend/core/src/main/java/org/opencdmp/model/builder/planblueprint/PlanBlueprintBuilder.java @@ -62,6 +62,8 @@ public class PlanBlueprintBuilder extends BaseBuilder !this.isNull(item.getStatus())) .failOn(PlanBlueprintPersist._status).failWith(this.messageSource.getMessage("Validation_Required", new Object[]{PlanBlueprintPersist._status}, LocaleContextHolder.getLocale())), - + this.spec() + .must(() -> !this.isEmpty(item.getCode())) + .failOn(PlanBlueprintPersist._code).failWith(messageSource.getMessage("Validation_Required", new Object[]{PlanBlueprintPersist._code}, LocaleContextHolder.getLocale())), + this.spec() + .iff(() -> !this.isEmpty(item.getCode())) + .must(() -> this.lessEqualLength(item.getCode(), PlanBlueprintEntity._codeLength)) + .failOn(PlanBlueprintPersist._code).failWith(messageSource.getMessage("Validation_MaxLength", new Object[]{PlanBlueprintPersist._code}, LocaleContextHolder.getLocale())), this.spec() .iff(() -> item.getStatus() == PlanBlueprintStatus.Finalized) .must(() -> !this.isNull(item.getDefinition())) diff --git a/backend/core/src/main/java/org/opencdmp/model/planblueprint/PlanBlueprint.java b/backend/core/src/main/java/org/opencdmp/model/planblueprint/PlanBlueprint.java index fdaed6d40..19af2bae6 100644 --- a/backend/core/src/main/java/org/opencdmp/model/planblueprint/PlanBlueprint.java +++ b/backend/core/src/main/java/org/opencdmp/model/planblueprint/PlanBlueprint.java @@ -17,6 +17,11 @@ public class PlanBlueprint { public static final String _label = "label"; + private String code; + + public final static String _code = "code"; + + private Definition definition; public static final String _definition = "definition"; @@ -72,6 +77,14 @@ public class PlanBlueprint { this.label = label; } + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + public Definition getDefinition() { return definition; } diff --git a/backend/core/src/main/java/org/opencdmp/query/PlanBlueprintQuery.java b/backend/core/src/main/java/org/opencdmp/query/PlanBlueprintQuery.java index c64975b8c..dfa116794 100644 --- a/backend/core/src/main/java/org/opencdmp/query/PlanBlueprintQuery.java +++ b/backend/core/src/main/java/org/opencdmp/query/PlanBlueprintQuery.java @@ -41,6 +41,8 @@ public class PlanBlueprintQuery extends QueryBase { private Collection versions; + private Collection codes; + private Collection versionStatuses; private EnumSet authorize = EnumSet.of(AuthorizationFlags.None); @@ -155,6 +157,21 @@ public class PlanBlueprintQuery extends QueryBase { return this; } + public PlanBlueprintQuery codes(String value) { + this.codes = List.of(value); + return this; + } + + public PlanBlueprintQuery codes(String... value) { + this.codes = Arrays.asList(value); + return this; + } + + public PlanBlueprintQuery codes(Collection values) { + this.codes = values; + return this; + } + public PlanBlueprintQuery authorize(EnumSet values) { this.authorize = values; return this; @@ -213,7 +230,9 @@ public class PlanBlueprintQuery extends QueryBase { } if (this.like != null && !this.like.isBlank()) { - predicates.add(this.queryUtilsService.ilike(queryContext.CriteriaBuilder, queryContext.Root.get(PlanBlueprintEntity._label), this.like)); + predicates.add(queryContext.CriteriaBuilder.or(this.queryUtilsService.ilike(queryContext.CriteriaBuilder, queryContext.Root.get(PlanBlueprintEntity._label), this.like), + this.queryUtilsService.ilike(queryContext.CriteriaBuilder, queryContext.Root.get(PlanBlueprintEntity._code), this.like) + )); } if (this.isActives != null) { @@ -251,6 +270,13 @@ public class PlanBlueprintQuery extends QueryBase { predicates.add(inClause); } + if (this.codes != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(PlanBlueprintEntity._code)); + for (String item : this.codes) + inClause.value(item); + predicates.add(inClause); + } + if (!predicates.isEmpty()) { Predicate[] predicatesArray = predicates.toArray(new Predicate[0]); return queryContext.CriteriaBuilder.and(predicatesArray); @@ -265,6 +291,7 @@ public class PlanBlueprintQuery extends QueryBase { item.setId(QueryBase.convertSafe(tuple, columns, PlanBlueprintEntity._id, UUID.class)); item.setTenantId(QueryBase.convertSafe(tuple, columns, PlanBlueprintEntity._tenantId, UUID.class)); item.setLabel(QueryBase.convertSafe(tuple, columns, PlanBlueprintEntity._label, String.class)); + item.setCode(QueryBase.convertSafe(tuple, columns, PlanBlueprintEntity._code, String.class)); item.setDefinition(QueryBase.convertSafe(tuple, columns, PlanBlueprintEntity._definition, String.class)); item.setStatus(QueryBase.convertSafe(tuple, columns, PlanBlueprintEntity._status, PlanBlueprintStatus.class)); item.setGroupId(QueryBase.convertSafe(tuple, columns, PlanBlueprintEntity._groupId, UUID.class)); @@ -282,6 +309,8 @@ public class PlanBlueprintQuery extends QueryBase { return PlanBlueprintEntity._id; else if (item.match(PlanBlueprint._label)) return PlanBlueprintEntity._label; + else if (item.match(PlanBlueprint._code)) + return PlanBlueprintEntity._code; else if (item.match(PlanBlueprint._definition)) return PlanBlueprintEntity._definition; else if (item.prefix(PlanBlueprint._definition)) diff --git a/backend/core/src/main/java/org/opencdmp/service/description/DescriptionServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/description/DescriptionServiceImpl.java index ab685a282..35a1dfa16 100644 --- a/backend/core/src/main/java/org/opencdmp/service/description/DescriptionServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/description/DescriptionServiceImpl.java @@ -1367,8 +1367,8 @@ public class DescriptionServiceImpl implements DescriptionService { if (descriptionXml.getDescriptionTemplate() != null) { - DescriptionTemplateEntity descriptionTemplateEntity = this.queryFactory.query(DescriptionTemplateQuery.class).disableTracking().ids(UUID.randomUUID()).first(); - if (descriptionTemplateEntity == null) descriptionTemplateEntity = this.queryFactory.query(DescriptionTemplateQuery.class).disableTracking().groupIds(UUID.randomUUID()).versionStatuses(DescriptionTemplateVersionStatus.Current).isActive(IsActive.Active).statuses(DescriptionTemplateStatus.Finalized).first(); + DescriptionTemplateEntity descriptionTemplateEntity = this.queryFactory.query(DescriptionTemplateQuery.class).disableTracking().ids(descriptionXml.getDescriptionTemplate().getId()).first(); + if (descriptionTemplateEntity == null) descriptionTemplateEntity = this.queryFactory.query(DescriptionTemplateQuery.class).disableTracking().groupIds(descriptionXml.getDescriptionTemplate().getGroupId()).versionStatuses(DescriptionTemplateVersionStatus.Current).isActive(IsActive.Active).statuses(DescriptionTemplateStatus.Finalized).first(); UUID descriptionTemplateId; if (descriptionTemplateEntity != null){ descriptionTemplateId = descriptionTemplateEntity.getId(); diff --git a/backend/core/src/main/java/org/opencdmp/service/descriptiontemplate/DescriptionTemplateServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/descriptiontemplate/DescriptionTemplateServiceImpl.java index ee00dbd94..bad3ca74b 100644 --- a/backend/core/src/main/java/org/opencdmp/service/descriptiontemplate/DescriptionTemplateServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/descriptiontemplate/DescriptionTemplateServiceImpl.java @@ -214,12 +214,10 @@ public class DescriptionTemplateServiceImpl implements DescriptionTemplateServic data.setUpdatedAt(Instant.now()); data.setDefinition(this.xmlHandlingService.toXml(this.buildDefinitionEntity(model.getDefinition()))); - Long descriptionTemplateCodes = 0L; - if (model.getCode() != null) descriptionTemplateCodes = this.queryFactory.query(DescriptionTemplateQuery.class).disableTracking().codes(model.getCode()).count(); - if (isUpdate) { this.entityManager.merge(data); } else { + Long descriptionTemplateCodes = this.queryFactory.query(DescriptionTemplateQuery.class).disableTracking().codes(model.getCode()).count(); if (descriptionTemplateCodes > 0) throw new MyValidationException(this.errors.getDescriptionTemplateCodeExists().getCode(), this.errors.getDescriptionTemplateCodeExists().getMessage()); this.entityManager.persist(data); this.accountingService.increase(UsageLimitTargetMetric.DESCRIPTION_TEMPLATE_COUNT.getValue()); diff --git a/backend/core/src/main/java/org/opencdmp/service/descriptiontemplatetype/DescriptionTemplateTypeServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/descriptiontemplatetype/DescriptionTemplateTypeServiceImpl.java index f41516b8c..9030f5fb7 100644 --- a/backend/core/src/main/java/org/opencdmp/service/descriptiontemplatetype/DescriptionTemplateTypeServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/descriptiontemplatetype/DescriptionTemplateTypeServiceImpl.java @@ -103,6 +103,8 @@ public class DescriptionTemplateTypeServiceImpl implements DescriptionTemplateTy data = this.entityManager.find(DescriptionTemplateTypeEntity.class, model.getId()); if (data == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), DescriptionTemplateType.class.getSimpleName()}, LocaleContextHolder.getLocale())); if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage()); + if (!data.getCode().equals(model.getCode())) + throw new MyForbiddenException("Code can not change"); } else { this.usageLimitService.checkIncrease(UsageLimitTargetMetric.DESCRIPTION_TEMPLATE_TYPE_COUNT); data = new DescriptionTemplateTypeEntity(); @@ -116,12 +118,10 @@ public class DescriptionTemplateTypeServiceImpl implements DescriptionTemplateTy data.setStatus(model.getStatus()); data.setUpdatedAt(Instant.now()); - Long descriptionTemplateTypeCodes = this.queryFactory.query(DescriptionTemplateTypeQuery.class).disableTracking().codes(model.getCode()).count(); - if (isUpdate) { - if (descriptionTemplateTypeCodes > 1) throw new MyValidationException(this.errors.getDescriptionTemplateTypeCodeExists().getCode(), this.errors.getDescriptionTemplateTypeCodeExists().getMessage()); this.entityManager.merge(data); } else { + Long descriptionTemplateTypeCodes = this.queryFactory.query(DescriptionTemplateTypeQuery.class).disableTracking().codes(model.getCode()).count(); if (descriptionTemplateTypeCodes > 0) throw new MyValidationException(this.errors.getDescriptionTemplateTypeCodeExists().getCode(), this.errors.getDescriptionTemplateTypeCodeExists().getMessage()); this.entityManager.persist(data); this.accountingService.increase(UsageLimitTargetMetric.DESCRIPTION_TEMPLATE_TYPE_COUNT.getValue()); diff --git a/backend/core/src/main/java/org/opencdmp/service/plan/PlanServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/plan/PlanServiceImpl.java index 2451ea6c6..fe12d3ceb 100644 --- a/backend/core/src/main/java/org/opencdmp/service/plan/PlanServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/plan/PlanServiceImpl.java @@ -1912,8 +1912,12 @@ public class PlanServiceImpl implements PlanService { if (planBlueprintEntity != null){ return planBlueprintEntity.getId(); } else { - PlanBlueprint persisted = this.planBlueprintService.importXml(planXml.getBlueprint(), null, planXml.getBlueprint().getLabel(), new BaseFieldSet().ensure(PlanBlueprint._label).ensure(PlanBlueprint._hash)); - return persisted.getId(); + planBlueprintEntity = this.queryFactory.query(PlanBlueprintQuery.class).disableTracking().codes(planXml.getBlueprint().getCode()).first(); + if (planBlueprintEntity == null) { + throw new MyValidationException(this.errors.getPlanBlueprintImportNotFound().getCode(), planXml.getBlueprint().getCode()); + } else { + return planBlueprintEntity.getId(); + } } } return null; diff --git a/backend/core/src/main/java/org/opencdmp/service/planblueprint/PlanBlueprintServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/planblueprint/PlanBlueprintServiceImpl.java index f10c30432..76252426f 100644 --- a/backend/core/src/main/java/org/opencdmp/service/planblueprint/PlanBlueprintServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/planblueprint/PlanBlueprintServiceImpl.java @@ -137,6 +137,8 @@ public class PlanBlueprintServiceImpl implements PlanBlueprintService { throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage()); if (data.getStatus().equals(PlanBlueprintStatus.Finalized)) throw new MyForbiddenException("Cannot update finalized blueprint"); + if (!data.getCode().equals(model.getCode())) + throw new MyForbiddenException("Code can not change"); } else { this.usageLimitService.checkIncrease(UsageLimitTargetMetric.BLUEPRINT_COUNT); data = new PlanBlueprintEntity(); @@ -162,13 +164,16 @@ public class PlanBlueprintServiceImpl implements PlanBlueprintService { } data.setLabel(model.getLabel()); + data.setCode(model.getCode()); data.setStatus(model.getStatus()); data.setUpdatedAt(Instant.now()); data.setDefinition(this.xmlHandlingService.toXml(this.buildDefinitionEntity(model.getDefinition()))); - if (isUpdate) + if (isUpdate) { this.entityManager.merge(data); - else{ + } else { + Long planBlueprintCodes = this.queryFactory.query(PlanBlueprintQuery.class).disableTracking().codes(model.getCode()).count(); + if (planBlueprintCodes > 0) throw new MyValidationException(this.errors.getPlanBlueprintCodeExists().getCode(), this.errors.getPlanBlueprintCodeExists().getMessage()); this.entityManager.persist(data); this.accountingService.increase(UsageLimitTargetMetric.BLUEPRINT_COUNT.getValue()); } @@ -465,6 +470,7 @@ public class PlanBlueprintServiceImpl implements PlanBlueprintService { data.setStatus(PlanBlueprintStatus.Draft); data.setDefinition(this.xmlHandlingService.toXml(this.buildDefinitionEntity(model.getDefinition()))); data.setGroupId(oldPlanBlueprintEntity.getGroupId()); + data.setCode(oldPlanBlueprintEntity.getCode()); data.setVersion((short) (oldPlanBlueprintEntity.getVersion() + 1)); data.setVersionStatus(PlanBlueprintVersionStatus.NotFinalized); data.setCreatedAt(Instant.now()); @@ -518,6 +524,7 @@ public class PlanBlueprintServiceImpl implements PlanBlueprintService { BlueprintImportExport xml = new BlueprintImportExport(); xml.setId(entity.getId()); xml.setLabel(entity.getLabel()); + xml.setCode(entity.getCode()); xml.setGroupId(entity.getGroupId()); DefinitionEntity planBlueprintDefinition = this.xmlHandlingService.fromXml(DefinitionEntity.class, entity.getDefinition()); xml.setPlanBlueprintDefinition(this.definitionXmlToExport(planBlueprintDefinition)); @@ -669,23 +676,43 @@ public class PlanBlueprintServiceImpl implements PlanBlueprintService { .groupIds(groupId) .count() : 0; + if (activeBlueprintForTheGroup == 0 && !this.conventionService.isNullOrEmpty(planBlueprintDefinition.getCode())) { + this.queryFactory.query(PlanBlueprintQuery.class).disableTracking() + .isActive(IsActive.Active) + .codes(planBlueprintDefinition.getCode()) + .count(); + } + if (activeBlueprintForTheGroup == 0) { PlanBlueprintPersist persist = new PlanBlueprintPersist(); persist.setLabel(label); + persist.setCode(planBlueprintDefinition.getCode()); persist.setStatus(PlanBlueprintStatus.Draft); persist.setDefinition(this.xmlDefinitionToPersist(planBlueprintDefinition.getPlanBlueprintDefinition())); this.validatorFactory.validator(PlanBlueprintPersist.PlanBlueprintPersistValidator.class).validateForce(persist); return this.persist(persist, groupId, fields); } else { - PlanBlueprintEntity latestVersionPlanBlueprint = this.queryFactory.query(PlanBlueprintQuery.class) - .disableTracking() - .versionStatuses(PlanBlueprintVersionStatus.Current) - .isActive(IsActive.Active) - .statuses(PlanBlueprintStatus.Finalized) - .groupIds(groupId) - .first(); + PlanBlueprintEntity latestVersionPlanBlueprint = null; + if (groupId != null) { + latestVersionPlanBlueprint = this.queryFactory.query(PlanBlueprintQuery.class) + .disableTracking() + .versionStatuses(PlanBlueprintVersionStatus.Current) + .isActive(IsActive.Active) + .statuses(PlanBlueprintStatus.Finalized) + .groupIds(groupId) + .first(); + } + if (latestVersionPlanBlueprint == null && !this.conventionService.isNullOrEmpty(planBlueprintDefinition.getCode())) { + latestVersionPlanBlueprint = this.queryFactory.query(PlanBlueprintQuery.class) + .disableTracking() + .versionStatuses(PlanBlueprintVersionStatus.Current) + .isActive(IsActive.Active) + .statuses(PlanBlueprintStatus.Finalized) + .codes(planBlueprintDefinition.getCode()) + .first(); + } if (latestVersionPlanBlueprint == null) throw new MyValidationException(this.errors.getPlanIsNotFinalized().getCode(), this.errors.getPlanIsNotFinalized().getMessage()); NewVersionPlanBlueprintPersist persist = new NewVersionPlanBlueprintPersist(); persist.setId(latestVersionPlanBlueprint.getId()); diff --git a/backend/web/src/main/resources/config/errors.yml b/backend/web/src/main/resources/config/errors.yml index 4af35110b..55ef58d63 100644 --- a/backend/web/src/main/resources/config/errors.yml +++ b/backend/web/src/main/resources/config/errors.yml @@ -142,4 +142,10 @@ error-thesaurus: message: Description template code exists descriptionTemplateImportNotFound: code: 151 - message: Description template code exists \ No newline at end of file + message: Description template not found + planBlueprintCodeExists: + code: 152 + message: Plan blueprint code exists + planBlueprintImportNotFound: + code: 153 + message: Plan blueprint code not found \ No newline at end of file diff --git a/frontend/src/app/core/common/enum/respone-error-code.ts b/frontend/src/app/core/common/enum/respone-error-code.ts index 16faa20a3..b395a5c43 100644 --- a/frontend/src/app/core/common/enum/respone-error-code.ts +++ b/frontend/src/app/core/common/enum/respone-error-code.ts @@ -47,6 +47,8 @@ export enum ResponseErrorCode { referenceTypeImportNotFound = 149, descriptionTemplateCodeExists = 150, descriptionTemplateImportNotFound = 151, + planBlueprintCodeExists = 152, + planBlueprintImportNotFound = 153, // Notification & Annotation Errors InvalidApiKey = 200, @@ -175,6 +177,8 @@ export class ResponseErrorCodeHelper { return language.instant("GENERAL.BACKEND-ERRORS.DESCRIPTION-TEMPLATE-CODE-EXISTS"); case ResponseErrorCode.descriptionTemplateImportNotFound: return language.instant("GENERAL.BACKEND-ERRORS.DESCRIPTION-TEMPLATE-IMPORT-NOT-FOUND"); + case ResponseErrorCode.planBlueprintCodeExists: + return language.instant("GENERAL.BACKEND-ERRORS.PLAN-BLUEPRINT-CODE-EXISTS"); default: return language.instant("GENERAL.SNACK-BAR.NOT-FOUND"); } diff --git a/frontend/src/app/core/model/plan-blueprint/plan-blueprint.ts b/frontend/src/app/core/model/plan-blueprint/plan-blueprint.ts index 59b808adc..9e400e20f 100644 --- a/frontend/src/app/core/model/plan-blueprint/plan-blueprint.ts +++ b/frontend/src/app/core/model/plan-blueprint/plan-blueprint.ts @@ -11,6 +11,7 @@ import { PlanBlueprintVersionStatus } from "@app/core/common/enum/plan-blueprint export interface PlanBlueprint extends BaseEntity { label: string; + code: string; definition: PlanBlueprintDefinition; status: PlanBlueprintStatus; version: number; @@ -71,6 +72,7 @@ export interface ReferenceTypeFieldInSection extends FieldInSection { // export interface PlanBlueprintPersist extends BaseEntityPersist { label: string; + code: string; definition: PlanBlueprintDefinitionPersist; status: PlanBlueprintStatus; } diff --git a/frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.component.ts b/frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.component.ts index a7dcb70ef..c649090ca 100644 --- a/frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.component.ts +++ b/frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.component.ts @@ -118,7 +118,7 @@ export class DescriptionTemplateTypeEditorComponent extends BaseEditor{{'GENERAL.VALIDATION.REQUIRED' | translate}} +
+ + {{'PLAN-BLUEPRINT-EDITOR.FIELDS.CODE' | translate}} + + {{formGroup.get('code').getError('backendError').message}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + +

{{'PLAN-BLUEPRINT-EDITOR.FIELDS.SECTIONS' | translate}} {{'PLAN-BLUEPRINT-EDITOR.SYSTEM-FIELDS-REQUIRED' | translate}}

diff --git a/frontend/src/app/ui/admin/plan-blueprint/editor/plan-blueprint-editor.component.ts b/frontend/src/app/ui/admin/plan-blueprint/editor/plan-blueprint-editor.component.ts index 93b0d6071..788ef1038 100644 --- a/frontend/src/app/ui/admin/plan-blueprint/editor/plan-blueprint-editor.component.ts +++ b/frontend/src/app/ui/admin/plan-blueprint/editor/plan-blueprint-editor.component.ts @@ -195,13 +195,14 @@ export class PlanBlueprintEditorComponent extends BaseEditor void): void { if (this.isNewVersion == false) { const formData = this.formService.getValue(this.formGroup.value) as PlanBlueprintPersist; + formData.code = this.formGroup.get('code').getRawValue(); this.planBlueprintService.persist(formData) .pipe(takeUntil(this._destroyed)).subscribe( diff --git a/frontend/src/app/ui/admin/plan-blueprint/editor/plan-blueprint-editor.model.ts b/frontend/src/app/ui/admin/plan-blueprint/editor/plan-blueprint-editor.model.ts index dd4a8f8b6..5774a9c4b 100644 --- a/frontend/src/app/ui/admin/plan-blueprint/editor/plan-blueprint-editor.model.ts +++ b/frontend/src/app/ui/admin/plan-blueprint/editor/plan-blueprint-editor.model.ts @@ -13,6 +13,7 @@ import { Guid } from "@common/types/guid"; export class PlanBlueprintEditorModel extends BaseEditorModel implements PlanBlueprintPersist { label: string; + code: string; definition: PlanBlueprintDefinitionEditorModel = new PlanBlueprintDefinitionEditorModel(); status: PlanBlueprintStatus = PlanBlueprintStatus.Draft; versionStatus: PlanBlueprintVersionStatus = PlanBlueprintVersionStatus.Current; @@ -28,6 +29,7 @@ export class PlanBlueprintEditorModel extends BaseEditorModel implements PlanBlu if (item) { super.fromModel(item); this.label = item.label; + this.code = item.code; this.status = item.status; this.versionStatus = item.versionStatus; this.definition = new PlanBlueprintDefinitionEditorModel(this.validationErrorModel).fromModel(item.definition); @@ -35,12 +37,13 @@ export class PlanBlueprintEditorModel extends BaseEditorModel implements PlanBlu return this; } - buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { + buildForm(context: ValidationContext = null, disabled: boolean = false, isNewOrClone: boolean = false): UntypedFormGroup { if (context == null) { context = this.createValidationContext(); } return this.formBuilder.group({ id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators], label: [{ value: this.label, disabled: disabled }, context.getValidation('label').validators], + code: [{ value: this.code, disabled: !isNewOrClone }, context.getValidation('code').validators], status: [{ value: this.status, disabled: disabled }, context.getValidation('status').validators], definition: this.definition.buildForm({ rootPath: `definition.`, @@ -55,6 +58,7 @@ export class PlanBlueprintEditorModel extends BaseEditorModel implements PlanBlu const baseValidationArray: Validation[] = new Array(); baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(this.validationErrorModel, 'id')] }); baseValidationArray.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] }); + baseValidationArray.push({ key: 'code', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'code')] }); baseValidationArray.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'status')] }); baseValidationArray.push({ key: 'hash', validators: [] }); diff --git a/frontend/src/app/ui/admin/plan-blueprint/editor/plan-blueprint-editor.resolver.ts b/frontend/src/app/ui/admin/plan-blueprint/editor/plan-blueprint-editor.resolver.ts index 299954617..196cd89e2 100644 --- a/frontend/src/app/ui/admin/plan-blueprint/editor/plan-blueprint-editor.resolver.ts +++ b/frontend/src/app/ui/admin/plan-blueprint/editor/plan-blueprint-editor.resolver.ts @@ -22,6 +22,7 @@ export class PlanBlueprintEditorResolver extends BaseEditorResolver { ...BaseEditorResolver.lookupFields(), nameof(x => x.id), nameof(x => x.label), + nameof(x => x.code), nameof(x => x.status), [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.id)].join('.'), [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.label)].join('.'), diff --git a/frontend/src/app/ui/admin/plan-blueprint/listing/plan-blueprint-listing.component.ts b/frontend/src/app/ui/admin/plan-blueprint/listing/plan-blueprint-listing.component.ts index 2c080432c..3c88fc88e 100644 --- a/frontend/src/app/ui/admin/plan-blueprint/listing/plan-blueprint-listing.component.ts +++ b/frontend/src/app/ui/admin/plan-blueprint/listing/plan-blueprint-listing.component.ts @@ -51,6 +51,7 @@ export class PlanBlueprintListingComponent extends BaseListingComponent(x => x.id), nameof(x => x.label), + nameof(x => x.code), nameof(x => x.status), nameof(x => x.version), nameof(x => x.groupId), @@ -118,6 +119,11 @@ export class PlanBlueprintListingComponent extends BaseListingComponent(x => x.code), + sortable: true, + languageName: 'PLAN-BLUEPRINT-LISTING.FIELDS.CODE' + }, { prop: nameof(x => x.status), sortable: true, diff --git a/frontend/src/common/modules/errors/error-handling/http-error-handling.service.ts b/frontend/src/common/modules/errors/error-handling/http-error-handling.service.ts index 7d39e3612..77d84dfb5 100644 --- a/frontend/src/common/modules/errors/error-handling/http-error-handling.service.ts +++ b/frontend/src/common/modules/errors/error-handling/http-error-handling.service.ts @@ -25,6 +25,8 @@ export class HttpErrorHandlingService { this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.BACKEND-ERRORS.REFERENCE-TYPE-IMPORT-NOT-FOUND', { 'referenceTypeCode': errorResponse.error.error }), SnackBarNotificationLevel.Error); } if (errorResponse.error.code === ResponseErrorCode.descriptionTemplateImportNotFound){ this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.BACKEND-ERRORS.DESCRIPTION-TEMPLATE-IMPORT-NOT-FOUND', { 'descriptionTemplateLabel': errorResponse.error.error }), SnackBarNotificationLevel.Error); + } if (errorResponse.error.code === ResponseErrorCode.planBlueprintImportNotFound){ + this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.BACKEND-ERRORS.PLAN-BLUEPRINT-IMPORT-NOT-FOUND', { 'planBlueprintLabel': errorResponse.error.error }), SnackBarNotificationLevel.Error); } else { this.uiNotificationService.snackBarNotification(ResponseErrorCodeHelper.getErrorMessageByBackendStatusCode(errorResponse.error.code, this.language), SnackBarNotificationLevel.Error); }