feat: add sale invoice card component with functionality for sending and retrieving invoice status

- Implemented sale invoice card component with HTML and TypeScript files.
- Added API routes for sale invoices including sending, retrying, and checking status.
- Created models for sale invoice fiscal actions and filters.
- Developed service for handling sale invoice operations.
- Introduced store for managing sale invoice state.
- Created views for listing and displaying single sale invoices.
- Added support for managing stock keeping units with forms and services.
- Implemented reusable select components for measure units and SKUs.
- Enhanced shared components for input fields including fiscal ID, SKU type, and VAT.
This commit is contained in:
2026-05-01 19:45:30 +03:30
parent 8104f1b7a7
commit 83f124b910
94 changed files with 1555 additions and 214 deletions
@@ -4,10 +4,15 @@ import { InputComponent } from '../input/input.component';
@Component({
selector: 'field-fiscal-code',
template: `<app-input label="کد مالیاتی" [control]="control" [name]="name" type="number" />`,
template: `<app-input
label="کد مالیاتی"
[control]="control"
[name]="name"
[isLtrInput]="true"
/>`,
imports: [ReactiveFormsModule, InputComponent],
})
export class FiscalCodeComponent {
export class FiscalIdComponent {
@Input({ required: true }) control = new FormControl<string>('');
@Input() name = 'fiscal_code';
@Input() name = 'fiscal_id';
}
+3 -1
View File
@@ -8,7 +8,7 @@ export * from './device_id.component';
export * from './economic_code.component';
export * from './email.component';
export * from './first_name.component';
export * from './fiscal_code.component';
export * from './fiscal_id.component';
export * from './guild_id.component';
export * from './last_name.component';
export * from './legal_name.component';
@@ -29,6 +29,8 @@ export * from './registration_number.component';
export * from './serial_number.component';
export * from './set_off.component';
export * from './sku.component';
export * from './sku_type.component';
export * from './terminal.component';
export * from './unit_price.component';
export * from './username.component';
export * from './vat.component';
@@ -1,11 +1,11 @@
import { CatalogSkuSelectComponent } from '@/shared/catalog/sku';
import { Component, Input } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { InputComponent } from '../input/input.component';
@Component({
selector: 'field-sku',
template: `<app-input label="شناسه عمومی" [control]="control" [name]="name" />`,
imports: [ReactiveFormsModule, InputComponent],
template: `<catalog-sku-select label="شناسه‌ی کالا" [control]="control" [name]="name" />`,
imports: [ReactiveFormsModule, CatalogSkuSelectComponent],
})
export class SkuComponent {
@Input({ required: true }) control = new FormControl<string>('');
@@ -0,0 +1,13 @@
import { Component, Input } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { InputComponent } from '../input/input.component';
@Component({
selector: 'field-sku-type',
template: `<app-input label="نوع" [control]="control" [name]="name" />`,
imports: [ReactiveFormsModule, InputComponent],
})
export class SkuTypeComponent {
@Input({ required: true }) control = new FormControl<string>('');
@Input() name = 'type';
}
@@ -0,0 +1,13 @@
import { Component, Input } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { InputComponent } from '../input/input.component';
@Component({
selector: 'field-vat',
template: `<app-input label="مالیات بر ارزش افزوده" [control]="control" [name]="name" type="price" />`,
imports: [ReactiveFormsModule, InputComponent],
})
export class VatComponent {
@Input({ required: true }) control = new FormControl<number | string>('');
@Input() name = 'VAT';
}
@@ -1,10 +1,10 @@
<div class="flex items-center">
<div class="flex items-center p-4">
<div class="grow">
<div class="flex items-center gap-2">
@if (backRoute) {
<p-button icon="pi pi-arrow-right" aria-label="بازگشت" outlined [routerLink]="backRoute" />
}
<h4 class="m-0">{{ pageTitle }}</h4>
<span class="text-xl font-bold">{{ pageTitle }}</span>
</div>
</div>
@if (actions) {
@@ -1,7 +1,14 @@
<div class="inline-flex flex-col gap-1 w-full">
<div class="inline-flex gap-2 items-center w-full">
<span class="text-muted-color text-base font-normal flex-auto grow-0">{{ label }}:</span>
<div class="shrink-0 grow">
<div
class="shrink-0 grow"
[ngClass]="{
'text-right': alignment === 'start',
'text-center': alignment === 'center',
'text-left': alignment === 'end',
}"
>
<ng-content>
@if (valueType() === "badge") {
<p-badge [value]="valueToShow()?.toString()" [severity]="value ? 'success' : 'danger'" />
@@ -17,6 +17,7 @@ export class KeyValueComponent {
@Input() label!: string;
@Input() value?: string | boolean | number;
@Input() hint?: string;
@Input() alignment?: 'start' | 'center' | 'end' = 'start';
@Input() type:
| 'price'
| 'active'