From 7317a918ba40c72f1291fe165aff1b5cc8754983 Mon Sep 17 00:00:00 2001
From: Fadil Zemmari <fadil.zemmari@xelians.fr>
Date: Fri, 18 Sep 2020 15:06:32 +0200
Subject: [PATCH] [US TRTL-113] Add internal code on customer creation form

---
 .../vitamui/iam/common/dto/CustomerDto.java   |   7 +-
 .../iam/common/utils/CustomerDtoEditor.java   |   2 +-
 .../customer/converter/CustomerConverter.java |   4 +
 .../server/customer/domain/Customer.java      |   7 +-
 .../service/CustomerInternalService.java      |   4 +
 .../owner/converter/OwnerConverter.java       |   6 +
 .../internal/server/owner/domain/Owner.java   |   6 +
 .../owner/service/OwnerInternalService.java   |   9 +
 .../vitamui/commons/api/domain/OwnerDto.java  |   7 +
 .../commons/api/enums/AddressType.java        |  43 ++++
 .../models/customer/address-type.enum.ts      |  40 ++++
 .../models/customer/customer.interface.ts     |   3 +
 .../src/app/modules/models/customer/index.ts  |   1 +
 .../models/customer/owner.interface.ts        |   3 +
 .../src/app/core/api/customer-api.service.ts  |   2 +
 .../customer-create.component.html            | 201 +++++++++++-------
 .../customer-create.component.scss            |  16 ++
 .../customer-create.component.ts              | 114 +++++++---
 .../customer-list/customer-list.service.ts    |   1 +
 .../owner-form/owner-form.component.html      |  13 +-
 .../owner-form/owner-form.component.ts        |  22 +-
 21 files changed, 398 insertions(+), 113 deletions(-)
 create mode 100644 commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/enums/AddressType.java
 create mode 100644 ui/ui-frontend-common/src/app/modules/models/customer/address-type.enum.ts

diff --git a/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/dto/CustomerDto.java b/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/dto/CustomerDto.java
index fc056c80..c6b5040f 100644
--- a/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/dto/CustomerDto.java
+++ b/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/dto/CustomerDto.java
@@ -43,6 +43,7 @@ import java.util.Map;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Size;
 
+import fr.gouv.vitamui.commons.api.enums.AddressType;
 import org.hibernate.validator.constraints.Length;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
