feat: implement stock keeping unit management form and list components
- Added StockKeepingUnitFormComponent for creating and editing stock keeping units. - Introduced StockKeepingUnitsComponent for listing stock keeping units with pagination. - Integrated form fields for code, name, VAT, and SKU type in the stock keeping unit form. - Created API routes for stock keeping units with CRUD operations. - Updated input components to handle numeric and price types with Persian/Arabic digit normalization. - Enhanced key-value component to support tag display instead of badge. - Adjusted layout styles for sidebar menu. - Added AGENT.md for repository-specific coding guidelines and practices. - Implemented good management form with file upload and category selection.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
<shared-dialog [header]="preparedTitle" [(visible)]="visible" [modal]="true" [style]="{ width: '500px' }"
|
||||
[closable]="true">
|
||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
||||
@if (visible) {
|
||||
<app-shared-upload-file accept="image/*" name="image" [initial_file_url]="initialValues?.image_url || ''"
|
||||
(onSelect)="changeFile($event)" />
|
||||
}
|
||||
<field-name [control]="form.controls.name" name="name" />
|
||||
<field-sku label="شناسه کالا" [control]="form.controls.sku_id" name="sku_id" />
|
||||
<catalog-guild-goodCategories-select [guildId]="guildId" label="دستهبندی" [control]="form.controls.category_id"
|
||||
name="category_id" />
|
||||
<catalog-measure-units-select label="واحد اندازهگیری" [control]="form.controls.measure_unit_id"
|
||||
name="measure_unit_id" />
|
||||
<app-enum-select type="goodPricingModel" [control]="form.controls.pricing_model" name="pricing_model" />
|
||||
<field-description [control]="form.controls.description" />
|
||||
|
||||
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" />
|
||||
</form>
|
||||
</shared-dialog>
|
||||
@@ -0,0 +1,76 @@
|
||||
import { AbstractFormDialog } from '@/shared/abstractClasses';
|
||||
import { DescriptionComponent, NameComponent, SkuComponent } from '@/shared/components';
|
||||
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
||||
import { Component, Input, signal } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { Maybe } from '@/core';
|
||||
import { EnumSelectComponent } from '@/shared/apiEnum/select.component';
|
||||
import { CatalogGuildGoodCategoriesSelectComponent } from '@/shared/catalog/guildGoodCategories';
|
||||
import { CatalogMeasureUnitsSelectComponent } from '@/shared/catalog/measureUnits';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
import { onSelectFileArgs } from '@/shared/components/uploadFile/model';
|
||||
import { fieldControl } from '@/shared/constants';
|
||||
import { buildFormData } from '@/utils';
|
||||
import { Observable } from 'rxjs';
|
||||
import { SharedUploadFileComponent } from '../uploadFile/upload-file.component';
|
||||
import { IGoodRequestPayload, IGoodResponse } from './types';
|
||||
|
||||
@Component({
|
||||
selector: 'shared-good-form',
|
||||
templateUrl: './form.component.html',
|
||||
imports: [
|
||||
ReactiveFormsModule,
|
||||
SharedDialogComponent,
|
||||
FormFooterActionsComponent,
|
||||
EnumSelectComponent,
|
||||
SkuComponent,
|
||||
CatalogMeasureUnitsSelectComponent,
|
||||
NameComponent,
|
||||
DescriptionComponent,
|
||||
SharedUploadFileComponent,
|
||||
CatalogGuildGoodCategoriesSelectComponent,
|
||||
],
|
||||
})
|
||||
export class SharedGoodFormComponent extends AbstractFormDialog<
|
||||
IGoodRequestPayload,
|
||||
IGoodResponse
|
||||
> {
|
||||
@Input({ required: true }) guildId!: string;
|
||||
@Input({ required: true }) createFn!: (payload: FormData) => Observable<IGoodResponse>;
|
||||
@Input({ required: true }) updateFn!: (payload: FormData) => Observable<IGoodResponse>;
|
||||
|
||||
goodImage = signal<Maybe<File>>(null);
|
||||
|
||||
form = this.fb.group({
|
||||
name: fieldControl.name(this.initialValues?.name || '', true),
|
||||
sku_id: fieldControl.sku(this.initialValues?.sku.id || '', true),
|
||||
measure_unit_id: fieldControl.measure_unit(this.initialValues?.measure_unit.id || '', true),
|
||||
pricing_model: fieldControl.pricing_model(this.initialValues?.pricing_model || '', true),
|
||||
category_id: fieldControl.category_id(this.initialValues?.category.id || '', true),
|
||||
description: fieldControl.description(this.initialValues?.description || '', false),
|
||||
});
|
||||
|
||||
get preparedTitle() {
|
||||
return `${this.editMode ? 'ویرایش' : 'افزودن'} کالا`;
|
||||
}
|
||||
|
||||
changeFile(payload: onSelectFileArgs) {
|
||||
this.goodImage.set(payload.file);
|
||||
}
|
||||
|
||||
override ngOnChanges(): void {
|
||||
this.form.patchValue(this.initialValues || {});
|
||||
this.form.controls.category_id.setValue(this.initialValues?.category.id || '');
|
||||
this.form.controls.measure_unit_id.setValue(this.initialValues?.measure_unit.id || '');
|
||||
this.form.controls.sku_id.setValue(this.initialValues?.sku.id || '');
|
||||
}
|
||||
|
||||
override submitForm() {
|
||||
const formData = buildFormData(this.form, { image: this.goodImage() });
|
||||
if (this.editMode) {
|
||||
return this.updateFn(formData);
|
||||
}
|
||||
return this.createFn(formData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './form.component';
|
||||
export * from './types';
|
||||
@@ -0,0 +1,23 @@
|
||||
import ISummary from '@/core/models/summary';
|
||||
|
||||
export interface IGoodResponse {
|
||||
id: string;
|
||||
name: string;
|
||||
image_url: string;
|
||||
sku: ISummary;
|
||||
category: ISummary;
|
||||
measure_unit: ISummary;
|
||||
pricing_model: string;
|
||||
description?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface IGoodRequestPayload {
|
||||
name: string;
|
||||
sku_id: string;
|
||||
category_id: string;
|
||||
measure_unit_id: string;
|
||||
pricing_model: string;
|
||||
description?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user