diff --git a/src/app.routes.ts b/src/app.routes.ts index 78b19cb..56594eb 100644 --- a/src/app.routes.ts +++ b/src/app.routes.ts @@ -3,6 +3,7 @@ import { BANK_ACCOUNTS_ROUTES } from '@/modules/bankAccounts/constants'; import { BANK_BRANCHES_ROUTES } from '@/modules/bankBranches/constants'; import { CARDEX_ROUTES } from '@/modules/cardex/constants'; import { CUSTOMERS_ROUTES } from '@/modules/customers/constants'; +import { DASHBOARD_ROUTES } from '@/modules/dashboard/constants'; import { INVENTORIES_ROUTES } from '@/modules/inventories/constants'; import { POSComponent } from '@/modules/pos/views/pos.component'; import { PRODUCT_BRANDS_ROUTES } from '@/modules/productBrands/constants'; @@ -21,7 +22,8 @@ export const appRoutes: Routes = [ path: '', component: AppLayout, children: [ - { path: '', component: Dashboard }, + { path: 'ng', component: Dashboard }, + ...DASHBOARD_ROUTES, ...USERS_ROUTES, ...SUPPLIERS_ROUTES, ...PRODUCT_BRANDS_ROUTES, diff --git a/src/app/modules/bankAccounts/views/list.component.html b/src/app/modules/bankAccounts/views/list.component.html index 8014e55..a93a2fc 100644 --- a/src/app/modules/bankAccounts/views/list.component.html +++ b/src/app/modules/bankAccounts/views/list.component.html @@ -1,10 +1,10 @@ + diff --git a/src/app/modules/bankAccounts/views/single.component.ts b/src/app/modules/bankAccounts/views/single.component.ts index 689be65..aefa666 100644 --- a/src/app/modules/bankAccounts/views/single.component.ts +++ b/src/app/modules/bankAccounts/views/single.component.ts @@ -1,9 +1,48 @@ -import { Component } from '@angular/core'; +import { + IColumn, + PageDataListComponent, +} from '@/shared/components/pageDataList/page-data-list.component'; +import { Component, signal } from '@angular/core'; +import { IBankAccountsResponse } from '../models'; @Component({ selector: 'app-bank-account', templateUrl: './single.component.html', + imports: [PageDataListComponent], }) export class BankAccountComponent { constructor() {} + + columns = [ + { field: 'id', header: 'شناسه', width: '60px' }, + { + field: 'name', + header: 'نام', + minWidth: '100px', + }, + + { + field: 'accountNumber', + header: 'شماره حساب بانکی', + canCopy: true, + minWidth: '160px', + }, + { + field: 'iban', + header: 'شماره شبا', + canCopy: true, + minWidth: '200px', + }, + { + field: 'cardNumber', + header: 'شماره کارت بانکی', + canCopy: true, + minWidth: '160px', + }, + { field: 'createdAt', header: 'تاریخ ایجاد', type: 'date' }, + { field: 'updatedAt', header: 'تاریخ به‌روزرسانی', type: 'date' }, + ] as IColumn[]; + + loading = signal(false); + items = signal([]); } diff --git a/src/app/modules/cardex/components/templates/inventory.component.html b/src/app/modules/cardex/components/templates/inventory.component.html index 1e2b66f..20c1173 100644 --- a/src/app/modules/cardex/components/templates/inventory.component.html +++ b/src/app/modules/cardex/components/templates/inventory.component.html @@ -58,7 +58,7 @@ @if (item.type === "IN") { - + } @else { 0 } @@ -68,13 +68,13 @@ @if (item.type === "OUT") { - + } @else { 0 } {{ item.remainedInStock }} - diff --git a/src/app/modules/cardex/models/io.d.ts b/src/app/modules/cardex/models/io.d.ts index 47d0430..86293c2 100644 --- a/src/app/modules/cardex/models/io.d.ts +++ b/src/app/modules/cardex/models/io.d.ts @@ -4,7 +4,7 @@ export interface ICardexRawResponse { id: number; type: string; quantity: number; - fee: number; + unitPrice: number; totalCost: number; referenceType: string; referenceId: string; diff --git a/src/app/modules/dashboard/constants/apiRoutes/index.ts b/src/app/modules/dashboard/constants/apiRoutes/index.ts new file mode 100644 index 0000000..475439c --- /dev/null +++ b/src/app/modules/dashboard/constants/apiRoutes/index.ts @@ -0,0 +1,8 @@ +const baseUrl = '/api/v1/pos'; + +export const POS_API_ROUTES = { + info: (posId: number) => `${baseUrl}/${posId}`, + stock: (posId: number) => `${baseUrl}/${posId}/stock`, + productCategories: (posId: number) => `${baseUrl}/${posId}/product-categories`, + submitOrder: (posId: number) => `${baseUrl}/${posId}/orders/create`, +}; diff --git a/src/app/modules/dashboard/constants/index.ts b/src/app/modules/dashboard/constants/index.ts new file mode 100644 index 0000000..ee61bd7 --- /dev/null +++ b/src/app/modules/dashboard/constants/index.ts @@ -0,0 +1,2 @@ +export * from './apiRoutes'; +export * from './routes'; diff --git a/src/app/modules/dashboard/constants/routes/index.ts b/src/app/modules/dashboard/constants/routes/index.ts new file mode 100644 index 0000000..8e1708a --- /dev/null +++ b/src/app/modules/dashboard/constants/routes/index.ts @@ -0,0 +1,18 @@ +import { NamedRoutes } from '@/core'; +import { Routes } from '@angular/router'; + +export const dashboardNamedRoutes: NamedRoutes = { + POS: { + path: '', + loadComponent: () => + import('../../views/dashboard.component').then((m) => m.DashboardComponent), + meta: { + title: 'داشبورد', + pagePath: () => ``, + }, + }, +}; + +export type TDashboardRouteNames = keyof typeof dashboardNamedRoutes; + +export const DASHBOARD_ROUTES: Routes = Object.values(dashboardNamedRoutes); diff --git a/src/app/modules/dashboard/views/dashboard.component.html b/src/app/modules/dashboard/views/dashboard.component.html new file mode 100644 index 0000000..dca4e49 --- /dev/null +++ b/src/app/modules/dashboard/views/dashboard.component.html @@ -0,0 +1,7 @@ +
+
+ + + +
+
diff --git a/src/app/modules/dashboard/views/dashboard.component.ts b/src/app/modules/dashboard/views/dashboard.component.ts new file mode 100644 index 0000000..99642ec --- /dev/null +++ b/src/app/modules/dashboard/views/dashboard.component.ts @@ -0,0 +1,36 @@ +import { StatisticsSharedTopAlertStocksComponent } from '@/modules/statistics/shared/components/top-alert-stocks.component'; +import { StatisticsSharedTopSalesComponent } from '@/modules/statistics/shared/components/top-sales.component'; +import { StatisticsSharedTopSupplierDebtsComponent } from '@/modules/statistics/shared/components/top-supplier-debts.component'; +import { Component } from '@angular/core'; +import images from 'src/assets/images'; + +@Component({ + selector: 'app-dashboard', + templateUrl: './dashboard.component.html', + imports: [ + StatisticsSharedTopAlertStocksComponent, + StatisticsSharedTopSalesComponent, + StatisticsSharedTopSupplierDebtsComponent, + ], +}) +export class DashboardComponent { + placeholderLogo = images.placeholders.logo; + + now = new Date(); + + // info = this.store.info; + // infoLoading = this.store.getInfoLoading; + + // getInfo() { + // this.infoLoading.set(true); + // this.service.getInfo(Number(this.posId)).subscribe({ + // next: (res) => { + // this.info.set(res); + // this.infoLoading.set(false); + // }, + // error: () => { + // this.infoLoading.set(false); + // }, + // }); + // } +} diff --git a/src/app/modules/inventories/components/movementList/movement-list.component.html b/src/app/modules/inventories/components/movementList/movement-list.component.html index ab812c9..894a32a 100644 --- a/src/app/modules/inventories/components/movementList/movement-list.component.html +++ b/src/app/modules/inventories/components/movementList/movement-list.component.html @@ -74,10 +74,10 @@ - +
قیمت واحد - +
@@ -94,7 +94,7 @@ {{ movement.product.id }} {{ movement.product.name }} {{ movement.quantity }} - + diff --git a/src/app/modules/inventories/components/select/select.component.html b/src/app/modules/inventories/components/select/select.component.html index 17849a5..bf256d5 100644 --- a/src/app/modules/inventories/components/select/select.component.html +++ b/src/app/modules/inventories/components/select/select.component.html @@ -5,7 +5,7 @@ [optionValue]="selectOptionValue" placeholder="انتخاب انبار" [formControl]="control" - [showClear]="true" + [showClear]="showClear" [filter]="true" appendTo="body" (onChange)="change($event.value)" diff --git a/src/app/modules/inventories/models/types.ts b/src/app/modules/inventories/models/types.ts index 8e2f3e3..1288a73 100644 --- a/src/app/modules/inventories/models/types.ts +++ b/src/app/modules/inventories/models/types.ts @@ -3,7 +3,7 @@ import { IProductRawResponse } from '@/modules/products/models'; export interface IInventoryMovement { id: number; quantity: number; - fee: number; + unitPrice: number; totalCost: number; avgCost: number; product: IInventoryProduct; @@ -27,7 +27,7 @@ export interface IInventoryInfo { date: string; type: string; quantity: number; - fee: number; + unitPrice: number; totalCost: number; referenceType: string; referenceId: string; diff --git a/src/app/modules/inventories/views/products.component.html b/src/app/modules/inventories/views/products.component.html index 1c357d8..dc3da19 100644 --- a/src/app/modules/inventories/views/products.component.html +++ b/src/app/modules/inventories/views/products.component.html @@ -26,10 +26,10 @@ - +
قیمت متوسط - +
diff --git a/src/app/modules/inventories/views/single.component.html b/src/app/modules/inventories/views/single.component.html index 30f6895..fb19f79 100644 --- a/src/app/modules/inventories/views/single.component.html +++ b/src/app/modules/inventories/views/single.component.html @@ -80,10 +80,10 @@ - +
قیمت متوسط - +
diff --git a/src/app/modules/pos/components/order/order-card.component.html b/src/app/modules/pos/components/order/order-card.component.html index 92491cd..9ba6f10 100644 --- a/src/app/modules/pos/components/order/order-card.component.html +++ b/src/app/modules/pos/components/order/order-card.component.html @@ -48,16 +48,17 @@
- + diff --git a/src/app/modules/pos/components/order/order-card.component.ts b/src/app/modules/pos/components/order/order-card.component.ts index e7908ad..c4e62ee 100644 --- a/src/app/modules/pos/components/order/order-card.component.ts +++ b/src/app/modules/pos/components/order/order-card.component.ts @@ -46,11 +46,11 @@ export class PosOrderCardComponent { } updateInOrderProductFee(productId: number, $event: Event, prevFee: number) { - const fee = $event.target + const unitPrice = $event.target ? parseFloat(($event.target as HTMLInputElement).ariaValueNow || prevFee.toString()) : prevFee; - this.store.updateInOrderProductFee(productId, fee); + this.store.updateInOrderProductFee(productId, unitPrice); } clearOrderList() { diff --git a/src/app/modules/pos/models/types.ts b/src/app/modules/pos/models/types.ts index c0abc75..580ab92 100644 --- a/src/app/modules/pos/models/types.ts +++ b/src/app/modules/pos/models/types.ts @@ -16,7 +16,7 @@ interface ICategorySummary { export interface IPosOrderItem { productId: number; count: number; - fee: number; + unitPrice: number; } export interface IPosInOrderProduct extends IPosOrderItem { diff --git a/src/app/modules/pos/store/index.ts b/src/app/modules/pos/store/index.ts index 72b6a94..140a37a 100644 --- a/src/app/modules/pos/store/index.ts +++ b/src/app/modules/pos/store/index.ts @@ -72,7 +72,7 @@ export class POSStore { readonly orderPricingInfo = computed(() => { const totalAmount = this.inOrderProducts().reduce( - (acc, curr) => acc + curr.fee * curr.count, + (acc, curr) => acc + curr.unitPrice * curr.count, 0, ); const taxAmount = totalAmount * 0.1; @@ -188,7 +188,7 @@ export class POSStore { product, productId: product.id, count: 1, - fee: parseFloat(product.salePrice), + unitPrice: parseFloat(product.salePrice), maxQuantity: productStock.quantity, }, ], @@ -220,13 +220,13 @@ export class POSStore { } } - updateInOrderProductFee(productId: number, fee: number) { + updateInOrderProductFee(productId: number, unitPrice: number) { const inOrderProducts = this.state$().inOrderProducts; if (inOrderProducts.some((p) => p.productId === productId)) { const updatedProducts = inOrderProducts.map((p) => { if (p.productId === productId) { - return { ...p, fee: fee }; + return { ...p, unitPrice: unitPrice }; } return p; }); @@ -255,7 +255,7 @@ export class POSStore { items: this.inOrderProducts()?.map((item) => ({ productId: item.productId, count: item.count, - fee: item.fee, + unitPrice: item.unitPrice, })), }; this.service.submitOrder(this.posId, orderPayload).subscribe(); diff --git a/src/app/modules/productCharges/components/form.component.html b/src/app/modules/productCharges/components/form.component.html index ea60015..0a77ab2 100644 --- a/src/app/modules/productCharges/components/form.component.html +++ b/src/app/modules/productCharges/components/form.component.html @@ -8,7 +8,7 @@ - + diff --git a/src/app/modules/productCharges/components/form.component.ts b/src/app/modules/productCharges/components/form.component.ts index 208b71d..81bca94 100644 --- a/src/app/modules/productCharges/components/form.component.ts +++ b/src/app/modules/productCharges/components/form.component.ts @@ -34,7 +34,7 @@ export class ProductChargeFormComponent { form = this.fb.group({ count: [0, [Validators.required, Validators.min(1)]], - fee: [0, [Validators.required, Validators.min(0)]], + unitPrice: [0, [Validators.required, Validators.min(0)]], totalAmount: [0, [Validators.required, Validators.min(0)]], isSettled: [false], buyAt: ['', Validators.required], diff --git a/src/app/modules/productCharges/models/io.d.ts b/src/app/modules/productCharges/models/io.d.ts index 5792a56..73b21c3 100644 --- a/src/app/modules/productCharges/models/io.d.ts +++ b/src/app/modules/productCharges/models/io.d.ts @@ -2,7 +2,7 @@ export interface IProductChargeRaw { id: number; name: string; count: number; - fee: number; + unitPrice: number; totalAmount: number; isSettled?: boolean; buyAt: string; @@ -20,7 +20,7 @@ export interface IProductChargeResponse extends IProductChargeRaw {} export interface IProductChargeRequest { name: string; count: number; - fee: number; + unitPrice: number; totalAmount: number; isSettled?: boolean; buyAt: string; diff --git a/src/app/modules/productCharges/views/list.component.ts b/src/app/modules/productCharges/views/list.component.ts index 62988db..a5485b7 100644 --- a/src/app/modules/productCharges/views/list.component.ts +++ b/src/app/modules/productCharges/views/list.component.ts @@ -24,7 +24,7 @@ export class ProductChargesComponent { { field: 'id', header: 'شناسه' }, { field: 'name', header: 'نام' }, { field: 'count', header: 'تعداد' }, - { field: 'fee', header: 'هزینه' }, + { field: 'unitPrice', header: 'هزینه' }, { field: 'totalAmount', header: 'مبلغ کل' }, { field: 'isSettled', header: 'تسویه شده' }, { field: 'buyAt', header: 'تاریخ خرید' }, diff --git a/src/app/modules/purchases/components/form.component.ts b/src/app/modules/purchases/components/form.component.ts index 2b832d4..a7ea84c 100644 --- a/src/app/modules/purchases/components/form.component.ts +++ b/src/app/modules/purchases/components/form.component.ts @@ -48,7 +48,7 @@ export class PurchaseFormComponent { this.fb.group({ productId: [this.product?.id || 0, [Validators.required]], count: [0, [Validators.required, Validators.min(1)]], - fee: [0, [Validators.required, Validators.min(0)]], + unitPrice: [0, [Validators.required, Validators.min(0)]], }), ]), inventoryId: [this.inventory?.id || 0, [Validators.required]], diff --git a/src/app/modules/purchases/components/product-charge-row-form-fields.component.html b/src/app/modules/purchases/components/product-charge-row-form-fields.component.html index f449649..79108f5 100644 --- a/src/app/modules/purchases/components/product-charge-row-form-fields.component.html +++ b/src/app/modules/purchases/components/product-charge-row-form-fields.component.html @@ -2,6 +2,6 @@
- +
diff --git a/src/app/modules/purchases/components/product-charge-row-form.component.html b/src/app/modules/purchases/components/product-charge-row-form.component.html index c3b6821..2a0f9d0 100644 --- a/src/app/modules/purchases/components/product-charge-row-form.component.html +++ b/src/app/modules/purchases/components/product-charge-row-form.component.html @@ -6,7 +6,7 @@ diff --git a/src/app/modules/purchases/components/product-charge-row-form.component.ts b/src/app/modules/purchases/components/product-charge-row-form.component.ts index 9f74b34..f92381c 100644 --- a/src/app/modules/purchases/components/product-charge-row-form.component.ts +++ b/src/app/modules/purchases/components/product-charge-row-form.component.ts @@ -25,7 +25,7 @@ export class ProductChargeRowFormComponent implements OnInit { FormGroup<{ productId: FormControl>; count: FormControl>; - fee: FormControl>; + unitPrice: FormControl>; }> >; @Input() isSingleProduct = false; @@ -43,7 +43,7 @@ export class ProductChargeRowFormComponent implements OnInit { const productFormGroup = this.fb.group({ productId: [0, [Validators.required]], count: [1, [Validators.required, Validators.min(1)]], - fee: [0, [Validators.required, Validators.min(0)]], + unitPrice: [0, [Validators.required, Validators.min(0)]], }); this.productsControl.push(productFormGroup); } diff --git a/src/app/modules/purchases/components/receiptTemplate/purchase-receipt-product-row.component.html b/src/app/modules/purchases/components/receiptTemplate/purchase-receipt-product-row.component.html index 8783bd2..4b1dd45 100644 --- a/src/app/modules/purchases/components/receiptTemplate/purchase-receipt-product-row.component.html +++ b/src/app/modules/purchases/components/receiptTemplate/purchase-receipt-product-row.component.html @@ -28,27 +28,27 @@ [autoResize]="false" > - + - + } @else { {{ purchaseItemControl.controls.product.value?.sku || "" }} {{ purchaseItemControl.controls.product.value?.name || "" }} {{ purchaseItemControl.controls.description.value || "" }} - + {{ purchaseItemControl.controls.count.value }} - + } diff --git a/src/app/modules/purchases/components/receiptTemplate/purchase-receipt-product-row.component.ts b/src/app/modules/purchases/components/receiptTemplate/purchase-receipt-product-row.component.ts index dc2ec7c..e633475 100644 --- a/src/app/modules/purchases/components/receiptTemplate/purchase-receipt-product-row.component.ts +++ b/src/app/modules/purchases/components/receiptTemplate/purchase-receipt-product-row.component.ts @@ -34,12 +34,12 @@ export class PurchaseReceiptProductRowComponent { ngOnInit() { this.purchaseItemControl?.controls.product.valueChanges.subscribe((res) => { - this.purchaseItemControl?.controls.fee.setValue(Number(res?.salePrice) || 0); + this.purchaseItemControl?.controls.unitPrice.setValue(Number(res?.salePrice) || 0); }); this.purchaseItemControl?.controls.count.valueChanges.subscribe(() => { this.updateTotal(); }); - this.purchaseItemControl?.controls.fee.valueChanges.subscribe(() => { + this.purchaseItemControl?.controls.unitPrice.valueChanges.subscribe(() => { this.updateTotal(); }); } @@ -47,7 +47,7 @@ export class PurchaseReceiptProductRowComponent { updateTotal() { this.purchaseItemControl.controls.total.setValue( (this.purchaseItemControl.controls.count.value || 0) * - (this.purchaseItemControl.controls.fee.value || 0), + (this.purchaseItemControl.controls.unitPrice.value || 0), ); } diff --git a/src/app/modules/purchases/components/receiptTemplate/purchase-receipt-template.component.html b/src/app/modules/purchases/components/receiptTemplate/purchase-receipt-template.component.html index 9ba1d18..4eeb9a2 100644 --- a/src/app/modules/purchases/components/receiptTemplate/purchase-receipt-template.component.html +++ b/src/app/modules/purchases/components/receiptTemplate/purchase-receipt-template.component.html @@ -9,38 +9,47 @@ انبار: - - - {{ form.controls.inventory.value?.name || "وارد نشده" }} + + +
+ {{ form.controls.inventory.value?.name || "وارد نشده" }} + @if (!inventory) { + + } +
- + -
+
تامین کننده: - - - {{ form.controls.supplier.value?.fullname || "وارد نشده" }} + + +
+ {{ form.controls.supplier.value?.fullname || "وارد نشده" }} + +
- - + -
+
@@ -49,27 +58,33 @@ شماره رسید: - - - {{ form.controls.code.value || "وارد نشده" }} + + +
+ {{ form.controls.code.value || "وارد نشده" }} + +
- - + + -
+
تاریخ خرید: - - - {{ form.controls.buyAt.value || "وارد نشده" }} + + +
+ {{ form.controls.buyAt.value || "وارد نشده" }} + +
- + -
+
@@ -116,7 +131,7 @@ } @else if (col.field === "total") { - {{ product["fee"] * product["count"] || 0 }} + {{ product["unitPrice"] * product["count"] || 0 }} } @else if (col.field === "action") {
@@ -130,7 +145,7 @@ - +
+
+ +
+
diff --git a/src/app/modules/statistics/shared/components/card.component.ts b/src/app/modules/statistics/shared/components/card.component.ts new file mode 100644 index 0000000..888b762 --- /dev/null +++ b/src/app/modules/statistics/shared/components/card.component.ts @@ -0,0 +1,17 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { ButtonDirective } from 'primeng/button'; + +@Component({ + selector: 'app-statistics-shared-card', + templateUrl: './card.component.html', + imports: [ButtonDirective], + host: { + class: 'block h-full overflow-auto', + }, +}) +export class StatisticsSharedCardComponent { + @Input() title!: string; + @Input() loading: boolean = false; + @Output() onRefresh = new EventEmitter(); + constructor() {} +} diff --git a/src/app/modules/statistics/shared/components/index.ts b/src/app/modules/statistics/shared/components/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/app/modules/statistics/shared/components/top-alert-stocks.component.html b/src/app/modules/statistics/shared/components/top-alert-stocks.component.html new file mode 100644 index 0000000..43ec5f9 --- /dev/null +++ b/src/app/modules/statistics/shared/components/top-alert-stocks.component.html @@ -0,0 +1,12 @@ + + + + + + + diff --git a/src/app/modules/statistics/shared/components/top-alert-stocks.component.ts b/src/app/modules/statistics/shared/components/top-alert-stocks.component.ts new file mode 100644 index 0000000..d071cea --- /dev/null +++ b/src/app/modules/statistics/shared/components/top-alert-stocks.component.ts @@ -0,0 +1,66 @@ +import { + IColumn, + PageDataListComponent, +} from '@/shared/components/pageDataList/page-data-list.component'; +import { Component, signal, TemplateRef, ViewChild } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { ButtonDirective } from 'primeng/button'; +import { IStatisticsTopAlertStockResponse } from '../models/io'; +import { SharedStatisticsService } from '../services/main.service'; +import { StatisticsSharedCardComponent } from './card.component'; + +@Component({ + selector: 'app-statistics-shared-top-alert-stocks', + templateUrl: './top-alert-stocks.component.html', + imports: [StatisticsSharedCardComponent, PageDataListComponent, ButtonDirective, RouterLink], +}) +export class StatisticsSharedTopAlertStocksComponent { + items = signal([]); + loading = signal(false); + column = [] as IColumn[]; + @ViewChild('actionTpl', { static: true }) actionTpl!: TemplateRef; + + constructor(private readonly service: SharedStatisticsService) { + this.getData(); + } + + ngOnInit() { + this.column = [ + { field: 'sku', header: 'شناسه' }, + { field: 'name', header: 'عنوان' }, + { + field: 'brand', + header: 'برند', + type: 'nested', + nestedPath: 'name', + }, + + { + field: 'stock', + header: 'موجودی ', + }, + { field: 'minimumStockAlertLevel', header: 'حد هشدار' }, + { + field: 'chargeAction', + header: '', + customDataModel: this.actionTpl, + width: '40px', + }, + ]; + } + + getData() { + this.loading.set(true); + this.service.getTopAlertStock().subscribe({ + next: (res) => { + this.items.set(res.data); + this.loading.set(false); + }, + error: () => { + this.loading.set(false); + }, + }); + } + + toPurchase(item: IStatisticsTopAlertStockResponse) {} +} diff --git a/src/app/modules/statistics/shared/components/top-sales.component.html b/src/app/modules/statistics/shared/components/top-sales.component.html new file mode 100644 index 0000000..0126a97 --- /dev/null +++ b/src/app/modules/statistics/shared/components/top-sales.component.html @@ -0,0 +1,9 @@ + + + + diff --git a/src/app/modules/statistics/shared/components/top-sales.component.ts b/src/app/modules/statistics/shared/components/top-sales.component.ts new file mode 100644 index 0000000..d798d7a --- /dev/null +++ b/src/app/modules/statistics/shared/components/top-sales.component.ts @@ -0,0 +1,52 @@ +import { + IColumn, + PageDataListComponent, +} from '@/shared/components/pageDataList/page-data-list.component'; +import { Component, signal, TemplateRef, ViewChild } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { ButtonDirective } from 'primeng/button'; +import { IStatisticsTopSalesResponse } from '../models/io'; +import { SharedStatisticsService } from '../services/main.service'; +import { StatisticsSharedCardComponent } from './card.component'; + +@Component({ + selector: 'app-statistics-shared-top-sales', + templateUrl: './top-sales.component.html', + imports: [StatisticsSharedCardComponent, PageDataListComponent, ButtonDirective, RouterLink], +}) +export class StatisticsSharedTopSalesComponent { + items = signal([]); + loading = signal(false); + column = [] as IColumn[]; + @ViewChild('actionTpl', { static: true }) actionTpl!: TemplateRef; + + constructor(private readonly service: SharedStatisticsService) { + this.getData(); + } + + ngOnInit() { + this.column = [ + { field: 'sku', header: 'شناسه' }, + { field: 'name', header: 'عنوان' }, + { + field: 'brand', + header: 'برند', + type: 'nested', + nestedPath: 'name', + }, + ]; + } + + getData() { + this.loading.set(true); + this.service.getTopSales().subscribe({ + next: (res) => { + this.items.set(res.data); + this.loading.set(false); + }, + error: () => { + this.loading.set(false); + }, + }); + } +} diff --git a/src/app/modules/statistics/shared/components/top-supplier-debts.component.html b/src/app/modules/statistics/shared/components/top-supplier-debts.component.html new file mode 100644 index 0000000..87c7812 --- /dev/null +++ b/src/app/modules/statistics/shared/components/top-supplier-debts.component.html @@ -0,0 +1,9 @@ + + + + diff --git a/src/app/modules/statistics/shared/components/top-supplier-debts.component.ts b/src/app/modules/statistics/shared/components/top-supplier-debts.component.ts new file mode 100644 index 0000000..0f54afd --- /dev/null +++ b/src/app/modules/statistics/shared/components/top-supplier-debts.component.ts @@ -0,0 +1,52 @@ +import { + IColumn, + PageDataListComponent, +} from '@/shared/components/pageDataList/page-data-list.component'; +import { Component, signal, TemplateRef, ViewChild } from '@angular/core'; +import { IStatisticsTopSupplierDebtsResponse } from '../models/io'; +import { SharedStatisticsService } from '../services/main.service'; +import { StatisticsSharedCardComponent } from './card.component'; + +@Component({ + selector: 'app-statistics-shared-top-supplier-debts', + templateUrl: './top-supplier-debts.component.html', + imports: [StatisticsSharedCardComponent, PageDataListComponent], +}) +export class StatisticsSharedTopSupplierDebtsComponent { + items = signal([]); + loading = signal(false); + column = [] as IColumn[]; + @ViewChild('actionTpl', { static: true }) actionTpl!: TemplateRef; + + constructor(private readonly service: SharedStatisticsService) { + this.getData(); + } + + ngOnInit() { + this.column = [ + { field: 'name', header: 'عنوان' }, + { + field: 'totalDebt', + header: 'بدهی کل', + type: 'price', + }, + { + field: 'unpaidReceipts', + header: 'فاکتورهای تسویه‌نشده', + }, + ]; + } + + getData() { + this.loading.set(true); + this.service.getTopSupplierDebts().subscribe({ + next: (res) => { + this.items.set(res.data); + this.loading.set(false); + }, + error: () => { + this.loading.set(false); + }, + }); + } +} diff --git a/src/app/modules/statistics/shared/constants/apiRoutes/index.ts b/src/app/modules/statistics/shared/constants/apiRoutes/index.ts new file mode 100644 index 0000000..c81be92 --- /dev/null +++ b/src/app/modules/statistics/shared/constants/apiRoutes/index.ts @@ -0,0 +1,8 @@ +const baseUrl = '/api/v1/statistics'; + +export const SHARED_STATISTICS_API_ROUTES = { + topAlertStock: `${baseUrl}/top-alert-stocks`, + topSales: `${baseUrl}/top-sales`, + topSupplierDebts: `${baseUrl}/top-supplier-debts`, + topSellProducts: `${baseUrl}/top-sell-products`, +}; diff --git a/src/app/modules/statistics/shared/constants/index.ts b/src/app/modules/statistics/shared/constants/index.ts new file mode 100644 index 0000000..b853783 --- /dev/null +++ b/src/app/modules/statistics/shared/constants/index.ts @@ -0,0 +1 @@ +export * from './apiRoutes'; diff --git a/src/app/modules/statistics/shared/index.ts b/src/app/modules/statistics/shared/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/app/modules/statistics/shared/models/index.ts b/src/app/modules/statistics/shared/models/index.ts new file mode 100644 index 0000000..61a518a --- /dev/null +++ b/src/app/modules/statistics/shared/models/index.ts @@ -0,0 +1 @@ +export * from './io'; diff --git a/src/app/modules/statistics/shared/models/io.ts b/src/app/modules/statistics/shared/models/io.ts new file mode 100644 index 0000000..316e8e3 --- /dev/null +++ b/src/app/modules/statistics/shared/models/io.ts @@ -0,0 +1,27 @@ +import ISummary from '@/core/models/summary'; + +export interface IStatisticsTopAlertStockRawResponse { + id: number; + name: string; + sku: string; + minimumStockAlertLevel: string; + stockBalances: any[]; + category: ISummary; + brand: ISummary; + deficit: number; +} +export interface IStatisticsTopAlertStockResponse extends IStatisticsTopAlertStockRawResponse {} + +export interface IStatisticsTopSalesRawResponse {} +export interface IStatisticsTopSalesResponse extends IStatisticsTopSalesRawResponse {} + +export interface IStatisticsTopSupplierDebtsRawResponse { + id: number; + name: string; + totalDebt: number; + unpaidReceipts: number; +} +export interface IStatisticsTopSupplierDebtsResponse extends IStatisticsTopSupplierDebtsRawResponse {} + +export interface IStatisticsTopSellProductsRawResponse {} +export interface IStatisticsTopSellProductsResponse extends IStatisticsTopSellProductsRawResponse {} diff --git a/src/app/modules/statistics/shared/services/main.service.ts b/src/app/modules/statistics/shared/services/main.service.ts new file mode 100644 index 0000000..acb2858 --- /dev/null +++ b/src/app/modules/statistics/shared/services/main.service.ts @@ -0,0 +1,46 @@ +import { IPaginatedResponse } from '@/core/models/service.model'; +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { SHARED_STATISTICS_API_ROUTES } from '../constants'; +import { + IStatisticsTopAlertStockRawResponse, + IStatisticsTopAlertStockResponse, + IStatisticsTopSalesRawResponse, + IStatisticsTopSalesResponse, + IStatisticsTopSellProductsRawResponse, + IStatisticsTopSellProductsResponse, + IStatisticsTopSupplierDebtsRawResponse, + IStatisticsTopSupplierDebtsResponse, +} from '../models'; + +@Injectable({ providedIn: 'root' }) +export class SharedStatisticsService { + constructor(private http: HttpClient) {} + + private apiRoutes = SHARED_STATISTICS_API_ROUTES; + + getTopAlertStock(): Observable> { + return this.http.get>( + `${this.apiRoutes.topAlertStock}`, + ); + } + + getTopSales(): Observable> { + return this.http.get>( + `${this.apiRoutes.topSales}`, + ); + } + + getTopSupplierDebts(): Observable> { + return this.http.get>( + `${this.apiRoutes.topSupplierDebts}`, + ); + } + + getTopSellProducts(): Observable> { + return this.http.get>( + `${this.apiRoutes.topSellProducts}`, + ); + } +} diff --git a/src/app/modules/suppliers/components/invoices/invoices.component.html b/src/app/modules/suppliers/components/invoices/invoices.component.html index 2389283..97673ed 100644 --- a/src/app/modules/suppliers/components/invoices/invoices.component.html +++ b/src/app/modules/suppliers/components/invoices/invoices.component.html @@ -85,10 +85,10 @@ - +
قیمت واحد - +
@@ -105,7 +105,7 @@ {{ item.product.id }} {{ item.product.name }} {{ item.count }} - + diff --git a/src/app/modules/suppliers/components/select/select.component.html b/src/app/modules/suppliers/components/select/select.component.html index 9ac3c8c..002d9e6 100644 --- a/src/app/modules/suppliers/components/select/select.component.html +++ b/src/app/modules/suppliers/components/select/select.component.html @@ -6,7 +6,7 @@ [optionValue]="selectOptionValue" placeholder="انتخاب تامین‌کننده" [formControl]="control" - [showClear]="true" + [showClear]="showClear" [filter]="true" appendTo="body" > diff --git a/src/app/modules/suppliers/models/types.ts b/src/app/modules/suppliers/models/types.ts index 70383e9..c6bc532 100644 --- a/src/app/modules/suppliers/models/types.ts +++ b/src/app/modules/suppliers/models/types.ts @@ -13,7 +13,7 @@ export interface ISupplierInventorySummary { export interface ISupplierReceiptItemSummary { id: number; count: string; - fee: string; + unitPrice: string; total: string; product: { id: string; diff --git a/src/app/shared/components/cardex/cardex.component.html b/src/app/shared/components/cardex/cardex.component.html index 3711044..a35bd30 100644 --- a/src/app/shared/components/cardex/cardex.component.html +++ b/src/app/shared/components/cardex/cardex.component.html @@ -44,7 +44,7 @@ @if (item.type === "IN") { - + } @else { 0 } @@ -54,13 +54,13 @@ @if (item.type === "OUT") { - + } @else { 0 } {{ item.remainedInStock }} - diff --git a/src/app/shared/components/input/input.component.html b/src/app/shared/components/input/input.component.html index 7777c61..4a01988 100644 --- a/src/app/shared/components/input/input.component.html +++ b/src/app/shared/components/input/input.component.html @@ -16,6 +16,7 @@ [required]="isRequired" [invalid]="control.invalid && (control.touched || control.dirty)" (input)="onInput($event)" + (onBlur)="blur.emit()" /> ریال @@ -34,6 +35,7 @@ [required]="isRequired" [invalid]="control.invalid && (control.touched || control.dirty)" (input)="onInput($event)" + (onBlur)="blur.emit()" /> } @if (hint) { diff --git a/src/app/shared/components/input/input.component.ts b/src/app/shared/components/input/input.component.ts index e3d4de9..f19ac29 100644 --- a/src/app/shared/components/input/input.component.ts +++ b/src/app/shared/components/input/input.component.ts @@ -45,6 +45,7 @@ export class InputComponent { @Input() showErrors = false; @Input() hint?: string; @Output() valueChange = new EventEmitter(); + @Output() blur = new EventEmitter(); onInput(ev: Event) { const v = (ev.target as HTMLInputElement).value; diff --git a/src/app/shared/components/purchaseReceiptPayment/wrapper.component.html b/src/app/shared/components/purchaseReceiptPayment/wrapper.component.html index 8ad7a06..92260b4 100644 --- a/src/app/shared/components/purchaseReceiptPayment/wrapper.component.html +++ b/src/app/shared/components/purchaseReceiptPayment/wrapper.component.html @@ -5,5 +5,6 @@ [supplierId]="purchaseReceipt.supplierId.toString()" [inventoryId]="purchaseReceipt.inventoryId.toString()" [invoiceId]="purchaseReceipt.id.toString()" + (onSubmit)="submitted()" /> } diff --git a/src/app/shared/components/purchaseReceiptPayment/wrapper.component.ts b/src/app/shared/components/purchaseReceiptPayment/wrapper.component.ts index 4aa451e..02a0fb2 100644 --- a/src/app/shared/components/purchaseReceiptPayment/wrapper.component.ts +++ b/src/app/shared/components/purchaseReceiptPayment/wrapper.component.ts @@ -1,6 +1,6 @@ import { ToastService } from '@/core/services/toast.service'; import { SupplierInvoicePayFormComponent } from '@/modules/suppliers/components/invoices/pay-form.component'; -import { Component, Input, signal } from '@angular/core'; +import { Component, EventEmitter, Input, Output, signal } from '@angular/core'; import { IPurchaseReceiptResponse } from '../../../modules/purchases/models'; import { ConfirmationDialogService } from '../confirmationDialog/confirmation-dialog.service'; @@ -12,6 +12,8 @@ import { ConfirmationDialogService } from '../confirmationDialog/confirmation-di export class PurchaseReceiptPaymentWrapperComponent { @Input() purchaseReceipt!: IPurchaseReceiptResponse; + @Output() onSubmit = new EventEmitter(); + showPaymentForm = signal(false); constructor( private confirmService: ConfirmationDialogService, @@ -40,7 +42,12 @@ export class PurchaseReceiptPaymentWrapperComponent { }); } - submit() {} + submitted() { + console.log('submitted'); + + this.showPaymentForm.set(false); + this.onSubmit.emit(); + } toPaymentForm() { this.showPaymentForm.set(true);