@@ -100,9 +101,13 @@ public class CustomerDto extends IdDto {
     @NotNull
     private String defaultEmailDomain;
 
-    @NotNull
     private AddressDto address;
 
+    private String internalCode;
+
+    @NotNull
+    private AddressType addressType;
+
     private boolean subrogeable = false;
 
     private boolean readonly = false;
diff --git a/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/utils/CustomerDtoEditor.java b/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/utils/CustomerDtoEditor.java
index 918359a4..a273b69a 100644
--- a/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/utils/CustomerDtoEditor.java
+++ b/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/utils/CustomerDtoEditor.java
@@ -60,7 +60,7 @@ public class CustomerDtoEditor extends PropertyEditorSupport {
         if (StringUtils.hasText(text)) {
             try {
                 final ObjectMapper mapper = new ObjectMapper();
-                final CustomerDto customerDto = mapper.readValue(text, new TypeReference<CustomerDto>() {
+                final CustomerDto customerDto = mapper.readValue(text, new TypeReference<>() {
                 });
                 setValue(customerDto);
             }
diff --git a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/converter/CustomerConverter.java b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/converter/CustomerConverter.java
index bf01b2a1..b6befc88 100644
--- a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/converter/CustomerConverter.java
+++ b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/converter/CustomerConverter.java
@@ -84,6 +84,8 @@ public class CustomerConverter implements Converter<CustomerDto, Customer> {
 
     public static final String EMAIL_DOMAINS_KEY = "Domaines";
 
+    public static final String INTERNAL_CODE_KEY = "Code interne";
+
     public static final String DEFAULT_EMAIL_DOMAIN_KEY = "Domaine par défaut";
 
     public static final String SUBROGEABLE_KEY = "Subrogeable";
@@ -111,6 +113,7 @@ public class CustomerConverter implements Converter<CustomerDto, Customer> {
         logbookData.put(EMAIL_DOMAINS_KEY, customer.getEmailDomains().toString());
         logbookData.put(DEFAULT_EMAIL_DOMAIN_KEY, LogbookUtils.getValue(customer.getDefaultEmailDomain()));
         logbookData.put(SUBROGEABLE_KEY, LogbookUtils.getValue(customer.isSubrogeable()));
+        logbookData.put(INTERNAL_CODE_KEY, LogbookUtils.getValue(customer.getInternalCode()));
         logbookData.put(CUSTOM_GRAPHIC_IDENTITY_KEY, LogbookUtils.getValue(customer.isHasCustomGraphicIdentity()));
         return ApiUtils.toJson(logbookData);
     }
@@ -153,6 +156,7 @@ public class CustomerConverter implements Converter<CustomerDto, Customer> {
         if (customer.getAddress() != null) {
             dto.setAddress(VitamUIUtils.copyProperties(customer.getAddress(), new AddressDto()));
         }
+
         if (customer.getGraphicIdentity() != null) {
             GraphicIdentity graphicalIdentity = customer.getGraphicIdentity();
             dto.setHasCustomGraphicIdentity(graphicalIdentity.isHasCustomGraphicIdentity());
diff --git a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/domain/Customer.java b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/domain/Customer.java
index 1add4d97..36286385 100644
--- a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/domain/Customer.java
+++ b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/domain/Customer.java
@@ -41,6 +41,7 @@ import java.util.List;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Size;
 
+import fr.gouv.vitamui.commons.api.enums.AddressType;
 import org.hibernate.validator.constraints.Length;
 import org.springframework.data.annotation.TypeAlias;
 import org.springframework.data.mongodb.core.index.Indexed;
@@ -104,9 +105,13 @@ public class Customer extends IdDocument {
     @NotNull
     private String defaultEmailDomain;
 
-    @NotNull
     private Address address;
 
+    private String internalCode;
+
+    @NotNull
+    private AddressType addressType;
+
     private boolean readonly = false;
 
     private boolean subrogeable = false;
diff --git a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/service/CustomerInternalService.java b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/service/CustomerInternalService.java
index 5b08157b..acb7ddea 100644
--- a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/service/CustomerInternalService.java
+++ b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/service/CustomerInternalService.java
@@ -312,6 +312,10 @@ public class CustomerInternalService extends VitamUICrudService<CustomerDto, Cus
                     }
                     addressService.processPatch(customer.getAddress(), CastUtils.toMap(entry.getValue()), logbooks);
                     break;
+                case "internalCode" :
+                    logbooks.add(new EventDiffDto(CustomerConverter.INTERNAL_CODE_KEY, customer.getInternalCode(), entry.getValue()));
+                    customer.setInternalCode(CastUtils.toString(entry.getValue()));
+                    break;
                 case "subrogeable" :
                     logbooks.add(new EventDiffDto(CustomerConverter.SUBROGEABLE_KEY, customer.isSubrogeable(), entry.getValue()));
                     customer.setSubrogeable(CastUtils.toBoolean(entry.getValue()));
diff --git a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/converter/OwnerConverter.java b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/converter/OwnerConverter.java
index f172b68a..0bd0c1a8 100644
--- a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/converter/OwnerConverter.java
+++ b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/converter/OwnerConverter.java
@@ -56,6 +56,10 @@ public class OwnerConverter implements Converter<OwnerDto, Owner> {
 
     public static final String COMPANY_NAME_KEY = "Raison sociale";
 
+    public static final String ADDRESS_TYPE_KEY = "Type d'adresse";
+
+    public static final String INTERNAL_CODE_KEY = "Code interne";
+
     private final AddressConverter addressConverter;
 
     public OwnerConverter(final AddressConverter addressConverter) {
@@ -68,6 +72,8 @@ public class OwnerConverter implements Converter<OwnerDto, Owner> {
         ownerLogbookData.put(CODE_KEY, LogbookUtils.getValue(owner.getCode()));
         ownerLogbookData.put(NAME_KEY, LogbookUtils.getValue(owner.getName()));
         ownerLogbookData.put(COMPANY_NAME_KEY, LogbookUtils.getValue(owner.getCompanyName()));
+        ownerLogbookData.put(ADDRESS_TYPE_KEY, LogbookUtils.getValue(owner.getAddressType()));
+        ownerLogbookData.put(INTERNAL_CODE_KEY, LogbookUtils.getValue(owner.getInternalCode()));
         AddressDto address = owner.getAddress() != null ? owner.getAddress() : new AddressDto();
         addressConverter.addAddress(address, ownerLogbookData);
         return ApiUtils.toJson(ownerLogbookData);
diff --git a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/domain/Owner.java b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/domain/Owner.java
index 04662c10..9c6c00fd 100644
--- a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/domain/Owner.java
+++ b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/domain/Owner.java
@@ -38,6 +38,7 @@ package fr.gouv.vitamui.iam.internal.server.owner.domain;
 
 import javax.validation.constraints.NotNull;
 
+import fr.gouv.vitamui.commons.api.enums.AddressType;
 import org.hibernate.validator.constraints.Length;
 import org.springframework.data.annotation.TypeAlias;
 import org.springframework.data.mongodb.core.index.Indexed;
@@ -83,5 +84,10 @@ public class Owner extends CustomerIdDocument {
 
     private Address address;
 
+    private String internalCode;
+
+    @NotNull
+    private AddressType addressType;
+
     private boolean readonly;
 }
diff --git a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/service/OwnerInternalService.java b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/service/OwnerInternalService.java
index 6b9e5a7b..85f1c1f7 100644
--- a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/service/OwnerInternalService.java
+++ b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/service/OwnerInternalService.java
@@ -44,6 +44,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Optional;
 
+import fr.gouv.vitamui.commons.api.enums.AddressType;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.mongodb.core.query.Criteria;
@@ -214,6 +215,14 @@ public class OwnerInternalService extends VitamUICrudService<OwnerDto, Owner> {
                     logbooks.add(new EventDiffDto(OwnerConverter.COMPANY_NAME_KEY, owner.getCompanyName(), entry.getValue()));
                     owner.setCompanyName(CastUtils.toString(entry.getValue()));
                     break;
+                case "addressType" :
+                    logbooks.add(new EventDiffDto(OwnerConverter.ADDRESS_TYPE_KEY, owner.getAddressType(), entry.getValue()));
+                    owner.setAddressType((AddressType) entry.getValue());
+                    break;
+                case "internalCode" :
+                    logbooks.add(new EventDiffDto(OwnerConverter.INTERNAL_CODE_KEY, owner.getInternalCode(), entry.getValue()));
+                    owner.setInternalCode(CastUtils.toString(entry.getValue()));
+                    break;
                 case "address" :
                     Address address;
                     if (owner.getAddress() == null) {
diff --git a/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/OwnerDto.java b/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/OwnerDto.java
index 02f1c3df..6089a8f9 100644
--- a/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/OwnerDto.java
+++ b/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/OwnerDto.java
@@ -38,6 +38,7 @@ package fr.gouv.vitamui.commons.api.domain;
 
 import javax.validation.constraints.NotNull;
 
+import fr.gouv.vitamui.commons.api.enums.AddressType;
 import org.hibernate.validator.constraints.Length;
 
 import lombok.EqualsAndHashCode;
@@ -70,8 +71,14 @@ public class OwnerDto extends CustomerIdDto {
 
     private AddressDto address;
 
+    private String internalCode;
+
+    @NotNull
+    private AddressType addressType;
+
     private boolean readonly;
 
     // no validations for identifier. Because during the creation step, the identifier is set by the backend.
     private String identifier;
+
 }
diff --git a/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/enums/AddressType.java b/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/enums/AddressType.java
new file mode 100644
index 00000000..0c90007c
--- /dev/null
+++ b/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/enums/AddressType.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2020)
+ * and the signatories of the "VITAM - Accord du Contributeur" agreement.
+ *
+ * contact@programmevitam.fr
+ *
+ * This software is a computer program whose purpose is to implement
+ * implement a digital archiving front-office system for the secure and
+ * efficient high volumetry VITAM solution.
+ *
+ * This software is governed by the CeCILL-C license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-C
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-C license and that you accept its terms.
+ */
+package fr.gouv.vitamui.commons.api.enums;
+
+/** Possible address types of a Customer or an Owner **/
+public enum AddressType {
+    POSTAL,
+    INTERNAL_CODE,
+}
diff --git a/ui/ui-frontend-common/src/app/modules/models/customer/address-type.enum.ts b/ui/ui-frontend-common/src/app/modules/models/customer/address-type.enum.ts
new file mode 100644
index 00000000..3e5d3f99
--- /dev/null
+++ b/ui/ui-frontend-common/src/app/modules/models/customer/address-type.enum.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2020)
+ * and the signatories of the "VITAM - Accord du Contributeur" agreement.
+ *
+ * contact@programmevitam.fr
+ *
+ * This software is a computer program whose purpose is to implement
+ * implement a digital archiving front-office system for the secure and
+ * efficient high volumetry VITAM solution.
+ *
+ * This software is governed by the CeCILL-C license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-C
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-C license and that you accept its terms.
+ */
+export enum AddressType {
+    POSTAL = 'POSTAL',
+    INTERNAL_CODE = 'INTERNAL_CODE'
+}
diff --git a/ui/ui-frontend-common/src/app/modules/models/customer/customer.interface.ts b/ui/ui-frontend-common/src/app/modules/models/customer/customer.interface.ts
index 56e93753..0221cef6 100644
--- a/ui/ui-frontend-common/src/app/modules/models/customer/customer.interface.ts
+++ b/ui/ui-frontend-common/src/app/modules/models/customer/customer.interface.ts
@@ -35,6 +35,7 @@
  * knowledge of the CeCILL-C license and that you accept its terms.
  */
 import { Id } from '../id.interface';
+import { AddressType } from './address-type.enum';
 import { Address } from './address.interface';
 import { OtpState } from './otp-state.enum';
 import { Owner } from './owner.interface';
@@ -49,6 +50,8 @@ export interface Customer extends Id {
   otp: OtpState;
   idp?: boolean;
   address: Address;
+  internalCode?: string;
+  addressType: AddressType;
   language: string;
   emailDomains: string[];
   defaultEmailDomain: string;
diff --git a/ui/ui-frontend-common/src/app/modules/models/customer/index.ts b/ui/ui-frontend-common/src/app/modules/models/customer/index.ts
index 00d32156..4540adc7 100644
--- a/ui/ui-frontend-common/src/app/modules/models/customer/index.ts
+++ b/ui/ui-frontend-common/src/app/modules/models/customer/index.ts
@@ -42,3 +42,4 @@ export * from './identity-provider.interface';
 export * from './tenant.interface';
 export * from './basic-customer.interface';
 export * from './customer.interface';
+export * from './address-type.enum';
diff --git a/ui/ui-frontend-common/src/app/modules/models/customer/owner.interface.ts b/ui/ui-frontend-common/src/app/modules/models/customer/owner.interface.ts
index 1d5a3661..bd0f7f14 100644
--- a/ui/ui-frontend-common/src/app/modules/models/customer/owner.interface.ts
+++ b/ui/ui-frontend-common/src/app/modules/models/customer/owner.interface.ts
@@ -35,6 +35,7 @@
  * knowledge of the CeCILL-C license and that you accept its terms.
  */
 import { Id } from '../id.interface';
+import { AddressType } from './address-type.enum';
 import { Address } from './address.interface';
 
 export interface Owner extends Id {
@@ -43,6 +44,8 @@ export interface Owner extends Id {
   name: string;
   companyName: string;
   address: Address;
+  internalCode?: string;
+  addressType: AddressType;
   customerId: string;
   readonly: boolean;
 }
diff --git a/ui/ui-frontend/projects/identity/src/app/core/api/customer-api.service.ts b/ui/ui-frontend/projects/identity/src/app/core/api/customer-api.service.ts
index f8a533c5..e5dc8bc0 100644
--- a/ui/ui-frontend/projects/identity/src/app/core/api/customer-api.service.ts
+++ b/ui/ui-frontend/projects/identity/src/app/core/api/customer-api.service.ts
@@ -77,6 +77,8 @@ export class CustomerApiService extends BaseHttpClient<Customer> {
       otp: customer.otp,
       idp: customer.idp,
       address: customer.address,
+      addressType: customer.addressType,
+      internalCode: customer.internalCode,
       language: customer.language,
       emailDomains: customer.emailDomains,
       defaultEmailDomain: customer.defaultEmailDomain,
diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.html b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.html
index 85e7cb39..1efe4678 100644
--- a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.html
+++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.html
@@ -9,51 +9,84 @@
       <div class="content">
         <h2 i18n="Create customer title@@customerCreateTitle1">Création d'un client</h2>
         <div>
-          <vitamui-common-input
-            class="field-code"
-            formControlName="code"
-            maxlength="20"
-            required
-            placeholder="Code client" i18n-placeholder="Customer code input placeholder + format@@customerCreateCustomerCodeInputPlaceholder"
-          >
+          <vitamui-common-input class="field-code" formControlName="code" maxlength="20" required
+            placeholder="Code client"
+            i18n-placeholder="Customer code input placeholder + format@@customerCreateCustomerCodeInputPlaceholder">
             <ng-container *ngIf="form.get('code')?.touched">
-              <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
-              <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.pattern" i18n="Wrong format (6 digits minimum) error hint@@formError6DigitsField">Format incorrect (6 chiffres minimum)</vitamui-common-input-error>
-              <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.uniqueCode" i18n="Code exists error hint@@formErrorCodeExists">Code déjà existant</vitamui-common-input-error>
+              <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.required"
+                i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
+              <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.pattern"
+                i18n="Wrong format (6 digits minimum) error hint@@formError6DigitsField">Format incorrect (6 chiffres
+                minimum)</vitamui-common-input-error>
+              <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.uniqueCode"
+                i18n="Code exists error hint@@formErrorCodeExists">Code déjà existant</vitamui-common-input-error>
             </ng-container>
           </vitamui-common-input>
         </div>
 
         <div class="d-flex">
-          <vitamui-common-input class="field-name" formControlName="name" maxlength="100" required placeholder="Client" i18n-placeholder="Customer name input placeholder@@customerCreateNameInputPlaceholder">
-            <vitamui-common-input-error *ngIf="form.get('name')?.touched && !!form.get('name')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
+          <vitamui-common-input class="field-name" formControlName="name" maxlength="100" required placeholder="Client"
+            i18n-placeholder="Customer name input placeholder@@customerCreateNameInputPlaceholder">
+            <vitamui-common-input-error *ngIf="form.get('name')?.touched && !!form.get('name')?.errors?.required"
+              i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
           </vitamui-common-input>
-          <vitamui-common-input class="field-company-name" formControlName="companyName" maxlength="250" required placeholder="Raison sociale" i18n-placeholder="Customer company name input placeholder@@customerCreateCompanyNameInputPlaceholder">
-            <vitamui-common-input-error *ngIf="form.get('companyName')?.touched && !!form.get('companyName')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
+          <vitamui-common-input class="field-company-name" formControlName="companyName" maxlength="250" required
+            placeholder="Raison sociale"
+            i18n-placeholder="Customer company name input placeholder@@customerCreateCompanyNameInputPlaceholder">
+            <vitamui-common-input-error
+              *ngIf="form.get('companyName')?.touched && !!form.get('companyName')?.errors?.required"
+              i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
           </vitamui-common-input>
         </div>
 
-        <ng-container formGroupName="address">
+        <div class="mb-4">
+          <div i18n="Address type@@CustomerAddressType" class="mb-2">Type d'adresse</div>
+          <mat-button-toggle-group #group="matButtonToggleGroup" formControlName="addressType">
+            <mat-button-toggle color="primary" value="POSTAL"
+              [ngClass]="{'selected': form.get('addressType').value === ADDRESS_TYPE.POSTAL}">Postale</mat-button-toggle>
+            <mat-button-toggle color="primary" value="INTERNAL_CODE"
+              [ngClass]="{'selected': form.get('addressType').value === ADDRESS_TYPE.INTERNAL_CODE}">Code interne</mat-button-toggle>
+          </mat-button-toggle-group>
+        </div>
+
+        <div *ngIf="form.get('addressType').value === ADDRESS_TYPE.INTERNAL_CODE">
+          <vitamui-common-input class="field-street" formControlName="internalCode" maxlength="20" required placeholder="Code interne"
+          i18n-placeholder="Internal code@@customerInternalCodePlaceholder">
+            <vitamui-common-input-error
+            *ngIf="form.get('internalCode')?.touched && !!form.get('internalCode')?.errors?.required"
+            i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
+          </vitamui-common-input>
+        </div>
+
+        <ng-container formGroupName="address" *ngIf="form.get('addressType').value === ADDRESS_TYPE.POSTAL">
           <div>
-            <vitamui-common-input class="field-street" formControlName="street" maxlength="250" required placeholder="N° et nom de rue" i18n-placeholder="Customer street input placeholder@@customerCreateStreetInputPlaceholder">
-              <vitamui-common-input-error *ngIf="form.get('address.street')?.touched && !!form.get('address.street')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
+            <vitamui-common-input class="field-street" formControlName="street" maxlength="250" required
+              placeholder="N° et nom de rue"
+              i18n-placeholder="Customer street input placeholder@@customerCreateStreetInputPlaceholder">
+              <vitamui-common-input-error
+                *ngIf="form.get('address.street')?.touched && !!form.get('address.street')?.errors?.required"
+                i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
             </vitamui-common-input>
           </div>
 
           <div class="d-flex">
-            <vitamui-common-input class="field-zip-code" formControlName="zipCode" maxlength="10" required placeholder="Code postal" i18n-placeholder="Customer zip code input placeholder@@customerCreateZipCodeInputPlaceholder">
-              <vitamui-common-input-error *ngIf="form.get('address.zipCode')?.touched && !!form.get('address.zipCode')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
+            <vitamui-common-input class="field-zip-code" formControlName="zipCode" maxlength="10" required
+              placeholder="Code postal"
+              i18n-placeholder="Customer zip code input placeholder@@customerCreateZipCodeInputPlaceholder">
+              <vitamui-common-input-error
+                *ngIf="form.get('address.zipCode')?.touched && !!form.get('address.zipCode')?.errors?.required"
+                i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
             </vitamui-common-input>
-            <vitamui-common-input class="field-city" formControlName="city" maxlength="100" required placeholder="Ville" i18n-placeholder="Customer city input placeholder@@customerCreateCityInputPlaceholder">
-              <vitamui-common-input-error *ngIf="form.get('address.city')?.touched && !!form.get('address.city')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
+            <vitamui-common-input class="field-city" formControlName="city" maxlength="100" required placeholder="Ville"
+              i18n-placeholder="Customer city input placeholder@@customerCreateCityInputPlaceholder">
+              <vitamui-common-input-error
+                *ngIf="form.get('address.city')?.touched && !!form.get('address.city')?.errors?.required"
+                i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
             </vitamui-common-input>
             <mat-form-field class="field-country vitamui-mat-select">
-              <mat-select
-                formControlName="country"
-                required
-                placeholder="Pays" i18n-placeholder="Customer country select placeholder@@customerCreateCountrySelectPlaceholder"
-                panelClass="vitamui-mat-select"
-              >
+              <mat-select formControlName="country" required placeholder="Pays"
+                i18n-placeholder="Customer country select placeholder@@customerCreateCountrySelectPlaceholder"
+                panelClass="vitamui-mat-select">
                 <!-- TODO Fetch those values from a referential -->
                 <mat-option value="GB">Royaume Uni</mat-option>
                 <mat-option value="FR">France</mat-option>
@@ -71,7 +104,8 @@
         </ng-container>
 
         <div class="d-flex">
-          <label for="language" class="inline-label label-language" i18n="Interface language (by default for the user)@@customerCreateLanguageInputLabel">
+          <label for="language" class="inline-label label-language"
+            i18n="Interface language (by default for the user)@@customerCreateLanguageInputLabel">
             Langue de l'interface <span class="required-marker">*</span><br>
             <small>(par défault pour l'utilisateur)</small>
           </label>
@@ -88,8 +122,10 @@
         </div>
 
         <div class="actions">
-          <button type="button" class="btn primary" cdkStepperNext [disabled]="firstStepInvalid()" i18n="Next step button label@@customerCreateNextButton">Suivant</button>
-          <button type="button" class="btn cancel" (click)="onCancel()" i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button>
+          <button type="button" class="btn primary" cdkStepperNext [disabled]="firstStepInvalid()"
+            i18n="Next step button label@@customerCreateNextButton">Suivant</button>
+          <button type="button" class="btn cancel" (click)="onCancel()"
+            i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button>
         </div>
       </div>
     </cdk-step>
@@ -99,19 +135,21 @@
         <h2 i18n="Customer access title@@customerCreateTitle2">Accès client</h2>
 
         <div class="d-flex">
-          <label for="passwordRevocationDelay" class="inline-label label-password-revocation-delay" i18n="Duration until password revocation (since the last change)@@customerCreatePasswordRevocationInputLabel">
+          <label for="passwordRevocationDelay" class="inline-label label-password-revocation-delay"
+            i18n="Duration until password revocation (since the last change)@@customerCreatePasswordRevocationInputLabel">
             Durée de révocation du mot de passe<br>
             <small>(depuis le dernier changement)</small>
           </label>
           <mat-form-field class="field-password-revocation-delay vitamui-mat-select">
-            <mat-select
-              formControlName="passwordRevocationDelay"
-              placeholder="Durée de révocation des mots de passe" i18n-placeholder="Customer password revocation delay select placeholder@@customerCreatePasswordRevocationDelaySelectPlaceholder"
-              panelClass="vitamui-mat-select"
-            >
-              <mat-option [value]="6" i18n="6 months@@customerCreatePasswordRevocationDelayOption6Months">6 mois</mat-option>
-              <mat-option [value]="9" i18n="9 months@@customerCreatePasswordRevocationDelayOption9Months">9 mois</mat-option>
-              <mat-option [value]="12" i18n="12 months@@customerCreatePasswordRevocationDelayOption12Months">12 mois</mat-option>
+            <mat-select formControlName="passwordRevocationDelay" placeholder="Durée de révocation des mots de passe"
+              i18n-placeholder="Customer password revocation delay select placeholder@@customerCreatePasswordRevocationDelaySelectPlaceholder"
+              panelClass="vitamui-mat-select">
+              <mat-option [value]="6" i18n="6 months@@customerCreatePasswordRevocationDelayOption6Months">6 mois
+              </mat-option>
+              <mat-option [value]="9" i18n="9 months@@customerCreatePasswordRevocationDelayOption9Months">9 mois
+              </mat-option>
+              <mat-option [value]="12" i18n="12 months@@customerCreatePasswordRevocationDelayOption12Months">12 mois
+              </mat-option>
             </mat-select>
             <div class="select-arrow">
               <i class="material-icons">keyboard_arrow_up</i>
@@ -124,10 +162,14 @@
           <label for="otp" i18n="OTP label@@customerCreateOTPInputLabel">
             Validation en deux étapes <span class="required-marker">*</span>
           </label>
-          <mat-button-toggle-group formControlName="otp" #group="matButtonToggleGroup" class="vitamui-button-toggle-group">
-            <mat-button-toggle value="DISABLED" i18n="OTP deactivate button@@customerCreateOTPDeactivatedButton">Non</mat-button-toggle>
-            <mat-button-toggle value="OPTIONAL" i18n="OTP optional button@@customerCreateOTPOptionalButton">Optionnelle</mat-button-toggle>
-            <mat-button-toggle value="MANDATORY" i18n="OTP mandatory button@@customerCreateOTPMandatoryButton">Obligatoire</mat-button-toggle>
+          <mat-button-toggle-group formControlName="otp" #group="matButtonToggleGroup"
+            class="vitamui-button-toggle-group">
+            <mat-button-toggle value="DISABLED" i18n="OTP deactivate button@@customerCreateOTPDeactivatedButton">Non
+            </mat-button-toggle>
+            <mat-button-toggle value="OPTIONAL" i18n="OTP optional button@@customerCreateOTPOptionalButton">Optionnelle
+            </mat-button-toggle>
+            <mat-button-toggle value="MANDATORY" i18n="OTP mandatory button@@customerCreateOTPMandatoryButton">
+              Obligatoire</mat-button-toggle>
           </mat-button-toggle-group>
         </div>
 
@@ -136,20 +178,21 @@
             Restriction de domaine e-mail<br>
             <small>(cliquer sur l'étiquette pour définir le domaine par défaut)</small>
           </label>
-          <app-domains-input
-            formControlName="emailDomains"
-            placeholder="domaine.xyz" i18n-placeholder="Email domain input placeholder@@customerCreateEmailDomainInputPlaceholder"
+          <app-domains-input formControlName="emailDomains" placeholder="domaine.xyz"
+            i18n-placeholder="Email domain input placeholder@@customerCreateEmailDomainInputPlaceholder"
             [selected]="form.get('defaultEmailDomain').value"
-            (selectedChange)="form.get('defaultEmailDomain').setValue($event)"
-            ></app-domains-input>
+            (selectedChange)="form.get('defaultEmailDomain').setValue($event)"></app-domains-input>
         </div>
 
         <div class="actions">
-          <button type="button" class="btn primary" cdkStepperNext [disabled]="secondStepInvalid()" i18n="Next step button label@@customerCreateNextButton">Suivant</button>
-          <button type="button" class="btn cancel" (click)="onCancel()" i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button>
+          <button type="button" class="btn primary" cdkStepperNext [disabled]="secondStepInvalid()"
+            i18n="Next step button label@@customerCreateNextButton">Suivant</button>
+          <button type="button" class="btn cancel" (click)="onCancel()"
+            i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button>
         </div>
         <button type="button" class="back" cdkStepperPrevious>
-          <i class="material-icons">arrow_back</i> <ng-container i18n="Previous step button label@@customerCreateBackButton">Retour</ng-container>
+          <i class="material-icons">arrow_back</i>
+          <ng-container i18n="Previous step button label@@customerCreateBackButton">Retour</ng-container>
         </button>
       </div>
     </cdk-step>
@@ -159,21 +202,23 @@
         <h2 i18n="Customer graphical identity title@@customerGraphicalIdentityTitle">Identité graphique du client</h2>
 
         <div class="form-group">
-          <vitamui-common-slide-toggle formControlName="hasCustomGraphicIdentity" i18n="Custom visual identity@@customerCreateVisualIdentityToggleLabel">Afficher l'identité graphique personnalisée</vitamui-common-slide-toggle>
+          <vitamui-common-slide-toggle formControlName="hasCustomGraphicIdentity"
+            i18n="Custom visual identity@@customerCreateVisualIdentityToggleLabel">Afficher l'identité graphique
+            personnalisée</vitamui-common-slide-toggle>
         </div>
 
         <div class="d-flex">
           <div class="upload-text">
-            <div class="upload" i18n="Customer graphical identity upload label@@customerGraphicalIdentityUploadLabel"><span class="underline" (click)="addLogo()">Sélectionner</span> le logo du client</div>
-            <div i18n="Customer graphical identity max size label@@customerGraphicalIdentityMaxSizeLabel">(taille max 280px * 100px)</div>
+            <div class="upload" i18n="Customer graphical identity upload label@@customerGraphicalIdentityUploadLabel">
+              <span class="underline" (click)="addLogo()">Sélectionner</span> le logo du client</div>
+            <div i18n="Customer graphical identity max size label@@customerGraphicalIdentityMaxSizeLabel">(taille max
+              280px * 100px)</div>
           </div>
-          <div class="drag-and-drop-area" [ngClass]="{'on-over': hasDropZoneOver}"
-            vitamuiCommonDragAndDrop
-            (fileToUploadEmitter)="onImageDropped($event)"
-            (fileDragOverEmitter)="onImageDragOver($event)"
+          <div class="drag-and-drop-area" [ngClass]="{'on-over': hasDropZoneOver}" vitamuiCommonDragAndDrop
+            (fileToUploadEmitter)="onImageDropped($event)" (fileDragOverEmitter)="onImageDragOver($event)"
             (fileDragLeaveEmitter)="onImageDragLeave($event)">
             <div *ngIf="imageUrl" class="image-container">
-              <img class="logo-image" [src]="imageUrl"/>
+              <img class="logo-image" [src]="imageUrl" />
             </div>
             <input type="file" #fileSearch class="input-file" (change)="handleFileInput($event.target.files)">
             <div class="drop-area">
@@ -185,40 +230,48 @@
         </div>
 
         <div class="customer-colors-input">
-          <app-customer-colors-input formControlName="themeColors" [disabled]="!hasCustomGraphicIdentity" themeOverloadSelector="form#formCreateCustomer"></app-customer-colors-input>
+          <app-customer-colors-input formControlName="themeColors" [disabled]="!hasCustomGraphicIdentity"
+            themeOverloadSelector="form#formCreateCustomer"></app-customer-colors-input>
         </div>
         <div class="error-message" *ngIf="hasError">
           {{ message }}
         </div>
 
         <div class="actions">
-          <button type="button" class="btn primary" cdkStepperNext [disabled]="!thirdStepValid()" i18n="Create owner button@@customerCreateCreateOwnerButton">
-              Créer le propriétaire
-              <small> des éléments de preuves</small>
-            </button>
-          <button type="button" class="btn cancel" (click)="onCancel()" i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button>
+          <button type="button" class="btn primary" cdkStepperNext [disabled]="!thirdStepValid()"
+            i18n="Create owner button@@customerCreateCreateOwnerButton">
+            Créer le propriétaire
+            <small> des éléments de preuves</small>
+          </button>
+          <button type="button" class="btn cancel" (click)="onCancel()"
+            i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button>
         </div>
         <button type="button" class="back" cdkStepperPrevious>
-          <i class="material-icons">arrow_back</i> <ng-container i18n="Previous step button label@@customerCreateBackButton">Retour</ng-container>
+          <i class="material-icons">arrow_back</i>
+          <ng-container i18n="Previous step button label@@customerCreateBackButton">Retour</ng-container>
         </button>
       </div>
-
     </cdk-step>
 
     <cdk-step>
       <div class="content">
-        <h2 i18n="Create evidence owner title@@customerCreateTitle3">Création du propriétaire des éléments de preuve</h2>
+        <h2 i18n="Create evidence owner title@@customerCreateTitle3">Création du propriétaire des éléments de preuve
+        </h2>
         <div class="form-group">
           <app-owner-form [formControl]="form.get(['owners', 0])" [customerInfo]="customerInfo"></app-owner-form>
-          <p class="hint" i18n="the evidence tenant is automatically created with the owner@@customerCreateHint">Le coffre des éléments de preuve est créé automatiquement avec son propriétaire</p>
+          <p class="hint" i18n="the evidence tenant is automatically created with the owner@@customerCreateHint">Le
+            coffre des éléments de preuve est créé automatiquement avec son propriétaire</p>
         </div>
-
-        <button type="submit" class="btn primary" [disabled]="form.pending || form.invalid || creating" i18n="Finish customer creation button@@customerCreateFinishButton">Terminer</button>
-        <button type="button" class="btn cancel" (click)="onCancel()" i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button>
+        
+        <button type="submit" class="btn primary" 
+          i18n="Finish customer creation button@@customerCreateFinishButton" [disabled]="lastStepIsInvalid()">Terminer</button>
+        <button type="button" class="btn cancel" (click)="onCancel()"
+          i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button>
         <button type="button" class="back" cdkStepperPrevious>
-          <i class="material-icons">arrow_back</i> <ng-container i18n="Previous step button label@@customerCreateBackButton">Retour</ng-container>
+          <i class="material-icons">arrow_back</i>
+          <ng-container i18n="Previous step button label@@customerCreateBackButton">Retour</ng-container>
         </button>
       </div>
     </cdk-step>
   </vitamui-common-stepper>
-</form>
+</form>
\ No newline at end of file
diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.scss b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.scss
index b93541ff..50e5ee46 100644
--- a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.scss
+++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.scss
@@ -217,3 +217,19 @@ button > small {
     font-size: 14px;
     margin-bottom: 30px;
 }
+
+.selected {
+    background-color: var(--vitamui-secondary);
+    color: $white;
+}
+
+:host::ng-deep {
+    .mat-button-toggle-button {
+        min-width: 100px;
+    }
+
+    .mat-button-toggle-label-content {
+        max-height: 40px!important;
+        line-height: 2!important;
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.ts b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.ts
index f349a3e8..3b5dcfe8 100644
--- a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.ts
+++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.ts
@@ -35,7 +35,7 @@
  * knowledge of the CeCILL-C license and that you accept its terms.
  */
 import { merge, Subscription } from 'rxjs';
-import {ConfirmDialogService, Customer, OtpState, ThemeService} from 'ui-frontend-common';
+import { AddressType, ConfirmDialogService, Customer, OtpState, ThemeService } from 'ui-frontend-common';
 
 import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core';
 import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@@ -45,8 +45,16 @@ import { CustomerService } from '../../core/customer.service';
 import { CustomerCreateValidators } from './customer-create.validators';
 
 const PROGRESS_BAR_MULTIPLICATOR = 100;
+
 const IMAGE_TYPE_PREFIX = 'image';
 
+interface CustomerInfo {
+   code: string;
+   name: string;
+   companyName: string;
+   addressType: AddressType;
+}
+
 @Component({
   selector: 'app-customer-create',
   templateUrl: './customer-create.component.html',
@@ -54,30 +62,53 @@ const IMAGE_TYPE_PREFIX = 'image';
 })
 export class CustomerCreateComponent implements OnInit, OnDestroy {
 
-  form: FormGroup;
-  stepIndex = 0;
-  customerInfo: { code: string, name: string, companyName: string } = { code: '', name: '', companyName: '' };
-  hasCustomGraphicIdentity = false;
-  hasDropZoneOver = false;
-  imageToUpload: File = null;
-  lastImageUploaded: File = null;
-  imageUrl: any;
-  lastUploadedImageUrl: any;
-  lastColors: {[key: string]: string};
-  hasError = true;
-  message: string;
-  creating = false;
-
-  hexPattern = /#([0-9A-Fa-f]{6})/;
+  public form: FormGroup;
+
+  public stepIndex = 0;
+
+  public hasCustomGraphicIdentity = false;
+
+  public hasDropZoneOver = false;
+
+  public imageToUpload: File = null;
+
+  public lastImageUploaded: File = null;
+
+  public imageUrl: any;
+
+  public lastUploadedImageUrl: any;
+
+  public lastColors: {[key: string]: string};
+
+  public hasError = true;
+
+
+  public message: string;
+
+  public creating = false;
+
+  public JSON = JSON;
+
+  public hexPattern = /#([0-9A-Fa-f]{6})/;
+
+  public customerInfo: CustomerInfo = {
+    code: '',
+    name: '',
+    companyName: '',
+    addressType: AddressType.POSTAL
+  };
+
+  public ADDRESS_TYPE = AddressType;
+
+  @ViewChild('fileSearch', { static: false }) public fileSearch: any;
 
   // stepCount is the total number of steps and is used to calculate the advancement of the progress bar.
   // We could get the number of steps using ViewChildren(StepComponent) but this triggers a
   // "Expression has changed after it was checked" error so we instead manually define the value.
   // Make sure to update this value whenever you add or remove a step from the  template.
   private stepCount = 4;
-  private keyPressSubscription: Subscription;
 
-  @ViewChild('fileSearch', { static: false }) fileSearch: any;
+  private keyPressSubscription: Subscription;
 
   constructor(
     public dialogRef: MatDialogRef<CustomerCreateComponent>,
@@ -103,16 +134,18 @@ export class CustomerCreateComponent implements OnInit, OnDestroy {
       passwordRevocationDelay: 6,
       otp: OtpState.OPTIONAL,
       address: this.formBuilder.group({
-        street: [null, Validators.required],
-        zipCode: [null, Validators.required],
-        city: [null, Validators.required],
-        country: ['FR', Validators.required],
+        street: [''],
+        zipCode: [''],
+        city: [''],
+        country: ['FR']
       }),
+      internalCode: [null],
+      addressType: [AddressType.POSTAL, Validators.required],
       language: ['FRENCH', Validators.required],
       emailDomains: [null, Validators.required],
       defaultEmailDomain: [null, Validators.required],
       hasCustomGraphicIdentity: false,
-      themeColors: null,
+      themeColors: [null],
       owners: this.formBuilder.array([
         this.formBuilder.control(null, Validators.required),
       ])
@@ -155,14 +188,16 @@ export class CustomerCreateComponent implements OnInit, OnDestroy {
     merge(
       this.form.get('code').valueChanges,
       this.form.get('name').valueChanges,
-      this.form.get('companyName').valueChanges
+      this.form.get('companyName').valueChanges,
+      this.form.get('addressType').valueChanges
     )
     .subscribe(() => {
       // reset object to trigger customerInfo input update in child component
       this.customerInfo = {
         code: this.form.get('code').value,
         name: this.form.get('name').value,
-        companyName: this.form.get('companyName').value
+        companyName: this.form.get('companyName').value,
+        addressType: this.form.get('addressType').value
       };
     });
   }
@@ -176,9 +211,8 @@ export class CustomerCreateComponent implements OnInit, OnDestroy {
   }
 
   onSubmit() {
-    if (this.form.invalid) { return; }
+    if (this.lastStepIsInvalid()) { return; }
     this.creating = true;
-
     const customer: Customer = this.updateForCustomerModel(this.form.value);
 
     this.customerService.create(customer, this.imageToUpload).subscribe(
@@ -191,6 +225,14 @@ export class CustomerCreateComponent implements OnInit, OnDestroy {
       });
   }
 
+  isFormValid(form: FormGroup): boolean {
+    if (this.form.get('addressType').value === AddressType.INTERNAL_CODE) {
+      return form.get('internalCode').valid;
+    } else {
+      return form.valid;
+    }
+  }
+
   updateForCustomerModel(formValue: any): Customer {
     const { themeColors, ...customer } = formValue;
     const customerTheme =  {
@@ -254,13 +296,18 @@ export class CustomerCreateComponent implements OnInit, OnDestroy {
   }
 
   firstStepInvalid(): boolean {
-    return this.form.get('code').invalid || this.form.get('code').pending ||
-      this.form.get('name').invalid || this.form.get('name').pending ||
-      this.form.get('companyName').invalid || this.form.get('companyName').pending ||
-      this.form.get('address.street').invalid || this.form.get('address.street').pending ||
+    const response = this.form.get('code').invalid || this.form.get('code').pending ||
+    this.form.get('name').invalid || this.form.get('name').pending ||
+    this.form.get('companyName').invalid || this.form.get('companyName').pending;
+
+    if (this.form.get('addressType').value === AddressType.POSTAL) {
+      return response || this.form.get('address.street').invalid || this.form.get('address.street').pending ||
       this.form.get('address.zipCode').invalid || this.form.get('address.zipCode').pending ||
       this.form.get('address.city').invalid || this.form.get('address.city').pending ||
       this.form.get('address.country').invalid || this.form.get('address.country').pending;
+    } else if (this.form.get('addressType').value === AddressType.INTERNAL_CODE) {
+      return response || this.form.get('internalCode').invalid || this.form.get('internalCode').pending;
+    }
   }
 
   secondStepInvalid(): boolean {
@@ -277,6 +324,11 @@ export class CustomerCreateComponent implements OnInit, OnDestroy {
         );
   }
 
+  lastStepIsInvalid(): boolean {
+      const invalid = this.firstStepInvalid() || this.secondStepInvalid() || !this.thirdStepValid();
+      return this.form.pending || invalid || this.creating;
+  }
+
   private isThemeColorsFormValid(): boolean {
     const value = this.form.get('themeColors').value;
     for (const key of Object.keys(value)) {
diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-list/customer-list.service.ts b/ui/ui-frontend/projects/identity/src/app/customer/customer-list/customer-list.service.ts
index 11c75ac6..6f66b08f 100644
--- a/ui/ui-frontend/projects/identity/src/app/customer/customer-list/customer-list.service.ts
+++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-list/customer-list.service.ts
@@ -94,6 +94,7 @@ export class CustomerListService extends SearchService<Customer> {
       passwordRevocationDelay: customer.passwordRevocationDelay,
       otp: customer.otp,
       address: customer.address,
+      addressType: customer.addressType,
       language: customer.language,
       emailDomains: customer.emailDomains,
       defaultEmailDomain: customer.defaultEmailDomain,
diff --git a/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.html b/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.html
index 7ae17390..62756a5f 100644
--- a/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.html
+++ b/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.html
@@ -1,4 +1,6 @@
 <ng-container [formGroup]="form">
+
+
   <vitamui-common-input class="field-code" formControlName="code" maxlength="20" required placeholder="Code propriétaire" i18n-placeholder="Owner code input placeholder@@ownerFormCodeInputPlaceholder">
     <ng-container *ngIf="form.get('code')?.touched">
       <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
@@ -14,7 +16,13 @@
       <vitamui-common-input-error *ngIf="form.get('companyName')?.touched && !!form.get('companyName')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error>
     </vitamui-common-input>
   </div>
-  <ng-container formGroupName="address">
+
+  <div *ngIf="form.get('addressType').value === ADDRESS_TYPE.INTERNAL_CODE">
+    <vitamui-common-input class="field-street" formControlName="internalCode" maxlength="20" placeholder="Code interne"
+    i18n-placeholder="Internal code@@OwnerInternalCodePlaceholder"></vitamui-common-input>
+  </div>
+
+  <ng-container formGroupName="address" *ngIf="form.get('addressType').value === ADDRESS_TYPE.POSTAL">
     <div>
       <vitamui-common-input class="field-street" formControlName="street" maxlength="250" placeholder="N° et nom de la rue" i18n-placeholder="Owner street input placeholder@@ownerFormStreetInputPlaceholder"></vitamui-common-input>
     </div>
@@ -24,8 +32,7 @@
       <mat-select
         formControlName="country"
         placeholder="Pays" i18n-placeholder="Owner country select placeholder@@ownerFormCountrySelectPlaceholder"
-        panelClass="vitamui-mat-select"
-      >
+        panelClass="vitamui-mat-select">
         <!-- TODO Fetch those values from a referential -->
         <mat-option value="GB">Royaume Uni</mat-option>
         <mat-option value="FR">France</mat-option>
diff --git a/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.ts b/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.ts
index 9e6c72f9..2c5185a9 100644
--- a/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.ts
+++ b/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.ts
@@ -39,6 +39,7 @@ import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
 import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
 import { merge } from 'rxjs';
 import { distinctUntilChanged, map } from 'rxjs/operators';
+import { AddressType, Customer } from 'ui-frontend-common';
 
 import { Owner } from 'ui-frontend-common';
 import { OwnerFormValidators } from './owner-form.validators';
@@ -61,30 +62,42 @@ export class OwnerFormComponent implements ControlValueAccessor, OnDestroy, OnIn
 
   private sub: any;
 
+  public ADDRESS_TYPE = AddressType;
+
   @Input()
   set customerId(customerId: string) {
     this._customerId = customerId;
     if (!this.form) { return; }
     this.form.get('customerId').setValue(customerId);
   }
+
   get customerId() { return this._customerId; }
+
   // tslint:disable-next-line:variable-name
   private _customerId: string;
 
   @Input()
-  set customerInfo(customerInfo: any) {
+  set customerInfo(customerInfo: Customer) {
     this._customerInfo = customerInfo;
     if (customerInfo && this.form) {
-      this.form.patchValue({ code: customerInfo.code, name: customerInfo.name, companyName: customerInfo.companyName });
+      this.form.patchValue({
+          code: customerInfo.code,
+          name: customerInfo.name,
+          companyName: customerInfo.companyName,
+          addressType: customerInfo.addressType
+        });
     }
   }
+
   get customerInfo() { return this._customerInfo; }
+
   // tslint:disable-next-line:variable-name
   private _customerInfo: any;
 
   constructor(private formBuilder: FormBuilder, private ownerFormValidators: OwnerFormValidators) {}
 
   onChange = (_: any) => {};
+
   onTouched = () => {};
 
   ngOnInit() {
@@ -99,6 +112,8 @@ export class OwnerFormComponent implements ControlValueAccessor, OnDestroy, OnIn
       ],
       name: [null, Validators.required],
       companyName: [null, Validators.required],
+      internalCode: [null],
+      addressType: [this.customerInfo.addressType],
       address: this.formBuilder.group({
         street: null,
         zipCode: null,
@@ -107,6 +122,7 @@ export class OwnerFormComponent implements ControlValueAccessor, OnDestroy, OnIn
       }),
       readonly: false
     });
+
     this.subscribeToValueChanges();
   }
 
@@ -124,6 +140,8 @@ export class OwnerFormComponent implements ControlValueAccessor, OnDestroy, OnIn
       code: null,
       name: null,
       companyName: null,
+      internalCode: null,
+      addressType: this.customerInfo.addressType,
       address: {
         street: null,
         zipCode: null,
-- 
GitLab