feat(purchases): update terminology from "محصول" to "کالا" in purchase forms and templates
refactor(purchases): remove unused purchase receipt components and consolidate receipt template logic fix(suppliers): enhance suppliers select component to support full data option values style(tailwind): improve theme variables for better customization and consistency feat(shared): introduce abstract select component for reusable select field logic chore(purchases): clean up imports and improve component structure for better maintainability
This commit is contained in:
@@ -21,21 +21,21 @@ export const MENU_ITEMS = [
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'محصولات',
|
||||
label: 'کالاها',
|
||||
icon: 'pi pi-fw pi-tags',
|
||||
items: [
|
||||
{
|
||||
label: 'لیست محصولات',
|
||||
label: 'لیست کالاها',
|
||||
icon: 'pi pi-fw pi-list',
|
||||
routerLink: ['/products'],
|
||||
},
|
||||
{
|
||||
label: 'برندهای محصول',
|
||||
label: 'برندهای کالا',
|
||||
icon: 'pi pi-fw pi-tags',
|
||||
routerLink: ['/product-brands'],
|
||||
},
|
||||
{
|
||||
label: 'دستهبندیهای محصول',
|
||||
label: 'دستهبندیهای کالا',
|
||||
icon: 'pi pi-fw pi-list',
|
||||
routerLink: ['/product-categories'],
|
||||
},
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<div class="">
|
||||
<uikit-field label="مشتری">
|
||||
<uikit-field label="مشتری" [control]="control" [showLabel]="showLabel" [showErrors]="showErrors">
|
||||
<p-select
|
||||
[options]="brands()"
|
||||
[options]="items()"
|
||||
optionLabel="name"
|
||||
optionValue="id"
|
||||
[optionValue]="selectOptionValue"
|
||||
placeholder="انتخاب مشتری"
|
||||
[formControl]="control"
|
||||
[showClear]="true"
|
||||
@@ -11,5 +10,4 @@
|
||||
appendTo="body"
|
||||
>
|
||||
</p-select>
|
||||
</uikit-field>
|
||||
</div>
|
||||
</uikit-field>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { AbstractSelectComponent } from '@/shared/components';
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, Input, signal } from '@angular/core';
|
||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { Component } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { Select } from 'primeng/select';
|
||||
import { ICustomerResponse } from '../../models';
|
||||
import { CustomersService } from '../../services/main.service';
|
||||
@@ -11,24 +11,17 @@ import { CustomersService } from '../../services/main.service';
|
||||
templateUrl: './select.component.html',
|
||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent],
|
||||
})
|
||||
export class CustomersSelectComponent {
|
||||
@Input() control!: FormControl<Maybe<number>>;
|
||||
@Input() canInsert: boolean = false;
|
||||
|
||||
export class CustomersSelectComponent extends AbstractSelectComponent<ICustomerResponse> {
|
||||
constructor(private service: CustomersService) {
|
||||
super();
|
||||
this.getData();
|
||||
}
|
||||
|
||||
loading = signal(false);
|
||||
brands = signal<Maybe<ICustomerResponse[]>>(null);
|
||||
|
||||
isOpenFormDialog = signal(false);
|
||||
|
||||
getData() {
|
||||
this.loading.set(true);
|
||||
this.service.getAll().subscribe({
|
||||
next: (res) => {
|
||||
this.brands.set(res.data);
|
||||
this.items.set(res.data);
|
||||
this.loading.set(false);
|
||||
},
|
||||
error: () => {
|
||||
@@ -36,12 +29,4 @@ export class CustomersSelectComponent {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
onOpenForm() {
|
||||
// this.isOpenFormDialog.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<div class="">
|
||||
<uikit-field label="انبار">
|
||||
<uikit-field label="انبار" [control]="control" [showLabel]="showLabel" [showErrors]="showErrors">
|
||||
<p-select
|
||||
[options]="brands()"
|
||||
[options]="items()"
|
||||
optionLabel="name"
|
||||
optionValue="id"
|
||||
[optionValue]="selectOptionValue"
|
||||
placeholder="انتخاب انبار"
|
||||
[formControl]="control"
|
||||
[showClear]="true"
|
||||
@@ -11,5 +10,4 @@
|
||||
appendTo="body"
|
||||
>
|
||||
</p-select>
|
||||
</uikit-field>
|
||||
</div>
|
||||
</uikit-field>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { AbstractSelectComponent } from '@/shared/components';
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, Input, signal } from '@angular/core';
|
||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { Component } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { Select } from 'primeng/select';
|
||||
import { IInventoryResponse } from '../../models';
|
||||
import { InventoriesService } from '../../services/main.service';
|
||||
@@ -11,24 +11,17 @@ import { InventoriesService } from '../../services/main.service';
|
||||
templateUrl: './select.component.html',
|
||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent],
|
||||
})
|
||||
export class InventoriesSelectComponent {
|
||||
@Input() control!: FormControl<Maybe<number>>;
|
||||
@Input() canInsert: boolean = false;
|
||||
|
||||
export class InventoriesSelectComponent extends AbstractSelectComponent<IInventoryResponse> {
|
||||
constructor(private service: InventoriesService) {
|
||||
super();
|
||||
this.getData();
|
||||
}
|
||||
|
||||
loading = signal(false);
|
||||
brands = signal<Maybe<IInventoryResponse[]>>(null);
|
||||
|
||||
isOpenFormDialog = signal(false);
|
||||
|
||||
getData() {
|
||||
this.loading.set(true);
|
||||
this.service.getAll().subscribe({
|
||||
next: (res) => {
|
||||
this.brands.set(res.data);
|
||||
this.items.set(res.data);
|
||||
this.loading.set(false);
|
||||
},
|
||||
error: () => {
|
||||
@@ -36,12 +29,4 @@ export class InventoriesSelectComponent {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
onOpenForm() {
|
||||
// this.isOpenFormDialog.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<p-dialog
|
||||
header="فرم برند محصول"
|
||||
header="فرم برند کالا"
|
||||
[(visible)]="visible"
|
||||
[modal]="true"
|
||||
[style]="{ width: '500px' }"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<div class="">
|
||||
<uikit-field label="برند">
|
||||
<div class="w-full">
|
||||
<uikit-field label="برند" [control]="control" [showLabel]="showLabel" [showErrors]="showErrors">
|
||||
<p-select
|
||||
[options]="brands()"
|
||||
[options]="items()"
|
||||
optionLabel="name"
|
||||
optionValue="id"
|
||||
[optionValue]="selectOptionValue"
|
||||
placeholder="انتخاب برند"
|
||||
[formControl]="control"
|
||||
[showClear]="true"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { AbstractSelectComponent } from '@/shared/components';
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, Input, signal } from '@angular/core';
|
||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { Component } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { Button } from 'primeng/button';
|
||||
import { Select } from 'primeng/select';
|
||||
import { IProductBrandResponse } from '../../models';
|
||||
@@ -13,24 +13,17 @@ import { ProductBrandFormComponent } from '../form.component';
|
||||
templateUrl: './select.component.html',
|
||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent, Button, ProductBrandFormComponent],
|
||||
})
|
||||
export class ProductBrandsSelectComponent {
|
||||
@Input() control!: FormControl<Maybe<number>>;
|
||||
@Input() canInsert: boolean = false;
|
||||
|
||||
export class ProductBrandsSelectComponent extends AbstractSelectComponent<IProductBrandResponse> {
|
||||
constructor(private service: ProductBrandsService) {
|
||||
super();
|
||||
this.getData();
|
||||
}
|
||||
|
||||
loading = signal(false);
|
||||
brands = signal<Maybe<IProductBrandResponse[]>>(null);
|
||||
|
||||
isOpenFormDialog = signal(false);
|
||||
|
||||
getData() {
|
||||
this.loading.set(true);
|
||||
this.service.getAll().subscribe({
|
||||
next: (res) => {
|
||||
this.brands.set(res.data);
|
||||
this.items.set(res.data);
|
||||
this.loading.set(false);
|
||||
},
|
||||
error: () => {
|
||||
@@ -38,12 +31,4 @@ export class ProductBrandsSelectComponent {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
onOpenForm() {
|
||||
this.isOpenFormDialog.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ export const productBrandsNamedRoutes: NamedRoutes<TProductBrandsRouteNames> = {
|
||||
path: 'product-brands',
|
||||
loadComponent: () => import('../../views/list.component').then((m) => m.ProductBrandsComponent),
|
||||
meta: {
|
||||
title: 'برندهای محصول',
|
||||
title: 'برندهای کالا',
|
||||
pagePath: () => '/product-brands',
|
||||
},
|
||||
},
|
||||
@@ -17,7 +17,7 @@ export const productBrandsNamedRoutes: NamedRoutes<TProductBrandsRouteNames> = {
|
||||
loadComponent: () =>
|
||||
import('../../views/single.component').then((m) => m.ProductBrandComponent),
|
||||
meta: {
|
||||
title: 'برند محصول',
|
||||
title: 'برند کالا',
|
||||
pagePath: () => '/product-brands/:brandId',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<app-page-data-list
|
||||
[pageTitle]="'مدیریت برندهای محصول'"
|
||||
[pageTitle]="'مدیریت برندهای کالا'"
|
||||
[addNewCtaLabel]="'افزودن برند جدید'"
|
||||
[columns]="columns"
|
||||
[items]="items()"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<p-dialog
|
||||
header="فرم دستهبندی محصول"
|
||||
header="فرم دستهبندی کالا"
|
||||
[(visible)]="visible"
|
||||
[modal]="true"
|
||||
[style]="{ width: '500px' }"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<div class="">
|
||||
<uikit-field label="دستهبندی">
|
||||
<div class="w-full">
|
||||
<uikit-field label="دستهبندی" [control]="control" [showLabel]="showLabel" [showErrors]="showErrors">
|
||||
<p-select
|
||||
[options]="brands()"
|
||||
[options]="items()"
|
||||
optionLabel="name"
|
||||
optionValue="id"
|
||||
[optionValue]="selectOptionValue"
|
||||
placeholder="انتخاب دستهبندی"
|
||||
[formControl]="control"
|
||||
[showClear]="true"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { AbstractSelectComponent } from '@/shared/components';
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, Input, signal } from '@angular/core';
|
||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { Component } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { Button } from 'primeng/button';
|
||||
import { Select } from 'primeng/select';
|
||||
import { IProductCategoryResponse } from '../../models';
|
||||
@@ -13,24 +13,17 @@ import { ProductCategoryFormComponent } from '../form.component';
|
||||
templateUrl: './select.component.html',
|
||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent, Button, ProductCategoryFormComponent],
|
||||
})
|
||||
export class ProductCategoriesSelectComponent {
|
||||
@Input() control!: FormControl<Maybe<number>>;
|
||||
@Input() canInsert: boolean = false;
|
||||
|
||||
export class ProductCategoriesSelectComponent extends AbstractSelectComponent<IProductCategoryResponse> {
|
||||
constructor(private service: ProductCategoriesService) {
|
||||
super();
|
||||
this.getData();
|
||||
}
|
||||
|
||||
loading = signal(false);
|
||||
brands = signal<Maybe<IProductCategoryResponse[]>>(null);
|
||||
|
||||
isOpenFormDialog = signal(false);
|
||||
|
||||
getData() {
|
||||
this.loading.set(true);
|
||||
this.service.getAll().subscribe({
|
||||
next: (res) => {
|
||||
this.brands.set(res.data);
|
||||
this.items.set(res.data);
|
||||
this.loading.set(false);
|
||||
},
|
||||
error: () => {
|
||||
@@ -38,12 +31,4 @@ export class ProductCategoriesSelectComponent {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
onOpenForm() {
|
||||
this.isOpenFormDialog.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ export const productCategoriesNamedRoutes: NamedRoutes<TProductCategoriesRouteNa
|
||||
loadComponent: () =>
|
||||
import('../../views/list.component').then((m) => m.ProductCategoriesComponent),
|
||||
meta: {
|
||||
title: 'دستهبندی محصولات',
|
||||
title: 'دستهبندی کالاها',
|
||||
pagePath: () => '/product-categories',
|
||||
},
|
||||
},
|
||||
@@ -18,7 +18,7 @@ export const productCategoriesNamedRoutes: NamedRoutes<TProductCategoriesRouteNa
|
||||
loadComponent: () =>
|
||||
import('../../views/single.component').then((m) => m.ProductCategoryComponent),
|
||||
meta: {
|
||||
title: 'دستهبندی محصول',
|
||||
title: 'دستهبندی کالا',
|
||||
pagePath: () => '/product-categories/:categoryId',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<app-page-data-list
|
||||
[pageTitle]="'مدیریت دستهبندی محصولات'"
|
||||
[pageTitle]="'مدیریت دستهبندی کالاها'"
|
||||
[addNewCtaLabel]="'افزودن دستهبندی جدید'"
|
||||
[columns]="columns"
|
||||
[showAdd]="true"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<p-dialog [(visible)]="visible" [modal]="true" [style]="{ width: '50vw' }" header="افزودن هزینه محصول">
|
||||
<p-dialog [(visible)]="visible" [modal]="true" [style]="{ width: '50vw' }" header="افزودن هزینه کالا">
|
||||
<form [formGroup]="form" (ngSubmit)="submit()">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<products-select-field [control]="form.controls.productId" />
|
||||
|
||||
@@ -28,7 +28,7 @@ export class ProductChargesComponent {
|
||||
{ field: 'totalAmount', header: 'مبلغ کل' },
|
||||
{ field: 'isSettled', header: 'تسویه شده' },
|
||||
{ field: 'buyAt', header: 'تاریخ خرید' },
|
||||
{ field: 'productId', header: 'شناسه محصول' },
|
||||
{ field: 'productId', header: 'شناسه کالا' },
|
||||
{ field: 'inventoryId', header: 'شناسه انبار' },
|
||||
{ field: 'supplierId', header: 'شناسه تامینکننده' },
|
||||
{ field: 'createdAt', header: 'تاریخ ایجاد' },
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<p-dialog header="فرم محصول" [(visible)]="visible" [modal]="true" [style]="{ width: '600px' }" [closable]="true">
|
||||
<p-dialog header="فرم کالا" [(visible)]="visible" [modal]="true" [style]="{ width: '600px' }" [closable]="true">
|
||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
||||
<app-input label="نام" [control]="form.controls.name" name="name" />
|
||||
<product-brands-select-field [control]="form.controls.brandId" [canInsert]="true" />
|
||||
<product-categories-select-field [control]="form.controls.categoryId" [canInsert]="true" />
|
||||
<app-input label="توضیحات" [control]="form.controls.description" name="description" />
|
||||
<!-- <app-input label="نوع محصول" [control]="form.controls.productType" name="productType" /> -->
|
||||
<!-- <app-input label="نوع کالا" [control]="form.controls.productType" name="productType" /> -->
|
||||
<!-- <app-input label="برند" [control]="form.controls.brandId" name="brandId" type="" />
|
||||
<app-input label="دستهبندی" [control]="form.controls.categoryId" name="categoryId" type="number" />
|
||||
<app-input label="تامینکننده" [control]="form.controls.supplierId" name="supplierId" type="number" /> -->
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="flex items-center gap-5 justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<p-button icon="pi pi-arrow-right" aria-label="بازگشت" outlined [routerLink]="backRoute" />
|
||||
<h3 class="m-0">{{ initialData ? "ویرایش محصول" : "ایجاد محصول جدید" }}</h3>
|
||||
<h3 class="m-0">{{ initialData ? "ویرایش کالا" : "ایجاد کالا جدید" }}</h3>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<div class="flex flex-col gap-3 grow">
|
||||
<p-card header="جزئیات محصول" class="w-full">
|
||||
<p-card header="جزئیات کالا" class="w-full">
|
||||
<form [formGroup]="form" (submit)="submit()" class="grid grid-cols-2 gap-4">
|
||||
<app-input label="نام" [control]="form.controls.name" name="name" class="col-span-2" />
|
||||
<app-input label="SKU" [control]="form.controls.sku" name="sku" />
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<uikit-field label="محصول" [control]="control" [showLabel]="showLabel" [showErrors]="showErrors">
|
||||
<uikit-field label="کالا" [control]="control" [showLabel]="showLabel" [showErrors]="showErrors">
|
||||
<p-select
|
||||
[options]="items()"
|
||||
optionLabel="name"
|
||||
[optionValue]="selectOptionValue"
|
||||
placeholder="انتخاب محصول"
|
||||
placeholder="انتخاب کالا"
|
||||
[formControl]="control"
|
||||
[showClear]="true"
|
||||
[filter]="true"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { AbstractSelectComponent } from '@/shared/components';
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, Input, signal } from '@angular/core';
|
||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { Component } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { Select } from 'primeng/select';
|
||||
import { IProductResponse } from '../../models';
|
||||
import { ProductsService } from '../../services/main.service';
|
||||
@@ -12,20 +12,15 @@ import { ProductsService } from '../../services/main.service';
|
||||
templateUrl: './select.component.html',
|
||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent, CommonModule],
|
||||
})
|
||||
export class ProductsSelectComponent {
|
||||
@Input() control!: FormControl<Maybe<number | IProductResponse>>;
|
||||
@Input() canInsert: boolean = false;
|
||||
@Input() showLabel: boolean = true;
|
||||
@Input() showErrors: boolean = true;
|
||||
|
||||
export class ProductsSelectComponent extends AbstractSelectComponent<IProductResponse> {
|
||||
constructor(private service: ProductsService) {
|
||||
super();
|
||||
this.getData();
|
||||
}
|
||||
|
||||
loading = signal(false);
|
||||
items = signal<Maybe<IProductResponse[]>>(null);
|
||||
|
||||
isOpenFormDialog = signal(false);
|
||||
getLabel(): string {
|
||||
return 'کالا';
|
||||
}
|
||||
|
||||
getData() {
|
||||
this.loading.set(true);
|
||||
@@ -39,19 +34,4 @@ export class ProductsSelectComponent {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
onOpenForm() {
|
||||
// this.isOpenFormDialog.set(true);
|
||||
}
|
||||
|
||||
get selectOptionValue() {
|
||||
if (typeof this.control.value === 'number') {
|
||||
return 'id';
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ export const productsNamedRoutes: NamedRoutes<TProductsRouteNames> = {
|
||||
path: 'products',
|
||||
loadComponent: () => import('../../views/list.component').then((m) => m.ProductsComponent),
|
||||
meta: {
|
||||
title: 'محصولات',
|
||||
title: 'کالاها',
|
||||
pagePath: () => '/products',
|
||||
},
|
||||
},
|
||||
@@ -17,7 +17,7 @@ export const productsNamedRoutes: NamedRoutes<TProductsRouteNames> = {
|
||||
loadComponent: () =>
|
||||
import('../../views/create.component').then((m) => m.CreateProductComponent),
|
||||
meta: {
|
||||
title: 'ایجاد محصول جدید',
|
||||
title: 'ایجاد کالا جدید',
|
||||
pagePath: () => '/products/create',
|
||||
},
|
||||
},
|
||||
@@ -25,7 +25,7 @@ export const productsNamedRoutes: NamedRoutes<TProductsRouteNames> = {
|
||||
path: 'products/:productId',
|
||||
loadComponent: () => import('../../views/single.component').then((m) => m.ProductComponent),
|
||||
meta: {
|
||||
title: 'محصول',
|
||||
title: 'کالا',
|
||||
pagePath: () => '/products/:productId',
|
||||
},
|
||||
},
|
||||
@@ -34,7 +34,7 @@ export const productsNamedRoutes: NamedRoutes<TProductsRouteNames> = {
|
||||
loadComponent: () =>
|
||||
import('../../views/update.component').then((m) => m.UpdateProductComponent),
|
||||
meta: {
|
||||
title: 'محصول',
|
||||
title: 'کالا',
|
||||
pagePath: () => '/products/:productId/update',
|
||||
},
|
||||
},
|
||||
@@ -43,7 +43,7 @@ export const productsNamedRoutes: NamedRoutes<TProductsRouteNames> = {
|
||||
loadComponent: () =>
|
||||
import('../../views/purchase.component').then((m) => m.ProductPurchaseComponent),
|
||||
meta: {
|
||||
title: 'محصول',
|
||||
title: 'کالا',
|
||||
pagePath: () => '/products/:productId/purchase',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -25,7 +25,7 @@ export class CreateProductComponent {
|
||||
this.submitLoading.set(true);
|
||||
this.service.create(payload).subscribe({
|
||||
next: (res) => {
|
||||
this.toastService.success({ text: `محصول ${payload.name} با موفقیت ایجاد شد` });
|
||||
this.toastService.success({ text: `کالا ${payload.name} با موفقیت ایجاد شد` });
|
||||
this.router.navigate(['products', res.id]);
|
||||
this.submitLoading.set(false);
|
||||
},
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<app-page-data-list
|
||||
[pageTitle]="'مدیریت محصولات'"
|
||||
[addNewCtaLabel]="'افزودن محصول جدید'"
|
||||
[pageTitle]="'مدیریت کالاها'"
|
||||
[addNewCtaLabel]="'افزودن کالا جدید'"
|
||||
[columns]="columns"
|
||||
[showAdd]="true"
|
||||
emptyPlaceholderTitle="محصولی یافت نشد"
|
||||
emptyPlaceholderDescription="برای افزودن محصول جدید، روی دکمهٔ بالا کلیک کنید."
|
||||
emptyPlaceholderTitle="کالای یافت نشد"
|
||||
emptyPlaceholderDescription="برای افزودن کالا جدید، روی دکمهٔ بالا کلیک کنید."
|
||||
[items]="items()"
|
||||
[loading]="loading()"
|
||||
[showDetails]="true"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PurchaseReceiptTemplateComponent } from '@/modules/purchases/components/purchase-receipt-template.component';
|
||||
import { PurchaseReceiptTemplateComponent } from '@/modules/purchases/components/receiptTemplate/purchase-receipt-template.component';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -45,7 +45,7 @@ export class UpdateProductComponent {
|
||||
this.submitLoading.set(true);
|
||||
this.service.update(this.productId, payload).subscribe({
|
||||
next: (res) => {
|
||||
this.toastService.success({ text: `محصول ${payload.name} با موفقیت ویرایش شد` });
|
||||
this.toastService.success({ text: `کالا ${payload.name} با موفقیت ویرایش شد` });
|
||||
this.router.navigate(['products', this.productId]);
|
||||
this.submitLoading.set(false);
|
||||
},
|
||||
|
||||
@@ -57,7 +57,7 @@ export class PurchaseFormComponent {
|
||||
|
||||
get formTitle() {
|
||||
if (this.product) {
|
||||
return `شارژ محصول ${this.product.name}`;
|
||||
return `شارژ کالا ${this.product.name}`;
|
||||
}
|
||||
if (this.inventory) {
|
||||
return `شارژ انبار ${this.inventory.name}`;
|
||||
@@ -65,7 +65,7 @@ export class PurchaseFormComponent {
|
||||
if (this.supplier) {
|
||||
return `شارژ تامینکننده ${this.supplier.fullname}`;
|
||||
}
|
||||
return 'شارژ محصول';
|
||||
return 'شارژ کالا';
|
||||
}
|
||||
|
||||
constructor() {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from './receiptTemplate';
|
||||
@@ -20,13 +20,13 @@
|
||||
class="shrink-0"
|
||||
(click)="removeProduct(i)"
|
||||
[disabled]="productsControl.length === 1"
|
||||
pTooltip="حذف محصول"
|
||||
pTooltip="حذف کالا"
|
||||
></button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@if (canAddOrRemoveProducts) {
|
||||
<button pButton type="button" label="افزودن محصول" (click)="addProduct()" pTooltip="افزودن محصول"></button>
|
||||
<button pButton type="button" label="افزودن کالا" (click)="addProduct()" pTooltip="افزودن کالا"></button>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
<form [formGroup]="form">
|
||||
<p-card class="grid grid-cols-1 p-0 max-w-6xl mx-auto border border-surface-700">
|
||||
<div class="mb-4 text-center">
|
||||
<h2 class="m-0">رسید خرید</h2>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4 border-b border-surface-700 pb-4">
|
||||
<div class="grid grid-cols-1 gap-2">
|
||||
<shared-inline-edit>
|
||||
<ng-template #data>
|
||||
<app-key-value label="انبار" value="انبار انتخاب شده" />
|
||||
</ng-template>
|
||||
<ng-template #field>
|
||||
<inventories-select-field [control]="form.controls.inventoryId" />
|
||||
</ng-template>
|
||||
</shared-inline-edit>
|
||||
<shared-inline-edit>
|
||||
<ng-template #data>
|
||||
<app-key-value label="تامین کننده" value="تامینکنندهی انتخاب شده" />
|
||||
</ng-template>
|
||||
<ng-template #field>
|
||||
<suppliers-select-field [control]="form.controls.supplierId" />
|
||||
</ng-template>
|
||||
</shared-inline-edit>
|
||||
</div>
|
||||
<div class="">
|
||||
<div class="flex flex-col gap-2 max-w-xs items-end ms-auto w-full">
|
||||
<shared-inline-edit class="w-full block">
|
||||
<ng-template #data>
|
||||
<app-key-value label="شماره رسید" value="۲۱۳۱۲۳" />
|
||||
</ng-template>
|
||||
<ng-template #field>
|
||||
<app-input label="شماره رسید" [control]="form.controls.code" />
|
||||
</ng-template>
|
||||
</shared-inline-edit>
|
||||
<shared-inline-edit class="w-full block">
|
||||
<ng-template #data>
|
||||
<app-key-value label="تاریخ رسید" value="۲۱۳۱۲۳" />
|
||||
</ng-template>
|
||||
<ng-template #field>
|
||||
<app-input label="تاریخ خرید" [control]="form.controls.buyAt" />
|
||||
</ng-template>
|
||||
</shared-inline-edit>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p-table
|
||||
[columns]="columns"
|
||||
[value]="this.form.controls.products.controls"
|
||||
[scrollable]="true"
|
||||
[resizableColumns]="false"
|
||||
[tableStyleClass]="'table-fixed'"
|
||||
>
|
||||
<ng-template #header let-columns>
|
||||
<tr>
|
||||
@for (col of columns; track $index) {
|
||||
<th [style]="{ width: col.width, minWidth: col.minWidth }">
|
||||
{{ col.header }}
|
||||
</th>
|
||||
}
|
||||
</tr>
|
||||
</ng-template>
|
||||
<ng-template #body let-product let-columns="columns" let-rowIndex="rowIndex">
|
||||
<tr
|
||||
purchase-receipt-product-row
|
||||
[rowIndex]="rowIndex"
|
||||
[purchaseItemControl]="product"
|
||||
[canRemove]="this.form.controls.products.controls.length > 1"
|
||||
(onRemove)="removePurchaseItem(rowIndex)"
|
||||
></tr>
|
||||
<!-- <tr>
|
||||
@for (col of columns; track $index) {
|
||||
<td>
|
||||
@if (col.field === "index") {
|
||||
{{ rowIndex + 1 }}
|
||||
} @else if (col.field === "name") {
|
||||
<shared-inline-edit>
|
||||
<ng-template #data>
|
||||
{{ product.name || "-" }}
|
||||
</ng-template>
|
||||
<ng-template #field>
|
||||
<products-select-field
|
||||
[control]="form.controls.products.controls[rowIndex].controls.productId"
|
||||
[showLabel]="false"
|
||||
></products-select-field>
|
||||
</ng-template>
|
||||
</shared-inline-edit>
|
||||
} @else if (col.field === "total") {
|
||||
{{ product["fee"] * product["count"] || 0 }}
|
||||
} @else if (col.field === "action") {
|
||||
<div class="flex items-center gap-2">
|
||||
<button></button>
|
||||
</div>
|
||||
} @else {
|
||||
{{ product[col.field] }}
|
||||
}
|
||||
</td>
|
||||
}
|
||||
</tr> -->
|
||||
</ng-template>
|
||||
</p-table>
|
||||
<div class="flex items-center justify-center py-3">
|
||||
<button
|
||||
pButton
|
||||
type="button"
|
||||
icon="pi pi-plus"
|
||||
size="large"
|
||||
rounded
|
||||
outlined
|
||||
(click)="onAddProductClick()"
|
||||
></button>
|
||||
</div>
|
||||
<div class="flex border-t border-surface-700 items-stretch">
|
||||
<div class="grow border-e border-surface-700"></div>
|
||||
<div class="shrink-0 w-xs">
|
||||
<div class="flex flex-col gap-2 p-4">
|
||||
<div class="flex justify-between">
|
||||
<span>جمع کل:</span>
|
||||
<span [appPriceMask]="totalAmount"></span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span>مالیات (۹٪):</span>
|
||||
<span [appPriceMask]="totalAmount * 0.09"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex border-t border-surface-700 pt-4">
|
||||
<div class="grow">
|
||||
<span>مبلغ قابل پرداخت:</span>
|
||||
<span [appPriceAlphabet]="totalAmount + totalAmount * 0.09"></span>
|
||||
</div>
|
||||
<div class="shrink-0 w-xs">
|
||||
<span [appPriceMask]="totalAmount + totalAmount * 0.09"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-center gap-2 mt-10">
|
||||
<button pButton type="button" label="لغو" outlined (click)="onCancel()"></button>
|
||||
<button pButton type="button" label="ثبت رسید" (click)="onSubmit()"></button>
|
||||
</div>
|
||||
</p-card>
|
||||
</form>
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './purchase-receipt-product-row.component';
|
||||
export * from './purchase-receipt-template.component';
|
||||
+6
-1
@@ -13,7 +13,12 @@
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<products-select-field [control]="purchaseItemControl.controls.product" [showLabel]="false" [showErrors]="false" />
|
||||
<products-select-field
|
||||
[control]="purchaseItemControl.controls.product"
|
||||
[isFullDataOptionValue]="true"
|
||||
[showLabel]="false"
|
||||
[showErrors]="false"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<textarea
|
||||
+1
-1
@@ -6,7 +6,7 @@ import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { InputText } from 'primeng/inputtext';
|
||||
import { Textarea } from 'primeng/textarea';
|
||||
import { IPurchaseItemFormGroup } from '../models';
|
||||
import { IPurchaseItemFormGroup } from '../../models';
|
||||
|
||||
@Component({
|
||||
selector: 'tr[purchase-receipt-product-row]',
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
<form [formGroup]="form">
|
||||
<p-card class="grid grid-cols-1 p-0! max-w-6xl mx-auto border border-surface-700">
|
||||
<div class="mb-4 text-center">
|
||||
<h2 class="m-0">رسید خرید</h2>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4 border-b border-surface-700 pb-4">
|
||||
<div class="grid grid-cols-1 gap-2">
|
||||
<div class="w-full flex items-center gap-2 h-10">
|
||||
<span [class]="formIsSubmitted() && form.controls.inventory.invalid ? ' text-error' : 'text-muted-color'"
|
||||
>انبار:</span
|
||||
>
|
||||
<shared-inline-edit>
|
||||
<ng-template #data>
|
||||
<span class="font-bold">{{ form.controls.inventory.value?.name || "وارد نشده" }}</span>
|
||||
</ng-template>
|
||||
<ng-template #field>
|
||||
<inventories-select-field
|
||||
[control]="form.controls.inventory"
|
||||
[isFullDataOptionValue]="true"
|
||||
[showErrors]="false"
|
||||
[showLabel]="false"
|
||||
/>
|
||||
</ng-template>
|
||||
</shared-inline-edit>
|
||||
</div>
|
||||
<div class="w-full flex items-center gap-2 h-10">
|
||||
<span [class]="formIsSubmitted() && form.controls.supplier.invalid ? ' text-error' : 'text-muted-color'"
|
||||
>تامین کننده:</span
|
||||
>
|
||||
<shared-inline-edit>
|
||||
<ng-template #data>
|
||||
<span class="font-bold">{{ form.controls.supplier.value?.fullname || "وارد نشده" }}</span>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #field>
|
||||
<suppliers-select-field
|
||||
[control]="form.controls.supplier"
|
||||
[isFullDataOptionValue]="true"
|
||||
[showErrors]="false"
|
||||
[showLabel]="false"
|
||||
/>
|
||||
</ng-template>
|
||||
</shared-inline-edit>
|
||||
</div>
|
||||
</div>
|
||||
<div class="">
|
||||
<div class="flex flex-col gap-2 max-w-xs items-end ms-auto w-full">
|
||||
<div class="w-full flex items-center gap-2 h-10">
|
||||
<span [class]="formIsSubmitted() && form.controls.code.invalid ? ' text-error' : 'text-muted-color'"
|
||||
>شماره رسید:</span
|
||||
>
|
||||
<shared-inline-edit>
|
||||
<ng-template #data>
|
||||
<span class="font-bold">{{ form.controls.code.value || "وارد نشده" }}</span>
|
||||
</ng-template>
|
||||
<ng-template #field>
|
||||
<app-input [control]="form.controls.code" [showErrors]="false" />
|
||||
</ng-template>
|
||||
</shared-inline-edit>
|
||||
</div>
|
||||
<div class="w-full flex items-center gap-2 h-10">
|
||||
<span [class]="formIsSubmitted() && form.controls.buyAt.invalid ? ' text-error' : 'text-muted-color'"
|
||||
>تاریخ رسید:</span
|
||||
>
|
||||
<shared-inline-edit>
|
||||
<ng-template #data>
|
||||
<span class="font-bold">{{ form.controls.buyAt.value || "وارد نشده" }}</span>
|
||||
</ng-template>
|
||||
<ng-template #field>
|
||||
<uikit-datepicker [control]="form.controls.buyAt" [showErrors]="false" [showLabel]="false" />
|
||||
</ng-template>
|
||||
</shared-inline-edit>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p-table
|
||||
[columns]="columns"
|
||||
[value]="this.form.controls.products.controls"
|
||||
[scrollable]="true"
|
||||
[resizableColumns]="false"
|
||||
[tableStyleClass]="'table-fixed'"
|
||||
>
|
||||
<ng-template #header let-columns>
|
||||
<tr>
|
||||
@for (col of columns; track $index) {
|
||||
<th [style]="{ width: col.width, minWidth: col.minWidth }">
|
||||
{{ col.header }}
|
||||
</th>
|
||||
}
|
||||
</tr>
|
||||
</ng-template>
|
||||
<ng-template #body let-product let-columns="columns" let-rowIndex="rowIndex">
|
||||
<tr
|
||||
purchase-receipt-product-row
|
||||
[rowIndex]="rowIndex"
|
||||
[purchaseItemControl]="product"
|
||||
[canRemove]="this.form.controls.products.controls.length > 1"
|
||||
(onRemove)="removePurchaseItem(rowIndex)"
|
||||
></tr>
|
||||
<!-- <tr>
|
||||
@for (col of columns; track $index) {
|
||||
<td>
|
||||
@if (col.field === "index") {
|
||||
{{ rowIndex + 1 }}
|
||||
} @else if (col.field === "name") {
|
||||
<shared-inline-edit>
|
||||
<ng-template #data>
|
||||
{{ product.name || "-" }}
|
||||
</ng-template>
|
||||
<ng-template #field>
|
||||
<products-select-field
|
||||
[control]="form.controls.products.controls[rowIndex].controls.productId"
|
||||
[showLabel]="false"
|
||||
></products-select-field>
|
||||
</ng-template>
|
||||
</shared-inline-edit>
|
||||
} @else if (col.field === "total") {
|
||||
{{ product["fee"] * product["count"] || 0 }}
|
||||
} @else if (col.field === "action") {
|
||||
<div class="flex items-center gap-2">
|
||||
<button></button>
|
||||
</div>
|
||||
} @else {
|
||||
{{ product[col.field] }}
|
||||
}
|
||||
</td>
|
||||
}
|
||||
</tr> -->
|
||||
</ng-template>
|
||||
<ng-template #footer>
|
||||
<tr>
|
||||
<td [attr.colspan]="8" class="p-0!">
|
||||
<div class="flex justify-center p-3">
|
||||
<button
|
||||
pButton
|
||||
type="button"
|
||||
label="افزودن کالا"
|
||||
icon="pi pi-plus"
|
||||
(click)="onAddProductClick()"
|
||||
></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td [attr.colspan]="6" class="border-e border-surface-700"></td>
|
||||
<td [attr.colspan]="2" class="p-0!">
|
||||
<div class="flex flex-col gap-4 w-full border-s border-surface-700 px-3 py-6">
|
||||
<div class="flex justify-between">
|
||||
<span>جمع کل:</span>
|
||||
<span class="font-bold" [appPriceMask]="totalAmount"></span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span>مالیات (۹٪):</span>
|
||||
<span class="font-bold" [appPriceMask]="totalAmount * 0.09"></span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td [attr.colspan]="6" class="p-0! border-none!">
|
||||
<div class="w-full flex items-center gap-2 py-10 border-surface-700 border-t-4">
|
||||
<span>مبلغ قابل پرداخت:</span>
|
||||
<span [appPriceAlphabet]="totalAmount + totalAmount * 0.09" class="font-bold text-lg"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td [attr.colspan]="2" class="p-0! border-none!">
|
||||
<div class="flex h-full items-center justify-end py-10 px-2 border-surface-700 border-t-4 border-r">
|
||||
<span [appPriceMask]="totalAmount + totalAmount * 0.09" class="text-xl font-bold"></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
</p-table>
|
||||
</p-card>
|
||||
|
||||
<div class="flex items-center justify-center gap-2 mt-10">
|
||||
<button pButton type="button" label="لغو" outlined [disabled]="form.disabled" (click)="onCancel()"></button>
|
||||
<button pButton type="button" label="ثبت رسید" [loading]="form.disabled" (click)="onSubmit()"></button>
|
||||
</div>
|
||||
</form>
|
||||
+59
-23
@@ -1,18 +1,22 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { ToastService } from '@/core/services/toast.service';
|
||||
import { InventoriesSelectComponent } from '@/modules/inventories/components/select/select.component';
|
||||
import { IInventoryResponse } from '@/modules/inventories/models';
|
||||
import { IProductResponse } from '@/modules/products/models';
|
||||
import { SuppliersSelectComponent } from '@/modules/suppliers/components/select/select.component';
|
||||
import { ISupplierResponse } from '@/modules/suppliers/models';
|
||||
import { InlineEditComponent, InputComponent, KeyValueComponent } from '@/shared/components';
|
||||
import { InlineEditComponent, InputComponent } from '@/shared/components';
|
||||
import { IColumn } from '@/shared/components/pageDataList/page-data-list.component';
|
||||
import { PriceAlphabetDirective, PriceMaskDirective } from '@/shared/directives';
|
||||
import { UikitFlatpickrJalaliComponent } from '@/uikit';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, inject, Input } from '@angular/core';
|
||||
import { Component, inject, Input, signal } from '@angular/core';
|
||||
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { Card } from 'primeng/card';
|
||||
import { TableModule } from 'primeng/table';
|
||||
import { IPurchaseRequest } from '../../models';
|
||||
import { PurchasesService } from '../../services/main.service';
|
||||
import { PurchaseReceiptProductRowComponent } from './purchase-receipt-product-row.component';
|
||||
|
||||
@Component({
|
||||
@@ -27,13 +31,13 @@ import { PurchaseReceiptProductRowComponent } from './purchase-receipt-product-r
|
||||
InputComponent,
|
||||
TableModule,
|
||||
InlineEditComponent,
|
||||
KeyValueComponent,
|
||||
PurchaseReceiptProductRowComponent,
|
||||
PriceAlphabetDirective,
|
||||
PriceMaskDirective,
|
||||
ButtonDirective,
|
||||
CommonModule,
|
||||
ReactiveFormsModule,
|
||||
UikitFlatpickrJalaliComponent,
|
||||
],
|
||||
})
|
||||
export class PurchaseReceiptTemplateComponent {
|
||||
@@ -43,15 +47,6 @@ export class PurchaseReceiptTemplateComponent {
|
||||
@Input() inventory?: IInventoryResponse;
|
||||
@Input() supplier?: ISupplierResponse;
|
||||
|
||||
constructor() {
|
||||
this.form.controls.products.valueChanges.subscribe((products) => {
|
||||
let totalAmount = 0;
|
||||
products.forEach((p: any) => {
|
||||
totalAmount += p.total || 0;
|
||||
});
|
||||
this.form.controls.totalAmount.setValue(totalAmount);
|
||||
});
|
||||
}
|
||||
columns = [
|
||||
{
|
||||
field: 'index',
|
||||
@@ -96,25 +91,41 @@ export class PurchaseReceiptTemplateComponent {
|
||||
] as IColumn[];
|
||||
|
||||
form = this.fb.group({
|
||||
totalAmount: [0, [Validators.required, Validators.min(0)]],
|
||||
code: ['', [Validators.required]],
|
||||
totalAmount: [300000, [Validators.required, Validators.min(0)]],
|
||||
code: ['122132', [Validators.required]],
|
||||
isSettled: [false],
|
||||
buyAt: ['', Validators.required],
|
||||
buyAt: ['2025-12-01', Validators.required],
|
||||
description: [''],
|
||||
products: this.fb.array([
|
||||
this.fb.group({
|
||||
product: [null as Maybe<IProductResponse>, [Validators.required]],
|
||||
count: [0, [Validators.required, Validators.min(1)]],
|
||||
fee: [0, [Validators.required, Validators.min(0)]],
|
||||
product: [{ id: 1 } as Maybe<IProductResponse>, [Validators.required]],
|
||||
count: [2, [Validators.required, Validators.min(1)]],
|
||||
fee: [150000, [Validators.required, Validators.min(0)]],
|
||||
description: [''],
|
||||
total: [0, [Validators.required, Validators.min(0)]],
|
||||
total: [300000, [Validators.required, Validators.min(0)]],
|
||||
}),
|
||||
]),
|
||||
inventoryId: [this.inventory?.id || 0, [Validators.required]],
|
||||
supplierId: [this.supplier?.id || 0, [Validators.required]],
|
||||
inventory: [{ id: 2 } as Maybe<IInventoryResponse>, [Validators.required]],
|
||||
supplier: [{ id: 1 } as Maybe<ISupplierResponse>, [Validators.required]],
|
||||
});
|
||||
|
||||
constructor(
|
||||
private service: PurchasesService,
|
||||
private toastService: ToastService,
|
||||
) {
|
||||
this.form.controls.products.valueChanges.subscribe((products) => {
|
||||
let totalAmount = 0;
|
||||
products.forEach((p: any) => {
|
||||
totalAmount += p.total || 0;
|
||||
});
|
||||
this.form.controls.totalAmount.setValue(totalAmount);
|
||||
});
|
||||
}
|
||||
|
||||
formIsSubmitted = signal(false);
|
||||
|
||||
ngOnInit() {
|
||||
this.formIsSubmitted.set(false);
|
||||
if (this.product) {
|
||||
this.form.controls.products.at(0).setValue({
|
||||
product: this.product,
|
||||
@@ -147,9 +158,34 @@ export class PurchaseReceiptTemplateComponent {
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.formIsSubmitted.set(true);
|
||||
this.form.markAllAsTouched();
|
||||
if (this.form.valid) {
|
||||
// Handle form submission logic here
|
||||
console.log('Form Submitted', this.form.value);
|
||||
const { products, inventory, supplier, ...res } = this.form.value;
|
||||
|
||||
const payload = {
|
||||
...res,
|
||||
inventoryId: this.form.controls.inventory.value?.id,
|
||||
supplierId: this.form.controls.supplier.value?.id,
|
||||
items: this.form.controls.products.value.map((item) => {
|
||||
const { product, description, ...res } = item;
|
||||
return { ...res, productId: item.product?.id };
|
||||
}),
|
||||
} as IPurchaseRequest;
|
||||
console.log(payload);
|
||||
this.form.disable();
|
||||
|
||||
this.service.create(payload).subscribe({
|
||||
next: (res) => {
|
||||
this.toastService.success({ text: 'ثبت سند خرید با موفقیت انجام شد' });
|
||||
this.form.enable();
|
||||
this.form.reset();
|
||||
this.formIsSubmitted.set(false);
|
||||
},
|
||||
error: () => {
|
||||
this.form.enable();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.form.markAllAsTouched();
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
import { PageDataListComponent } from '@/shared/components/pageDataList/page-data-list.component';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-product-charges',
|
||||
standalone: true,
|
||||
imports: [PageDataListComponent],
|
||||
templateUrl: './list.component.html',
|
||||
})
|
||||
export class ProductChargesComponent {}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<div class="">
|
||||
<uikit-field label="تامینکننده">
|
||||
<div class="w-full">
|
||||
<uikit-field label="تامینکننده" [control]="control" [showLabel]="showLabel" [showErrors]="showErrors">
|
||||
<p-select
|
||||
[options]="items()"
|
||||
optionLabel="fullname"
|
||||
optionValue="id"
|
||||
[optionValue]="selectOptionValue"
|
||||
placeholder="انتخاب تامینکننده"
|
||||
[formControl]="control"
|
||||
[showClear]="true"
|
||||
|
||||
@@ -1,29 +1,21 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { AbstractSelectComponent } from '@/shared/components';
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, Input, signal } from '@angular/core';
|
||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { Select } from 'primeng/select';
|
||||
import { Component } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { SelectModule } from 'primeng/select';
|
||||
import { ISupplierResponse } from '../../models';
|
||||
import { SuppliersService } from '../../services/main.service';
|
||||
|
||||
@Component({
|
||||
selector: 'suppliers-select-field',
|
||||
templateUrl: './select.component.html',
|
||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent],
|
||||
imports: [ReactiveFormsModule, SelectModule, UikitFieldComponent],
|
||||
})
|
||||
export class SuppliersSelectComponent {
|
||||
@Input() control!: FormControl<Maybe<number>>;
|
||||
@Input() canInsert: boolean = false;
|
||||
|
||||
export class SuppliersSelectComponent extends AbstractSelectComponent<ISupplierResponse> {
|
||||
constructor(private service: SuppliersService) {
|
||||
super();
|
||||
this.getData();
|
||||
}
|
||||
|
||||
loading = signal(false);
|
||||
items = signal<Maybe<ISupplierResponse[]>>(null);
|
||||
|
||||
isOpenFormDialog = signal(false);
|
||||
|
||||
getData() {
|
||||
this.loading.set(true);
|
||||
this.service.getAll().subscribe({
|
||||
@@ -36,12 +28,4 @@ export class SuppliersSelectComponent {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
onOpenForm() {
|
||||
// this.isOpenFormDialog.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { Component, Input, signal } from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
|
||||
export interface ISelectItem {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'abstract-select-field',
|
||||
template: '',
|
||||
})
|
||||
export abstract class AbstractSelectComponent<T = ISelectItem> {
|
||||
@Input() control!: FormControl<Maybe<number | T>>;
|
||||
@Input() canInsert: boolean = false;
|
||||
@Input() showLabel: boolean = true;
|
||||
@Input() showErrors: boolean = true;
|
||||
@Input() isFullDataOptionValue: boolean = false;
|
||||
@Input() optionValue = 'id';
|
||||
|
||||
loading = signal(false);
|
||||
items = signal<Maybe<T[]>>(null);
|
||||
isOpenFormDialog = signal(false);
|
||||
|
||||
abstract getData(): void;
|
||||
// abstract getLabel(): string;
|
||||
|
||||
refresh() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
onOpenForm() {
|
||||
// Override in subclass if needed
|
||||
}
|
||||
|
||||
get selectOptionValue() {
|
||||
if (!this.control) return undefined;
|
||||
if (this.isFullDataOptionValue) {
|
||||
return undefined;
|
||||
}
|
||||
return this.optionValue;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './abstract-select.component';
|
||||
export * from './breadcrumb.component';
|
||||
export * from './card-data.component';
|
||||
export * from './inlineConfirmation/inline-confirmation.component';
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<uikit-field [label]="label" [control]="control" class="w-full datepicker">
|
||||
<uikit-field
|
||||
[label]="label"
|
||||
[control]="control"
|
||||
[showLabel]="showLabel"
|
||||
[showErrors]="showErrors"
|
||||
class="w-full datepicker"
|
||||
>
|
||||
<div #wrapper [attr.data-disable]="disabled" [attr.data-name]="name" class="w-full">
|
||||
<input pInputText data-input [attr.placeholder]="placeholder" [name]="name" class="w-full" />
|
||||
</div>
|
||||
|
||||
@@ -28,6 +28,8 @@ export class UikitFlatpickrJalaliComponent implements OnInit {
|
||||
@Input() disabled = false;
|
||||
@Input() name: string = 'datepicker';
|
||||
@Input() options: Partial<BaseOptions> = {};
|
||||
@Input() showLabel: boolean = true;
|
||||
@Input() showErrors: boolean = true;
|
||||
|
||||
@Output() valueChange = new EventEmitter<string>();
|
||||
|
||||
|
||||
+28
-2
@@ -1,5 +1,5 @@
|
||||
@import 'tailwindcss';
|
||||
@import 'tailwindcss-primeui';
|
||||
@import "tailwindcss";
|
||||
@import "tailwindcss-primeui";
|
||||
@custom-variant dark (&:where(.app-dark, .app-dark *));
|
||||
|
||||
@theme {
|
||||
@@ -9,3 +9,29 @@
|
||||
--breakpoint-xl: 1200px;
|
||||
--breakpoint-2xl: 1920px;
|
||||
}
|
||||
|
||||
@theme {
|
||||
--color-primary-color: var(--primary-color);
|
||||
--color-primary-contrast-color: var(--primary-contrast-color);
|
||||
--color-text-color: var(--text-color);
|
||||
--color-text-color-secondary: var(--text-color-secondary);
|
||||
--color-surface-border: var(--surface-border);
|
||||
--color-surface-card: var(--surface-card);
|
||||
--color-surface-hover: var(--surface-hover);
|
||||
--color-surface-overlay: var(--surface-overlay);
|
||||
--color-transition-duration: var(--transition-duration);
|
||||
--color-maskbg: var(--maskbg);
|
||||
--color-content-border-radius: var(--content-border-radius);
|
||||
--layout-section-transition-duration: 0.2s;
|
||||
--color-element-transition-duration: var(--element-transition-duration);
|
||||
--color-focus-ring-width: var(--focus-ring-width);
|
||||
--color-focus-ring-style: var(--focus-ring-style);
|
||||
--color-focus-ring-color: var(--focus-ring-color);
|
||||
--color-focus-ring-offset: var(--focus-ring-offset);
|
||||
--color-focus-ring-shadow: var(--focus-ring-shadow);
|
||||
--color-surface-ground: var(--surface-ground);
|
||||
--color-code-background: var(--code-background);
|
||||
--color-code-color: var(--code-color);
|
||||
--color-error: var(--p-red-500);
|
||||
--p-inputtext-padding-y: 1rem !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user