From 2e1ad77946a6cdbbc10535dab7e8660aba82cef1 Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Tue, 19 May 2026 20:34:20 +0330 Subject: [PATCH] feat: implement fiscal ID validation; replace fiscal code validator and update related components --- src/app/core/services/form-errors.service.ts | 6 ++++ .../core/validators/fiscal-code.validator.ts | 13 -------- .../core/validators/fiscal-id.validator.ts | 30 +++++++++++++++++++ src/app/core/validators/index.ts | 2 +- src/app/core/validators/password.validator.ts | 19 +++++++----- .../consumer/constants/menuItems.const.ts | 12 ++++---- .../components/form.component.html | 2 +- .../partner/constants/menuItems.const.ts | 6 ++-- .../businessActivities/form.component.html | 3 +- .../businessActivities/form.component.ts | 5 ++++ .../models/businessActivities_io.d.ts | 1 + .../payloads/gold/form.component.html | 2 +- .../payloads/gold/form.component.ts | 20 ++++++------- .../payment/form-dialog.component.html | 18 +++++++---- .../superAdmin/layouts/layout.component.ts | 1 + .../businessActivities/form.component.html | 2 +- .../partners/views/single.component.html | 4 +-- .../sku/components/select.component.html | 2 +- .../components/fields/fiscal_id.component.ts | 5 ++-- .../invoice_number_sequence.component.ts | 1 + .../fields/partner_token.component.ts | 7 +---- .../components/fields/terminal.component.ts | 2 +- .../components/input/input.component.ts | 3 ++ .../sale-invoice-single-view.component.html | 2 +- .../passwordInput/password-input.component.ts | 3 +- src/app/shared/constants/fields/index.ts | 13 ++------ 26 files changed, 108 insertions(+), 76 deletions(-) delete mode 100644 src/app/core/validators/fiscal-code.validator.ts create mode 100644 src/app/core/validators/fiscal-id.validator.ts diff --git a/src/app/core/services/form-errors.service.ts b/src/app/core/services/form-errors.service.ts index 4c1444d..a2f7997 100644 --- a/src/app/core/services/form-errors.service.ts +++ b/src/app/core/services/form-errors.service.ts @@ -68,6 +68,11 @@ export class FormErrorsService { const info = errors['invalidUsername']; out.push({ key: 'invalidUsername', message: info.message ?? `${label} معتبر نیست.` }); } + + if (errors['invalidFiscalId']) { + const info = errors['invalidFiscalId']; + out.push({ key: 'invalidFiscalId', message: info.message ?? `${label} معتبر نیست.` }); + } // fallback: include any other error keys Object.keys(errors).forEach((k) => { if ( @@ -80,6 +85,7 @@ export class FormErrorsService { 'max', 'email', 'pattern', + 'invalidFiscalId', ].indexOf(k) === -1 ) { try { diff --git a/src/app/core/validators/fiscal-code.validator.ts b/src/app/core/validators/fiscal-code.validator.ts deleted file mode 100644 index 5c45867..0000000 --- a/src/app/core/validators/fiscal-code.validator.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ValidatorFn } from '@angular/forms'; - -export function fiscalCodeValidator(): ValidatorFn { - return (control) => { - if (control.value === null || control.value === undefined || control.value === '') { - return null; - } - return null; - return control.value.length === 11 && /^[0-9]{11}$/.test(control.value) - ? null - : { fiscalCode: 'معتبر نیست' }; - }; -} diff --git a/src/app/core/validators/fiscal-id.validator.ts b/src/app/core/validators/fiscal-id.validator.ts new file mode 100644 index 0000000..48286d7 --- /dev/null +++ b/src/app/core/validators/fiscal-id.validator.ts @@ -0,0 +1,30 @@ +import { ValidatorFn } from '@angular/forms'; + +export function fiscalIdValidator(): ValidatorFn { + return (control) => { + if (control.value === null || control.value === undefined || control.value === '') { + return null; + } + + if (control.value.length < 6) { + return { + minlength: { + requiredLength: 6, + actualLength: control.value.length, + }, + }; + } + + const pattern = /^[a-zA-Z0-9]*$/; + + if (!pattern.test(control.value)) { + return { + invalidFiscalId: { + value: control.value, + message: 'شناسه مالی فقط می‌تواند شامل حروف انگلیسی و اعداد باشد', + }, + }; + } + return null; + }; +} diff --git a/src/app/core/validators/index.ts b/src/app/core/validators/index.ts index a484f07..a0cb048 100644 --- a/src/app/core/validators/index.ts +++ b/src/app/core/validators/index.ts @@ -1,4 +1,4 @@ -export * from './fiscal-code.validator'; +export * from './fiscal-id.validator'; export * from './greater.validator'; export * from './iban.validator'; export * from './mobile.validator'; diff --git a/src/app/core/validators/password.validator.ts b/src/app/core/validators/password.validator.ts index ed520a4..a852857 100644 --- a/src/app/core/validators/password.validator.ts +++ b/src/app/core/validators/password.validator.ts @@ -1,16 +1,21 @@ import { ValidatorFn } from '@angular/forms'; -// Password must be minimum 8 characters, include at least one uppercase, -// one lowercase, one number and one special character -// export const PASSWORD_PATTERN = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,}$/; -export const PASSWORD_PATTERN = /^[0-9]{6,}$/; +// const PASSWORD_PATTERN = /^[a-zA-Z0-9_-]*$/; -// Validator factory named `password` as requested. Returns `null` for empty -// values so `Validators.required` can be used alongside it when needed. export function password(): ValidatorFn { return (control) => { const value = control?.value; if (value === null || value === undefined || String(value).length === 0) return null; - return PASSWORD_PATTERN.test(String(value)) ? null : { password: 'معتبر نیست' }; + + if (value.length < 6) { + return { + minlength: { + requiredLength: 6, + actualLength: value.length, + }, + }; + } + return null; + // return PASSWORD_PATTERN.test(String(value)) ? null : { password: 'معتبر نیست' }; }; } diff --git a/src/app/domains/consumer/constants/menuItems.const.ts b/src/app/domains/consumer/constants/menuItems.const.ts index f822ed6..a179cde 100644 --- a/src/app/domains/consumer/constants/menuItems.const.ts +++ b/src/app/domains/consumer/constants/menuItems.const.ts @@ -9,28 +9,28 @@ export const CONSUMER_MENU_ITEMS = [ }, { label: 'فعالیت اقتصادی', - icon: 'pi pi-fw pi-home', + icon: 'pi pi-fw pi-shop', routerLink: ['/consumer/business_activities'], }, { - label: 'پایانه‌های فروش', - icon: 'pi pi-fw pi-home', + label: 'پایانه‌‌ی فروش', + icon: 'pi pi-fw pi-tablet', routerLink: ['/consumer/poses'], }, { label: 'فاکتورها', - icon: 'pi pi-fw pi-home', + icon: 'pi pi-fw pi-receipt', routerLink: ['/consumer/sale_invoices'], }, { label: 'مشتری‌ها', - icon: 'pi pi-fw pi-home', + icon: 'pi pi-fw pi-users', routerLink: ['/consumer/customers'], }, { label: 'حساب‌های کاربری', - icon: 'pi pi-fw pi-home', + icon: 'pi pi-fw pi-user', routerLink: ['/consumer/accounts'], }, ], diff --git a/src/app/domains/consumer/modules/businessActivities/components/form.component.html b/src/app/domains/consumer/modules/businessActivities/components/form.component.html index 5bc388e..73dc803 100644 --- a/src/app/domains/consumer/modules/businessActivities/components/form.component.html +++ b/src/app/domains/consumer/modules/businessActivities/components/form.component.html @@ -9,7 +9,7 @@
- + diff --git a/src/app/domains/partner/constants/menuItems.const.ts b/src/app/domains/partner/constants/menuItems.const.ts index 31e4570..828dc5c 100644 --- a/src/app/domains/partner/constants/menuItems.const.ts +++ b/src/app/domains/partner/constants/menuItems.const.ts @@ -9,17 +9,17 @@ export const PARTNER_MENU_ITEMS = [ }, { label: 'حساب‌های کاربری', - icon: 'pi pi-fw pi-home', + icon: 'pi pi-fw pi-user', routerLink: ['/partner/accounts'], }, { label: 'مشتری‌ها', - icon: 'pi pi-fw pi-home', + icon: 'pi pi-fw pi-users', routerLink: ['/partner/consumers'], }, { label: 'لایسنس‌ها', - icon: 'pi pi-fw pi-home', + icon: 'pi pi-fw pi-key', routerLink: ['/partner/licenses'], }, ], diff --git a/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.html b/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.html index 6d156cb..0b2094a 100644 --- a/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.html +++ b/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.html @@ -1,7 +1,8 @@ - + + diff --git a/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.ts b/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.ts index 03b6dba..f857eba 100644 --- a/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.ts +++ b/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.ts @@ -7,6 +7,7 @@ import { NameComponent, PartnerTokenComponent, } from '@/shared/components'; +import { InvoiceNumberSequenceComponent } from '@/shared/components/fields/invoice_number_sequence.component'; import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component'; import { fieldControl } from '@/shared/constants/fields'; import { Component, inject, Input } from '@angular/core'; @@ -28,6 +29,7 @@ import { PartnerConsumerBusinessActivitiesService } from '../../services/busines LicenseStartsAtComponent, FormFooterActionsComponent, Divider, + InvoiceNumberSequenceComponent, ], }) export class ConsumerBusinessActivitiesFormComponent extends AbstractForm< @@ -44,6 +46,9 @@ export class ConsumerBusinessActivitiesFormComponent extends AbstractForm< name: fieldControl.name(this.initialValues?.name || ''), economic_code: fieldControl.economic_code(this.initialValues?.economic_code || ''), fiscal_id: fieldControl.fiscal_id(this.initialValues?.fiscal_id || ''), + invoice_number_sequence: fieldControl.invoice_number_sequence( + parseInt(this.initialValues?.invoice_number_sequence || '1'), + ), partner_token: fieldControl.partner_token(this.initialValues?.partner_token || ''), guild_id: fieldControl.guild_id(this.initialValues?.guild?.id || ''), license_starts_at: [''], diff --git a/src/app/domains/partner/modules/consumers/models/businessActivities_io.d.ts b/src/app/domains/partner/modules/consumers/models/businessActivities_io.d.ts index 2c10ffa..1b12c08 100644 --- a/src/app/domains/partner/modules/consumers/models/businessActivities_io.d.ts +++ b/src/app/domains/partner/modules/consumers/models/businessActivities_io.d.ts @@ -7,6 +7,7 @@ export interface IBusinessActivityRawResponse { fiscal_id: string; partner_token: string; guild: ISummary; + invoice_number_sequence: string; created_at: string; license_info: LicenseInfo; } diff --git a/src/app/domains/pos/modules/landing/components/payloads/gold/form.component.html b/src/app/domains/pos/modules/landing/components/payloads/gold/form.component.html index 9338a7c..8d2deff 100644 --- a/src/app/domains/pos/modules/landing/components/payloads/gold/form.component.html +++ b/src/app/domains/pos/modules/landing/components/payloads/gold/form.component.html @@ -1,6 +1,6 @@
- + diff --git a/src/app/domains/pos/modules/landing/components/payloads/gold/form.component.ts b/src/app/domains/pos/modules/landing/components/payloads/gold/form.component.ts index 9dd884c..d1062cf 100644 --- a/src/app/domains/pos/modules/landing/components/payloads/gold/form.component.ts +++ b/src/app/domains/pos/modules/landing/components/payloads/gold/form.component.ts @@ -31,16 +31,16 @@ export class PosGoldPayloadFormComponent extends AbstractForm< IPosOrderItem, IPosOrderItem > { - // override defaultValues: Partial> = { - // unit_price: 200_000_000, - // quantity: 2, - // payload: { - // // commission: 10_000, - // // wages: 10_000, - // // profit: 10_000, - // karat: 'KARAT_18' as TGoldKarat, - // } as any, - // }; + override defaultValues: Partial> = { + // unit_price: 200_000_000, + // quantity: 2, + payload: { + // commission: 10_000, + // wages: 10_000, + // profit: 10_000, + karat: 'KARAT_18' as TGoldKarat, + } as any, + }; @Input({ required: true }) vatPercentage!: number; diff --git a/src/app/domains/pos/modules/landing/components/payment/form-dialog.component.html b/src/app/domains/pos/modules/landing/components/payment/form-dialog.component.html index 9aad222..0936793 100644 --- a/src/app/domains/pos/modules/landing/components/payment/form-dialog.component.html +++ b/src/app/domains/pos/modules/landing/components/payment/form-dialog.component.html @@ -14,7 +14,7 @@
- + - تمامی بدهی باقی‌مانده + باقی‌مانده مبلغ }
- + diff --git a/src/app/domains/superAdmin/layouts/layout.component.ts b/src/app/domains/superAdmin/layouts/layout.component.ts index 1939a80..a869cc6 100644 --- a/src/app/domains/superAdmin/layouts/layout.component.ts +++ b/src/app/domains/superAdmin/layouts/layout.component.ts @@ -13,5 +13,6 @@ export class LayoutComponent { ngOnInit() { this.layoutService.setMenuItems(SUPER_ADMIN_MENU_ITEMS); + this.layoutService.setPanelInfo({ title: 'پنل مدیریتی ' }); } } diff --git a/src/app/domains/superAdmin/modules/consumers/components/businessActivities/form.component.html b/src/app/domains/superAdmin/modules/consumers/components/businessActivities/form.component.html index f7db1ac..e3c7002 100644 --- a/src/app/domains/superAdmin/modules/consumers/components/businessActivities/form.component.html +++ b/src/app/domains/superAdmin/modules/consumers/components/businessActivities/form.component.html @@ -9,7 +9,7 @@ - + diff --git a/src/app/domains/superAdmin/modules/partners/views/single.component.html b/src/app/domains/superAdmin/modules/partners/views/single.component.html index 73462ac..389b1cc 100644 --- a/src/app/domains/superAdmin/modules/partners/views/single.component.html +++ b/src/app/domains/superAdmin/modules/partners/views/single.component.html @@ -6,8 +6,8 @@
- - + +
`, imports: [ReactiveFormsModule, InputComponent], diff --git a/src/app/shared/components/fields/invoice_number_sequence.component.ts b/src/app/shared/components/fields/invoice_number_sequence.component.ts index 2c4b958..18b06db 100644 --- a/src/app/shared/components/fields/invoice_number_sequence.component.ts +++ b/src/app/shared/components/fields/invoice_number_sequence.component.ts @@ -10,6 +10,7 @@ import { InputComponent } from '../input/input.component'; [name]="name" type="number" [min]="min" + [maxLength]="9" />`, imports: [ReactiveFormsModule, InputComponent], }) diff --git a/src/app/shared/components/fields/partner_token.component.ts b/src/app/shared/components/fields/partner_token.component.ts index e79e24c..4edf071 100644 --- a/src/app/shared/components/fields/partner_token.component.ts +++ b/src/app/shared/components/fields/partner_token.component.ts @@ -4,12 +4,7 @@ import { InputComponent } from '../input/input.component'; @Component({ selector: 'field-partner-token', - template: ``, + template: ``, imports: [ReactiveFormsModule, InputComponent], }) export class PartnerTokenComponent { diff --git a/src/app/shared/components/fields/terminal.component.ts b/src/app/shared/components/fields/terminal.component.ts index 0549ec2..fe22b34 100644 --- a/src/app/shared/components/fields/terminal.component.ts +++ b/src/app/shared/components/fields/terminal.component.ts @@ -4,7 +4,7 @@ import { InputComponent } from '../input/input.component'; @Component({ selector: 'field-terminal', - template: ``, + template: ``, imports: [ReactiveFormsModule, InputComponent], }) export class TerminalComponent { diff --git a/src/app/shared/components/input/input.component.ts b/src/app/shared/components/input/input.component.ts index b3a1902..048e97e 100644 --- a/src/app/shared/components/input/input.component.ts +++ b/src/app/shared/components/input/input.component.ts @@ -66,6 +66,7 @@ export class InputComponent { @Input() isLtrInput = false; @Input() suffix: string = ''; @Input() maxLength?: number; + @Input() length?: number; @Input() min?: number; @Input() max?: number; @Input() fixed?: number; @@ -132,6 +133,8 @@ export class InputComponent { } get preparedMaxLength(): number | null { + const length = this.length || this.maxLength; + if (length) return length; switch (this.type) { case 'mobile': return 11; diff --git a/src/app/shared/components/invoices/sale-invoice-single-view.component.html b/src/app/shared/components/invoices/sale-invoice-single-view.component.html index 0af213e..862ed42 100644 --- a/src/app/shared/components/invoices/sale-invoice-single-view.component.html +++ b/src/app/shared/components/invoices/sale-invoice-single-view.component.html @@ -33,7 +33,7 @@ @for (payment of invoice.payments; track $index) { diff --git a/src/app/shared/components/passwordInput/password-input.component.ts b/src/app/shared/components/passwordInput/password-input.component.ts index 8a47f01..ccfdde8 100644 --- a/src/app/shared/components/passwordInput/password-input.component.ts +++ b/src/app/shared/components/passwordInput/password-input.component.ts @@ -11,8 +11,7 @@ import { Password } from 'primeng/password'; export class SharedPasswordInputComponent { @Input({ required: true }) passwordControl = new FormControl(''); @Input({ required: true }) confirmPasswordControl = new FormControl(''); - @Input() hint: string = - 'رمز باید حداقل ۸ کاراکتر بوده و شامل حداقل یک حرف بزرگ، یک حرف کوچک، یک عدد و یک کاراکتر ویژه باشد.'; + @Input() hint: string = 'رمز باید حداقل ۶ کاراکتر باشد.'; @Input() fluid: boolean = true; @Input() size: 'small' | 'large' = 'large'; } diff --git a/src/app/shared/constants/fields/index.ts b/src/app/shared/constants/fields/index.ts index 864d763..88a5d33 100644 --- a/src/app/shared/constants/fields/index.ts +++ b/src/app/shared/constants/fields/index.ts @@ -1,5 +1,5 @@ import { - fiscalCodeValidator, + fiscalIdValidator, mobileValidator, password, postalCodeValidator, @@ -30,15 +30,10 @@ export const fieldControl = { value, isRequired ? required() : [], ], - firstName: (value = '', isRequired = true): ControlConfig => [ - value, - isRequired ? required() : [], - ], last_name: (value = '', isRequired = true): ControlConfig => [ value, isRequired ? required() : [], ], - lastName: (value = '', isRequired = true): ControlConfig => [value, isRequired ? required() : []], legal_name: (value = '', isRequired = true): ControlConfig => [ value, isRequired ? required() : [], @@ -55,10 +50,6 @@ export const fieldControl = { value, isRequired ? [Validators.required, mobileValidator()] : [mobileValidator()], ], - mobile: (value = '', isRequired = true): ControlConfig => [ - value, - isRequired ? [Validators.required, mobileValidator()] : [mobileValidator()], - ], email: (value = '', isRequired = false): ControlConfig => [ value, isRequired ? [Validators.required, Validators.email] : [Validators.email], @@ -85,7 +76,7 @@ export const fieldControl = { ], fiscal_id: (value = '', isRequired = true): ControlConfig => [ value, - isRequired ? [Validators.required, fiscalCodeValidator()] : [fiscalCodeValidator()], + isRequired ? [Validators.required, fiscalIdValidator()] : [fiscalIdValidator()], ], partner_token: (value = '', isRequired = true): ControlConfig => [ value,