Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5ee03cf761 | |||
| 72954fb5d1 | |||
| b4cd4c05f2 |
@@ -1,3 +1,4 @@
|
|||||||
|
import { NavigationService } from '@/core/services/navigation.service';
|
||||||
import { PwaInstallService } from '@/core/services/pwa-install.service';
|
import { PwaInstallService } from '@/core/services/pwa-install.service';
|
||||||
import { ConfirmationDialogComponent } from '@/shared/components/confirmationDialog/confirmation-dialog.component';
|
import { ConfirmationDialogComponent } from '@/shared/components/confirmationDialog/confirmation-dialog.component';
|
||||||
import { Component, HostListener } from '@angular/core';
|
import { Component, HostListener } from '@angular/core';
|
||||||
@@ -18,7 +19,10 @@ import { brandingConfig } from './app/branding/branding.config';
|
|||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
toastPosition: 'top-center' | 'bottom-right' = 'bottom-right';
|
toastPosition: 'top-center' | 'bottom-right' = 'bottom-right';
|
||||||
|
|
||||||
constructor(private readonly pwaInstallService: PwaInstallService) {
|
constructor(
|
||||||
|
private readonly pwaInstallService: PwaInstallService,
|
||||||
|
private readonly navigationService: NavigationService
|
||||||
|
) {
|
||||||
this.updateToastPosition();
|
this.updateToastPosition();
|
||||||
if (brandingConfig.enableInstallPrompt) {
|
if (brandingConfig.enableInstallPrompt) {
|
||||||
this.pwaInstallService.init();
|
this.pwaInstallService.init();
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ export class NativeBridgeService {
|
|||||||
this.toastService.info({ text: 'در حال چاپ ...' });
|
this.toastService.info({ text: 'در حال چاپ ...' });
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
window.NativeBridge.print(JSON.stringify(payload));
|
window.NativeBridge.print(JSON.stringify(payload));
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.toastService.warn({ text: 'متاسفانه ارتباط با چاپگر برقرار نیست.' });
|
this.toastService.warn({ text: 'متاسفانه ارتباط با چاپگر برقرار نیست.' });
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { NavigationEnd, Router } from '@angular/router';
|
||||||
|
import { filter } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class NavigationService {
|
||||||
|
private readonly CURRENT_URL_KEY = 'currentUrl';
|
||||||
|
private readonly PREVIOUS_URL_KEY = 'previousUrl';
|
||||||
|
|
||||||
|
currentUrl: string | null;
|
||||||
|
previousUrl: string | null;
|
||||||
|
|
||||||
|
constructor(private router: Router) {
|
||||||
|
this.currentUrl = sessionStorage.getItem(this.CURRENT_URL_KEY);
|
||||||
|
this.previousUrl = sessionStorage.getItem(this.PREVIOUS_URL_KEY);
|
||||||
|
|
||||||
|
this.router.events
|
||||||
|
.pipe(filter((event): event is NavigationEnd => event instanceof NavigationEnd))
|
||||||
|
.subscribe((event) => {
|
||||||
|
const newUrl = event.urlAfterRedirects;
|
||||||
|
|
||||||
|
// Ignore duplicate events
|
||||||
|
if (newUrl === this.currentUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.previousUrl = this.currentUrl;
|
||||||
|
this.currentUrl = newUrl;
|
||||||
|
|
||||||
|
if (this.previousUrl) {
|
||||||
|
sessionStorage.setItem(this.PREVIOUS_URL_KEY, this.previousUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionStorage.setItem(this.CURRENT_URL_KEY, this.currentUrl);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
canGoBack(): boolean {
|
||||||
|
return !!this.previousUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
back(fallbackUrl = '/'): void {
|
||||||
|
if (this.canGoBack()) {
|
||||||
|
window.history.back();
|
||||||
|
} else {
|
||||||
|
this.router.navigateByUrl(fallbackUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-4
@@ -1,15 +1,15 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="مدیریت سطح دسترسی">
|
<app-card-data cardTitle="مدیریت سطح دسترسی">
|
||||||
@if (isOwner()) {
|
@if (isOwner()) {
|
||||||
<div class="py-20 flex items-center justify-center">
|
<div class="flex items-center justify-center py-20">
|
||||||
کاربر با سطح Owner به تمامی سطوح دسترسی داشته و قابل ویرایش نمیباشد
|
کاربر با سطح Owner به تمامی سطوح دسترسی داشته و قابل ویرایش نمیباشد
|
||||||
</div>
|
</div>
|
||||||
} @else if (loading()) {
|
} @else if (loading()) {
|
||||||
<div class="py-20 flex items-center justify-center">
|
<div class="flex items-center justify-center py-20">
|
||||||
<p-progressSpinner />
|
<p-progressSpinner />
|
||||||
</div>
|
</div>
|
||||||
} @else if (permissions()) {
|
} @else if (permissions()) {
|
||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<p-message severity="secondary"> پیام مفهومی برای مشخص کردن نوع دسترسی دادن</p-message>
|
<p-message severity="secondary"> پیام مفهومی برای مشخص کردن نوع دسترسی دادن</p-message>
|
||||||
@for (pos of permissions()?.poses; track $index) {
|
@for (pos of permissions()?.poses; track $index) {
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات کاربری" [editable]="false" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات کاربری" [editable]="false" [(editMode)]="editMode">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
|
|||||||
+4
-6
@@ -4,14 +4,13 @@
|
|||||||
[modal]="true"
|
[modal]="true"
|
||||||
[style]="{ width: '500px' }"
|
[style]="{ width: '500px' }"
|
||||||
[closable]="true"
|
[closable]="true"
|
||||||
(onHide)="close()"
|
(onHide)="close()">
|
||||||
>
|
|
||||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
||||||
<field-name [control]="form.controls.name" />
|
<field-name [control]="form.controls.name" />
|
||||||
|
|
||||||
<field-pos-type [control]="form.controls.pos_type" />
|
<!-- <field-pos-type [control]="form.controls.pos_type" /> -->
|
||||||
|
|
||||||
@if (form.controls.pos_type.value === "PSP") {
|
@if (form.controls.pos_type.value === 'PSP') {
|
||||||
<field-serial-number [control]="form.controls.serial_number" />
|
<field-serial-number [control]="form.controls.serial_number" />
|
||||||
<field-device-id [control]="form.controls.device_id" />
|
<field-device-id [control]="form.controls.device_id" />
|
||||||
<field-provider-id [control]="form.controls.provider_id" />
|
<field-provider-id [control]="form.controls.provider_id" />
|
||||||
@@ -22,8 +21,7 @@
|
|||||||
<field-username [control]="form.controls.username" />
|
<field-username [control]="form.controls.username" />
|
||||||
<shared-password-input
|
<shared-password-input
|
||||||
[passwordControl]="form.controls.password"
|
[passwordControl]="form.controls.password"
|
||||||
[confirmPasswordControl]="form.controls.confirmPassword"
|
[confirmPasswordControl]="form.controls.confirmPassword" />
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" />
|
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" />
|
||||||
|
|||||||
+4
-6
@@ -4,7 +4,6 @@ import { AbstractFormDialog } from '@/shared/abstractClasses';
|
|||||||
import {
|
import {
|
||||||
DeviceIdComponent,
|
DeviceIdComponent,
|
||||||
NameComponent,
|
NameComponent,
|
||||||
PosTypeComponent,
|
|
||||||
ProviderIdComponent,
|
ProviderIdComponent,
|
||||||
SerialNumberComponent,
|
SerialNumberComponent,
|
||||||
SharedPasswordInputComponent,
|
SharedPasswordInputComponent,
|
||||||
@@ -29,7 +28,6 @@ import { ConsumerPosesService } from '../../services/poses.service';
|
|||||||
FormFooterActionsComponent,
|
FormFooterActionsComponent,
|
||||||
DeviceIdComponent,
|
DeviceIdComponent,
|
||||||
ProviderIdComponent,
|
ProviderIdComponent,
|
||||||
PosTypeComponent,
|
|
||||||
SerialNumberComponent,
|
SerialNumberComponent,
|
||||||
UsernameComponent,
|
UsernameComponent,
|
||||||
Divider,
|
Divider,
|
||||||
@@ -46,7 +44,7 @@ export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IP
|
|||||||
initForm = () => {
|
initForm = () => {
|
||||||
const form = this.fb.group({
|
const form = this.fb.group({
|
||||||
name: fieldControl.name(this.initialValues?.name || ''),
|
name: fieldControl.name(this.initialValues?.name || ''),
|
||||||
pos_type: fieldControl.pos_type(this.initialValues?.pos_type || ''),
|
pos_type: fieldControl.pos_type(this.initialValues?.pos_type || 'PSP'),
|
||||||
serial_number: fieldControl.serial_number(this.initialValues?.serial_number || ''),
|
serial_number: fieldControl.serial_number(this.initialValues?.serial_number || ''),
|
||||||
device_id: fieldControl.device_id(this.initialValues?.device?.id || ''),
|
device_id: fieldControl.device_id(this.initialValues?.device?.id || ''),
|
||||||
provider_id: fieldControl.provider_id(this.initialValues?.provider?.id || ''),
|
provider_id: fieldControl.provider_id(this.initialValues?.provider?.id || ''),
|
||||||
@@ -96,7 +94,7 @@ export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IP
|
|||||||
this.fb.control<string>('', {
|
this.fb.control<string>('', {
|
||||||
nonNullable: true,
|
nonNullable: true,
|
||||||
validators: fieldControl.username('')[1],
|
validators: fieldControl.username('')[1],
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
form.addControl(
|
form.addControl(
|
||||||
@@ -104,7 +102,7 @@ export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IP
|
|||||||
this.fb.control<string>('', {
|
this.fb.control<string>('', {
|
||||||
nonNullable: true,
|
nonNullable: true,
|
||||||
validators: [Validators.required],
|
validators: [Validators.required],
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
form.addControl(
|
form.addControl(
|
||||||
@@ -112,7 +110,7 @@ export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IP
|
|||||||
this.fb.control<string>('', {
|
this.fb.control<string>('', {
|
||||||
nonNullable: true,
|
nonNullable: true,
|
||||||
validators: [Validators.required],
|
validators: [Validators.required],
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
form.addValidators([MustMatch('password', 'confirmPassword')]);
|
form.addValidators([MustMatch('password', 'confirmPassword')]);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-5
@@ -1,5 +1,5 @@
|
|||||||
<app-page-data-list
|
<app-page-data-list
|
||||||
pageTitle="لیست پایانههای فروش"
|
pageTitle="پایانههای فروش"
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
[addNewCtaLabel]="'افزودن پایانه فروش'"
|
[addNewCtaLabel]="'افزودن پایانه فروش'"
|
||||||
emptyPlaceholderTitle="پایانه فروشی یافت نشد."
|
emptyPlaceholderTitle="پایانه فروشی یافت نشد."
|
||||||
@@ -12,8 +12,7 @@
|
|||||||
(onAdd)="openAddForm()"
|
(onAdd)="openAddForm()"
|
||||||
(onEdit)="onEditClick($event)"
|
(onEdit)="onEditClick($event)"
|
||||||
(onDetails)="toSinglePage($event)"
|
(onDetails)="toSinglePage($event)"
|
||||||
(onRefresh)="refresh()"
|
(onRefresh)="refresh()">
|
||||||
>
|
|
||||||
</app-page-data-list>
|
</app-page-data-list>
|
||||||
<consumer-pos-form
|
<consumer-pos-form
|
||||||
[(visible)]="visibleForm"
|
[(visible)]="visibleForm"
|
||||||
@@ -22,5 +21,4 @@
|
|||||||
[complexId]="complexId"
|
[complexId]="complexId"
|
||||||
[posId]="selectedItemForEdit()?.id || ''"
|
[posId]="selectedItemForEdit()?.id || ''"
|
||||||
[initialValues]="selectedItemForEdit() || undefined"
|
[initialValues]="selectedItemForEdit() || undefined"
|
||||||
(onSubmit)="refresh()"
|
(onSubmit)="refresh()" />
|
||||||
/>
|
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@ import {
|
|||||||
} from '@/shared/components/pageDataList/page-data-list.component';
|
} from '@/shared/components/pageDataList/page-data-list.component';
|
||||||
import { Component, inject, Input } from '@angular/core';
|
import { Component, inject, Input } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { consumerPosesNamedRoutes } from '../../constants/routes/poses';
|
import { consumerComplexPosesNamedRoutes } from '../../constants/routes/poses';
|
||||||
import { IPosResponse } from '../../models';
|
import { IPosResponse } from '../../models';
|
||||||
import { ConsumerPosesService } from '../../services/poses.service';
|
import { ConsumerPosesService } from '../../services/poses.service';
|
||||||
import { ConsumerPosFormComponent } from './form.component';
|
import { ConsumerPosFormComponent } from './form.component';
|
||||||
@@ -36,7 +36,7 @@ export class ConsumerPosesComponent extends AbstractList<IPosResponse> {
|
|||||||
|
|
||||||
toSinglePage(item: IPosResponse) {
|
toSinglePage(item: IPosResponse) {
|
||||||
this.router.navigateByUrl(
|
this.router.navigateByUrl(
|
||||||
consumerPosesNamedRoutes.pos.meta.pagePath!(this.businessId, this.complexId, item.id),
|
consumerComplexPosesNamedRoutes.pos.meta.pagePath!(this.businessId, this.complexId, item.id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-2
@@ -1,8 +1,13 @@
|
|||||||
<app-page-data-list
|
<app-page-data-list
|
||||||
pageTitle="صورتحسابها"
|
[pageTitle]="'صورتحسابها'"
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
emptyPlaceholderTitle="تا به حال صورتحسابی توسط این پایانه ایجاد نشده است."
|
emptyPlaceholderTitle="صورتحسابی یافت نشد"
|
||||||
[items]="items()"
|
[items]="items()"
|
||||||
[loading]="loading()"
|
[loading]="loading()"
|
||||||
|
[showDetails]="true"
|
||||||
|
(onDetails)="toSinglePage($event)"
|
||||||
(onRefresh)="refresh()">
|
(onRefresh)="refresh()">
|
||||||
|
<ng-template #status let-item>
|
||||||
|
<catalog-tax-provider-status-tag [status]="item.status.value" [translate]="item.status.translate" />
|
||||||
|
</ng-template>
|
||||||
</app-page-data-list>
|
</app-page-data-list>
|
||||||
|
|||||||
+25
-20
@@ -1,47 +1,52 @@
|
|||||||
// import { CatalogRoleTagComponent } from '@/shared/catalog/roles';
|
// import { CatalogRoleTagComponent } from '@/shared/catalog/roles';
|
||||||
import { AbstractList } from '@/shared/abstractClasses/abstract-list';
|
import { AbstractList } from '@/shared/abstractClasses/abstract-list';
|
||||||
|
import { CatalogTaxProviderStatusTagComponent } from '@/shared/catalog';
|
||||||
import {
|
import {
|
||||||
IColumn,
|
IColumn,
|
||||||
PageDataListComponent,
|
PageDataListComponent,
|
||||||
} from '@/shared/components/pageDataList/page-data-list.component';
|
} from '@/shared/components/pageDataList/page-data-list.component';
|
||||||
import { Component, inject, Input } from '@angular/core';
|
import { saleInvoiceListConfig } from '@/shared/constants/list-configs';
|
||||||
|
import { Component, inject, Input, TemplateRef, ViewChild } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { consumerSaleInvoicesNamedRoutes } from '../../../saleInvoices/constants/routes';
|
||||||
import { ISalesInvoicesResponse } from '../../models';
|
import { ISalesInvoicesResponse } from '../../models';
|
||||||
import { ConsumerSalesInvoicesService } from '../../services/invoices.service';
|
import { ConsumerSalesInvoicesService } from '../../services/invoices.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'consumer-salesInvoices-list',
|
selector: 'consumer-salesInvoices-list',
|
||||||
templateUrl: './list.component.html',
|
templateUrl: './list.component.html',
|
||||||
imports: [PageDataListComponent],
|
imports: [PageDataListComponent, CatalogTaxProviderStatusTagComponent],
|
||||||
})
|
})
|
||||||
export class ConsumerSalesInvoicesComponent extends AbstractList<ISalesInvoicesResponse> {
|
export class ConsumerSalesInvoicesComponent extends AbstractList<ISalesInvoicesResponse> {
|
||||||
|
@ViewChild('status', { static: true }) status!: TemplateRef<any>;
|
||||||
|
|
||||||
@Input({ required: true }) complexId!: string;
|
@Input({ required: true }) complexId!: string;
|
||||||
@Input({ required: true }) posId!: string;
|
@Input({ required: true }) posId!: string;
|
||||||
@Input() fullHeight?: boolean;
|
@Input() fullHeight?: boolean;
|
||||||
@Input() header: IColumn[] = [
|
@Input() header: IColumn[] = saleInvoiceListConfig.columns;
|
||||||
// { field: 'id', header: 'شناسه', type: 'id' },
|
|
||||||
{ field: 'code', header: 'کد رهگیری' },
|
|
||||||
{ field: 'total_amount', header: 'مبلغ کل', type: 'price' },
|
|
||||||
{
|
|
||||||
field: 'items_count',
|
|
||||||
header: 'تعداد کالاها',
|
|
||||||
customDataModel(item) {
|
|
||||||
return `${item.items.length} عدد`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'invoice_date',
|
|
||||||
header: 'تاریخ',
|
|
||||||
type: 'date',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
private readonly service = inject(ConsumerSalesInvoicesService);
|
private readonly service = inject(ConsumerSalesInvoicesService);
|
||||||
|
private readonly router = inject(Router);
|
||||||
|
|
||||||
override setColumns(): void {
|
override setColumns(): void {
|
||||||
this.columns = this.header;
|
this.columns = this.header
|
||||||
|
.map((header) => {
|
||||||
|
if (header.field === 'status') {
|
||||||
|
return {
|
||||||
|
...header,
|
||||||
|
customDataModel: this.status,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return header;
|
||||||
|
})
|
||||||
|
.filter((header) => header.field !== 'pos');
|
||||||
}
|
}
|
||||||
|
|
||||||
override getDataRequest() {
|
override getDataRequest() {
|
||||||
return this.service.getAll(this.complexId, this.posId);
|
return this.service.getAll(this.complexId, this.posId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toSinglePage(item: ISalesInvoicesResponse) {
|
||||||
|
this.router.navigateByUrl(consumerSaleInvoicesNamedRoutes.saleInvoice.meta.pagePath!(item.id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export type TPosesRouteNames = 'poses' | 'pos';
|
|||||||
const baseUrl = (businessId: string, complexId: string) =>
|
const baseUrl = (businessId: string, complexId: string) =>
|
||||||
`/consumer/business_activities/${businessId}/complexes/${complexId}/poses`;
|
`/consumer/business_activities/${businessId}/complexes/${complexId}/poses`;
|
||||||
|
|
||||||
export const consumerPosesNamedRoutes: NamedRoutes<TPosesRouteNames> = {
|
export const consumerComplexPosesNamedRoutes: NamedRoutes<TPosesRouteNames> = {
|
||||||
poses: {
|
poses: {
|
||||||
path: 'poses',
|
path: 'poses',
|
||||||
loadComponent: () =>
|
loadComponent: () =>
|
||||||
@@ -31,17 +31,17 @@ export const consumerPosesNamedRoutes: NamedRoutes<TPosesRouteNames> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const CONSUMER_POSES_ROUTES: Routes = [
|
export const CONSUMER_POSES_ROUTES: Routes = [
|
||||||
consumerPosesNamedRoutes.poses,
|
consumerComplexPosesNamedRoutes.poses,
|
||||||
{
|
{
|
||||||
path: consumerPosesNamedRoutes.pos.path,
|
path: consumerComplexPosesNamedRoutes.pos.path,
|
||||||
loadComponent: () =>
|
loadComponent: () =>
|
||||||
import('../../components/poses/layout.component').then(
|
import('../../components/poses/layout.component').then(
|
||||||
(m) => m.SuperAdminConsumerPosLayoutComponent,
|
(m) => m.SuperAdminConsumerPosLayoutComponent
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
loadComponent: consumerPosesNamedRoutes.pos.loadComponent,
|
loadComponent: consumerComplexPosesNamedRoutes.pos.loadComponent,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
+4
@@ -1,11 +1,15 @@
|
|||||||
import ISummary from '@/core/models/summary';
|
import ISummary from '@/core/models/summary';
|
||||||
import { TCustomerInfo, TPosOrderGoodPayload } from '@/domains/pos/modules/shop/models';
|
import { TCustomerInfo, TPosOrderGoodPayload } from '@/domains/pos/modules/shop/models';
|
||||||
|
import { TspProviderResponseStatus } from '@/shared/catalog';
|
||||||
|
import { IEnumTranslate } from '@/shared/models';
|
||||||
|
|
||||||
export interface ISalesInvoicesRawResponse {
|
export interface ISalesInvoicesRawResponse {
|
||||||
id: string;
|
id: string;
|
||||||
|
invoice_number: string;
|
||||||
code: string;
|
code: string;
|
||||||
invoice_date: string;
|
invoice_date: string;
|
||||||
total_amount: string;
|
total_amount: string;
|
||||||
|
status: IEnumTranslate<TspProviderResponseStatus>;
|
||||||
items: Item[];
|
items: Item[];
|
||||||
payments: Payment[];
|
payments: Payment[];
|
||||||
customer?: TCustomerInfo;
|
customer?: TCustomerInfo;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export class BusinessActivityStore extends EntityStore<
|
|||||||
catchError((error) => {
|
catchError((error) => {
|
||||||
this.setError(error);
|
this.setError(error);
|
||||||
throw error;
|
throw error;
|
||||||
}),
|
})
|
||||||
)
|
)
|
||||||
.subscribe((entity) => {
|
.subscribe((entity) => {
|
||||||
this.patchState({ entity });
|
this.patchState({ entity });
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { defaultBaseStateData, EntityState, EntityStore } from '@/core/state';
|
|||||||
import { computed, inject, Injectable } from '@angular/core';
|
import { computed, inject, Injectable } from '@angular/core';
|
||||||
import { MenuItem } from 'primeng/api';
|
import { MenuItem } from 'primeng/api';
|
||||||
import { catchError, finalize } from 'rxjs';
|
import { catchError, finalize } from 'rxjs';
|
||||||
import { consumerPosesNamedRoutes } from '../constants/routes/poses';
|
import { consumerComplexPosesNamedRoutes } from '../constants/routes/poses';
|
||||||
import { IPosResponse } from '../models';
|
import { IPosResponse } from '../models';
|
||||||
import { ConsumerPosesService } from '../services/poses.service';
|
import { ConsumerPosesService } from '../services/poses.service';
|
||||||
|
|
||||||
@@ -28,12 +28,16 @@ export class PosStore extends EntityStore<IPosResponse, PosState> {
|
|||||||
this.patchState({
|
this.patchState({
|
||||||
breadcrumbItems: [
|
breadcrumbItems: [
|
||||||
{
|
{
|
||||||
...consumerPosesNamedRoutes.poses.meta,
|
...consumerComplexPosesNamedRoutes.poses.meta,
|
||||||
routerLink: consumerPosesNamedRoutes.poses.meta.pagePath!(businessId, complexId),
|
routerLink: consumerComplexPosesNamedRoutes.poses.meta.pagePath!(businessId, complexId),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: this.entity()?.name,
|
title: this.entity()?.name,
|
||||||
routerLink: consumerPosesNamedRoutes.pos.meta.pagePath!(businessId, complexId, posId),
|
routerLink: consumerComplexPosesNamedRoutes.pos.meta.pagePath!(
|
||||||
|
businessId,
|
||||||
|
complexId,
|
||||||
|
posId
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@@ -50,7 +54,7 @@ export class PosStore extends EntityStore<IPosResponse, PosState> {
|
|||||||
catchError((error) => {
|
catchError((error) => {
|
||||||
this.setError(error);
|
this.setError(error);
|
||||||
throw error;
|
throw error;
|
||||||
}),
|
})
|
||||||
)
|
)
|
||||||
.subscribe((entity) => {
|
.subscribe((entity) => {
|
||||||
this.patchState({ entity });
|
this.patchState({ entity });
|
||||||
|
|||||||
+2
-3
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات شعبه" [editable]="true" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات شعبه" [editable]="true" [(editMode)]="editMode">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
@@ -17,6 +17,5 @@
|
|||||||
[businessActivityId]="businessId()"
|
[businessActivityId]="businessId()"
|
||||||
[complexId]="complexId()"
|
[complexId]="complexId()"
|
||||||
[initialValues]="complex() || undefined"
|
[initialValues]="complex() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import pageParamsUtils from '@/utils/page-params.utils';
|
|||||||
import { Component, computed, inject, signal } from '@angular/core';
|
import { Component, computed, inject, signal } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { ConsumerPosesComponent } from '../../components/poses/list.component';
|
import { ConsumerPosesComponent } from '../../components/poses/list.component';
|
||||||
import { consumerPosesNamedRoutes } from '../../constants/routes/poses';
|
import { consumerComplexPosesNamedRoutes } from '../../constants/routes/poses';
|
||||||
import { BusinessActivityStore } from '../../store/businessActivity.store';
|
import { BusinessActivityStore } from '../../store/businessActivity.store';
|
||||||
import { ConsumerComplexStore } from '../../store/complex.store';
|
import { ConsumerComplexStore } from '../../store/complex.store';
|
||||||
|
|
||||||
@@ -32,10 +32,10 @@ export class ConsumerPosListPageComponent {
|
|||||||
...this.businessStore.breadcrumbItems(),
|
...this.businessStore.breadcrumbItems(),
|
||||||
...this.complexStore.breadcrumbItems(),
|
...this.complexStore.breadcrumbItems(),
|
||||||
{
|
{
|
||||||
title: consumerPosesNamedRoutes.poses.meta.title,
|
title: consumerComplexPosesNamedRoutes.poses.meta.title,
|
||||||
routerLink: consumerPosesNamedRoutes.poses.meta.pagePath!(
|
routerLink: consumerComplexPosesNamedRoutes.poses.meta.pagePath!(
|
||||||
this.businessId(),
|
this.businessId(),
|
||||||
this.complexId(),
|
this.complexId()
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|||||||
+3
-4
@@ -1,5 +1,5 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات پایانه فروش" [editable]="true" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات پایانه فروش" [backRoute]="backRoute()" [editable]="true" [(editMode)]="editMode">
|
||||||
<ng-template #moreActions>
|
<ng-template #moreActions>
|
||||||
<p-button type="button" variant="outlined" size="small" (onClick)="toPosLanding()"> ورود به پایانه </p-button>
|
<p-button type="button" variant="outlined" size="small" (onClick)="toPosLanding()"> ورود به پایانه </p-button>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@@ -24,6 +24,5 @@
|
|||||||
[complexId]="complexId()"
|
[complexId]="complexId()"
|
||||||
[posId]="posId()"
|
[posId]="posId()"
|
||||||
[initialValues]="pos() || undefined"
|
[initialValues]="pos() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { Button } from 'primeng/button';
|
|||||||
import { COOKIE_KEYS } from 'src/assets/constants';
|
import { COOKIE_KEYS } from 'src/assets/constants';
|
||||||
import { ConsumerPosFormComponent } from '../../components/poses/form.component';
|
import { ConsumerPosFormComponent } from '../../components/poses/form.component';
|
||||||
import { ConsumerSalesInvoicesComponent } from '../../components/salesInvoices/list.component';
|
import { ConsumerSalesInvoicesComponent } from '../../components/salesInvoices/list.component';
|
||||||
|
import { consumerComplexPosesNamedRoutes } from '../../constants/routes/poses';
|
||||||
import { BusinessActivityStore } from '../../store/businessActivity.store';
|
import { BusinessActivityStore } from '../../store/businessActivity.store';
|
||||||
import { ConsumerComplexStore } from '../../store/complex.store';
|
import { ConsumerComplexStore } from '../../store/complex.store';
|
||||||
import { PosStore } from '../../store/pos.store';
|
import { PosStore } from '../../store/pos.store';
|
||||||
@@ -38,6 +39,11 @@ export class ConsumerComplexPosPageComponent {
|
|||||||
readonly posId = signal<string>(this.pageParams()['posId']!);
|
readonly posId = signal<string>(this.pageParams()['posId']!);
|
||||||
editMode = signal<boolean>(false);
|
editMode = signal<boolean>(false);
|
||||||
|
|
||||||
|
backRoute = computed(
|
||||||
|
() =>
|
||||||
|
`${consumerComplexPosesNamedRoutes.poses.meta.pagePath!(this.businessId(), this.complexId())}`
|
||||||
|
);
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
effect(() => {
|
effect(() => {
|
||||||
if (this.pos()?.id) {
|
if (this.pos()?.id) {
|
||||||
@@ -59,7 +65,7 @@ export class ConsumerComplexPosPageComponent {
|
|||||||
sameSite: 'Lax', // or 'Strict' for same-site requests only
|
sameSite: 'Lax', // or 'Strict' for same-site requests only
|
||||||
secure: false,
|
secure: false,
|
||||||
path: '/',
|
path: '/',
|
||||||
domain: 'localhost',
|
domain: window.location.hostname,
|
||||||
});
|
});
|
||||||
window.open('/pos', '_blank');
|
window.open('/pos', '_blank');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات فعالیت اقتصادی" [editable]="true" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات فعالیت اقتصادی" [editable]="true" [(editMode)]="editMode">
|
||||||
<ng-template #moreActions>
|
<ng-template #moreActions>
|
||||||
<a routerLink pButton [routerLink]="goodsPageRoute()" outlined size="small">مدیریت کالاها</a>
|
<a routerLink pButton [routerLink]="goodsPageRoute()" outlined size="small">مدیریت کالاها</a>
|
||||||
@@ -25,6 +25,5 @@
|
|||||||
[editMode]="true"
|
[editMode]="true"
|
||||||
[businessId]="businessId()"
|
[businessId]="businessId()"
|
||||||
[initialValues]="business() || undefined"
|
[initialValues]="business() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<app-page-data-list
|
<app-page-data-list
|
||||||
[pageTitle]="'لیست مشتری'"
|
[pageTitle]="'مشتریها'"
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
emptyPlaceholderTitle="مشتری یافت نشد"
|
emptyPlaceholderTitle="مشتری یافت نشد"
|
||||||
[items]="items()"
|
[items]="items()"
|
||||||
@@ -8,8 +8,7 @@
|
|||||||
[showDetails]="true"
|
[showDetails]="true"
|
||||||
(onEdit)="onEditClick($event)"
|
(onEdit)="onEditClick($event)"
|
||||||
(onDetails)="toSinglePage($event)"
|
(onDetails)="toSinglePage($event)"
|
||||||
(onRefresh)="refresh()"
|
(onRefresh)="refresh()" />
|
||||||
/>
|
|
||||||
|
|
||||||
@if (selectedItemForEdit()) {
|
@if (selectedItemForEdit()) {
|
||||||
<consumer-customer-form-dialog [(visible)]="visibleForm" [customer]="selectedItemForEdit()!" (onSubmit)="refresh()" />
|
<consumer-customer-form-dialog [(visible)]="visibleForm" [customer]="selectedItemForEdit()!" (onSubmit)="refresh()" />
|
||||||
|
|||||||
+6
-2
@@ -1,9 +1,13 @@
|
|||||||
<app-page-data-list
|
<app-page-data-list
|
||||||
[pageTitle]="'لیست صورتحساب'"
|
[pageTitle]="'صورتحسابها'"
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
emptyPlaceholderTitle="صورتحسابی یافت نشد"
|
emptyPlaceholderTitle="صورتحسابی یافت نشد"
|
||||||
[items]="items()"
|
[items]="items()"
|
||||||
[loading]="loading()"
|
[loading]="loading()"
|
||||||
[showDetails]="true"
|
[showDetails]="true"
|
||||||
(onDetails)="toSinglePage($event)"
|
(onDetails)="toSinglePage($event)"
|
||||||
(onRefresh)="refresh()" />
|
(onRefresh)="refresh()">
|
||||||
|
<ng-template #status let-item>
|
||||||
|
<catalog-tax-provider-status-tag [status]="item.status.value" [translate]="item.status.translate" />
|
||||||
|
</ng-template>
|
||||||
|
</app-page-data-list>
|
||||||
|
|||||||
+15
-34
@@ -1,10 +1,12 @@
|
|||||||
// import { CatalogRoleTagComponent } from '@/shared/catalog/roles';
|
// import { CatalogRoleTagComponent } from '@/shared/catalog/roles';
|
||||||
import { AbstractList } from '@/shared/abstractClasses/abstract-list';
|
import { AbstractList } from '@/shared/abstractClasses/abstract-list';
|
||||||
|
import { CatalogTaxProviderStatusTagComponent } from '@/shared/catalog';
|
||||||
import {
|
import {
|
||||||
IColumn,
|
IColumn,
|
||||||
PageDataListComponent,
|
PageDataListComponent,
|
||||||
} from '@/shared/components/pageDataList/page-data-list.component';
|
} from '@/shared/components/pageDataList/page-data-list.component';
|
||||||
import { Component, inject, Input } from '@angular/core';
|
import { saleInvoiceListConfig } from '@/shared/constants/list-configs';
|
||||||
|
import { Component, inject, Input, TemplateRef, ViewChild } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { consumerCustomerSaleInvoicesNamedRoutes } from '../../constants/routes/saleInvoices';
|
import { consumerCustomerSaleInvoicesNamedRoutes } from '../../constants/routes/saleInvoices';
|
||||||
import { ICustomerSaleInvoicesResponse } from '../../models/saleInvoices.io';
|
import { ICustomerSaleInvoicesResponse } from '../../models/saleInvoices.io';
|
||||||
@@ -13,48 +15,27 @@ import { CustomerSaleInvoicesService } from '../../services/saleInvoices.service
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'consumer-customer-saleInvoice-list',
|
selector: 'consumer-customer-saleInvoice-list',
|
||||||
templateUrl: './list.component.html',
|
templateUrl: './list.component.html',
|
||||||
imports: [PageDataListComponent],
|
imports: [PageDataListComponent, CatalogTaxProviderStatusTagComponent],
|
||||||
})
|
})
|
||||||
export class ConsumerCustomerSaleInvoiceListComponent extends AbstractList<ICustomerSaleInvoicesResponse> {
|
export class ConsumerCustomerSaleInvoiceListComponent extends AbstractList<ICustomerSaleInvoicesResponse> {
|
||||||
@Input({ required: true }) customerId!: string;
|
@Input({ required: true }) customerId!: string;
|
||||||
@Input() fullHeight?: boolean;
|
@Input() fullHeight?: boolean;
|
||||||
@Input() header: IColumn[] = [
|
@Input() header: IColumn[] = saleInvoiceListConfig.columns;
|
||||||
{ field: 'code', header: 'کد رهگیری' },
|
@ViewChild('status', { static: true }) status!: TemplateRef<any>;
|
||||||
{
|
|
||||||
field: 'total_amount',
|
|
||||||
header: 'قیمت نهایی',
|
|
||||||
type: 'price',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'pos',
|
|
||||||
header: 'پایانه',
|
|
||||||
customDataModel(item: ICustomerSaleInvoicesResponse) {
|
|
||||||
return `${item.pos.complex.business_activity.name}، شعبه ${item.pos.complex.name}، پایانه فروش ${item.pos.name}`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'account',
|
|
||||||
header: 'ایجاد شده توسط',
|
|
||||||
type: 'nested',
|
|
||||||
nestedOption: { path: 'account.account.username' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'invoice_date',
|
|
||||||
header: 'تاریخ صورتحساب',
|
|
||||||
type: 'date',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'created_at',
|
|
||||||
header: 'تاریخ ایجاد',
|
|
||||||
type: 'date',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
private readonly service = inject(CustomerSaleInvoicesService);
|
private readonly service = inject(CustomerSaleInvoicesService);
|
||||||
private readonly router = inject(Router);
|
private readonly router = inject(Router);
|
||||||
|
|
||||||
override setColumns(): void {
|
override setColumns(): void {
|
||||||
this.columns = this.header;
|
this.columns = this.header.map((header) => {
|
||||||
|
if (header.field === 'status') {
|
||||||
|
return {
|
||||||
|
...header,
|
||||||
|
customDataModel: this.status,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return header;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
override getDataRequest() {
|
override getDataRequest() {
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ export const consumerCustomerSaleInvoicesNamedRoutes: NamedRoutes<TConsumerCusto
|
|||||||
(m) => m.ConsumerCustomerSaleInvoicesComponent
|
(m) => m.ConsumerCustomerSaleInvoicesComponent
|
||||||
),
|
),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'صورتحسابهای صادر شده',
|
title: 'صورتحسابها',
|
||||||
pagePath: (customerId: string) => `consumer/customers/${customerId}`,
|
pagePath: (customerId: string) => `consumer/customers/${customerId}/saleInvoices`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
saleInvoice: {
|
saleInvoice: {
|
||||||
@@ -23,7 +23,7 @@ export const consumerCustomerSaleInvoicesNamedRoutes: NamedRoutes<TConsumerCusto
|
|||||||
(m) => m.ConsumerCustomerSaleInvoiceComponent
|
(m) => m.ConsumerCustomerSaleInvoiceComponent
|
||||||
),
|
),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'صورتحساب صادر شده',
|
title: 'صورتحساب',
|
||||||
pagePath: (customerId: string, saleInvoiceId: string) =>
|
pagePath: (customerId: string, saleInvoiceId: string) =>
|
||||||
`consumer/customers/${customerId}/saleInvoices/${saleInvoiceId}`,
|
`consumer/customers/${customerId}/saleInvoices/${saleInvoiceId}`,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -36,10 +36,10 @@ export class ConsumerCustomerSaleInvoiceStore extends EntityStore<
|
|||||||
consumerCustomerSaleInvoicesNamedRoutes.saleInvoices.meta.pagePath!(customerId),
|
consumerCustomerSaleInvoicesNamedRoutes.saleInvoices.meta.pagePath!(customerId),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: this.entity()?.code,
|
title: `صورتحساب ${this.entity()?.invoice_number}`,
|
||||||
routerLink: consumerCustomerSaleInvoicesNamedRoutes.saleInvoice.meta.pagePath!(
|
routerLink: consumerCustomerSaleInvoicesNamedRoutes.saleInvoice.meta.pagePath!(
|
||||||
customerId,
|
customerId,
|
||||||
invoiceId,
|
invoiceId
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -57,7 +57,7 @@ export class ConsumerCustomerSaleInvoiceStore extends EntityStore<
|
|||||||
catchError((error) => {
|
catchError((error) => {
|
||||||
this.setError(error);
|
this.setError(error);
|
||||||
throw error;
|
throw error;
|
||||||
}),
|
})
|
||||||
)
|
)
|
||||||
.subscribe((entity) => {
|
.subscribe((entity) => {
|
||||||
this.patchState({ entity });
|
this.patchState({ entity });
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
// import { CatalogRoleTagComponent } from '@/shared/catalog/roles';
|
// import { CatalogRoleTagComponent } from '@/shared/catalog/roles';
|
||||||
import { Component, inject, signal } from '@angular/core';
|
import { BreadcrumbService } from '@/core/services';
|
||||||
|
import pageParamsUtils from '@/utils/page-params.utils';
|
||||||
|
import { Component, computed, inject, signal } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { ConsumerCustomerSaleInvoiceListComponent } from '../../components/saleInvoices/list.component';
|
import { ConsumerCustomerSaleInvoiceListComponent } from '../../components/saleInvoices/list.component';
|
||||||
|
import { consumerCustomerSaleInvoicesNamedRoutes } from '../../constants/routes/saleInvoices';
|
||||||
|
import { ConsumerCustomerStore } from '../../store/customer.store';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'consumer-customer-saleInvoices',
|
selector: 'consumer-customer-saleInvoices',
|
||||||
@@ -10,6 +14,25 @@ import { ConsumerCustomerSaleInvoiceListComponent } from '../../components/saleI
|
|||||||
})
|
})
|
||||||
export class ConsumerCustomerSaleInvoicesComponent {
|
export class ConsumerCustomerSaleInvoicesComponent {
|
||||||
private readonly route = inject(ActivatedRoute);
|
private readonly route = inject(ActivatedRoute);
|
||||||
|
private readonly breadcrumbService = inject(BreadcrumbService);
|
||||||
|
private readonly store = inject(ConsumerCustomerStore);
|
||||||
|
|
||||||
readonly customerId = signal<string>(this.route.snapshot.paramMap.get('customerId')!);
|
pageParams = computed(() => pageParamsUtils(this.route));
|
||||||
|
customerId = signal<string>(this.pageParams()['customerId']);
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this.setBreadcrumb();
|
||||||
|
}
|
||||||
|
|
||||||
|
setBreadcrumb() {
|
||||||
|
this.breadcrumbService.setItems([
|
||||||
|
...this.store.breadcrumbItems(),
|
||||||
|
{
|
||||||
|
title: consumerCustomerSaleInvoicesNamedRoutes.saleInvoices.meta.title,
|
||||||
|
routerLink: consumerCustomerSaleInvoicesNamedRoutes.saleInvoices.meta.pagePath!(
|
||||||
|
this.customerId()
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ export class ConsumerCustomerSaleInvoiceComponent {
|
|||||||
constructor() {
|
constructor() {
|
||||||
effect(() => {
|
effect(() => {
|
||||||
if (this.invoice()?.id) {
|
if (this.invoice()?.id) {
|
||||||
|
console.log('inja');
|
||||||
|
|
||||||
this.setBreadcrumb();
|
this.setBreadcrumb();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data
|
<app-card-data
|
||||||
[cardTitle]="`اطلاعات مشتری (${customer() ? (customer()?.type === 'LEGAL' ? 'حقوقی' : 'حقیقی') : ''})`"
|
[cardTitle]="`اطلاعات مشتری (${customer() ? (customer()?.type === 'LEGAL' ? 'حقوقی' : 'حقیقی') : ''})`"
|
||||||
[editable]="true"
|
[editable]="true"
|
||||||
[(editMode)]="editMode"
|
[(editMode)]="editMode">
|
||||||
>
|
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
@if (customer()?.type === "LEGAL") {
|
@if (customer()?.type === 'LEGAL') {
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
<app-key-value label="عنوان" [value]="customer()?.legal?.company_name" />
|
<app-key-value label="عنوان" [value]="customer()?.legal?.company_name" />
|
||||||
<app-key-value label="کد اقتصادی" [value]="customer()?.legal?.economic_code" />
|
<app-key-value label="کد اقتصادی" [value]="customer()?.legal?.economic_code" />
|
||||||
<app-key-value label="شماره ثبت" [value]="customer()?.legal?.registration_number" />
|
<app-key-value label="شماره ثبت" [value]="customer()?.legal?.registration_number" />
|
||||||
<app-key-value label="کد پستی" [value]="customer()?.legal?.postal_code" />
|
<app-key-value label="کد پستی" [value]="customer()?.legal?.postal_code" />
|
||||||
</div>
|
</div>
|
||||||
} @else if (customer()?.type === "INDIVIDUAL") {
|
} @else if (customer()?.type === 'INDIVIDUAL') {
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
<app-key-value label="نام" [value]="customer()?.individual?.first_name" />
|
<app-key-value label="نام" [value]="customer()?.individual?.first_name" />
|
||||||
<app-key-value label="نام خانوادگی" [value]="customer()?.individual?.last_name" />
|
<app-key-value label="نام خانوادگی" [value]="customer()?.individual?.last_name" />
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
<app-page-data-list
|
<app-page-data-list
|
||||||
pageTitle="آخرین صورتحسابهای صادر شده امروز"
|
pageTitle="صورتحسابهای امروز"
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
emptyPlaceholderTitle="تا به این لحظه صورتحسابی صادر نشده است."
|
emptyPlaceholderTitle="تا به این لحظه صورتحسابی صادر نشده است."
|
||||||
[items]="items()"
|
[items]="items()"
|
||||||
[showDetails]="true"
|
[showDetails]="true"
|
||||||
[loading]="loading()"
|
[loading]="loading()"
|
||||||
|
|||||||
+2
-23
@@ -2,6 +2,7 @@ import { consumerSaleInvoicesNamedRoutes } from '@/domains/consumer/modules/sale
|
|||||||
import { AbstractList } from '@/shared/abstractClasses';
|
import { AbstractList } from '@/shared/abstractClasses';
|
||||||
import { CatalogTaxProviderStatusTagComponent } from '@/shared/catalog';
|
import { CatalogTaxProviderStatusTagComponent } from '@/shared/catalog';
|
||||||
import { PageDataListComponent } from '@/shared/components/pageDataList/page-data-list.component';
|
import { PageDataListComponent } from '@/shared/components/pageDataList/page-data-list.component';
|
||||||
|
import { saleInvoiceListConfig } from '@/shared/constants/list-configs';
|
||||||
import { Component, inject, TemplateRef, ViewChild } from '@angular/core';
|
import { Component, inject, TemplateRef, ViewChild } from '@angular/core';
|
||||||
import { Router, RouterLink } from '@angular/router';
|
import { Router, RouterLink } from '@angular/router';
|
||||||
import { ButtonDirective } from 'primeng/button';
|
import { ButtonDirective } from 'primeng/button';
|
||||||
@@ -27,29 +28,7 @@ export class ConsumerStatisticsLatestInvoicesComponent extends AbstractList<ISta
|
|||||||
readonly invoicesPageRoute = consumerSaleInvoicesNamedRoutes.saleInvoices.meta.pagePath!();
|
readonly invoicesPageRoute = consumerSaleInvoicesNamedRoutes.saleInvoices.meta.pagePath!();
|
||||||
|
|
||||||
override setColumns(): void {
|
override setColumns(): void {
|
||||||
this.columns = [
|
this.columns = saleInvoiceListConfig.columns.filter((column) => column.field !== 'created_at');
|
||||||
{ field: 'code', header: 'کد پیگیری' },
|
|
||||||
{ field: 'total_amount', header: 'قیمت نهایی', type: 'price' },
|
|
||||||
{
|
|
||||||
field: 'pos',
|
|
||||||
header: 'پایانه',
|
|
||||||
customDataModel(item) {
|
|
||||||
return `${item.pos.name} - ${item.pos.complex.name} - ${item.pos.complex.business_activity.name}`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'consumer_account',
|
|
||||||
header: 'ایجاد شده توسط',
|
|
||||||
type: 'nested',
|
|
||||||
nestedOption: { path: 'consumer_account.account.username' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'invoice_date',
|
|
||||||
header: 'تاریخ صورتحساب',
|
|
||||||
type: 'dateTime',
|
|
||||||
},
|
|
||||||
{ field: 'status', header: 'وضعیت صدور', customDataModel: this.status },
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override getDataRequest() {
|
override getDataRequest() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<app-page-data-list
|
<app-page-data-list
|
||||||
pageTitle="لیست پایانههای فروش"
|
pageTitle="پایانههای فروش"
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
emptyPlaceholderTitle="پایانه فروشی یافت نشد."
|
emptyPlaceholderTitle="پایانه فروشی یافت نشد."
|
||||||
[items]="items()"
|
[items]="items()"
|
||||||
@@ -8,8 +8,7 @@
|
|||||||
[showEdit]="true"
|
[showEdit]="true"
|
||||||
(onEdit)="onEditClick($event)"
|
(onEdit)="onEditClick($event)"
|
||||||
(onDetails)="toSinglePage($event)"
|
(onDetails)="toSinglePage($event)"
|
||||||
(onRefresh)="refresh()"
|
(onRefresh)="refresh()">
|
||||||
>
|
|
||||||
<ng-template #toPosLandingAction let-item>
|
<ng-template #toPosLandingAction let-item>
|
||||||
<p-button type="button" variant="outlined" (onClick)="toPosLanding(item.id)"> ورود به پایانه </p-button>
|
<p-button type="button" variant="outlined" (onClick)="toPosLanding(item.id)"> ورود به پایانه </p-button>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@@ -19,5 +18,4 @@
|
|||||||
[editMode]="editMode()"
|
[editMode]="editMode()"
|
||||||
[posId]="selectedItemForEdit()?.id || ''"
|
[posId]="selectedItemForEdit()?.id || ''"
|
||||||
[initialValues]="selectedItemForEdit() || undefined"
|
[initialValues]="selectedItemForEdit() || undefined"
|
||||||
(onSubmit)="refresh()"
|
(onSubmit)="refresh()" />
|
||||||
/>
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات پایانه فروش" [editable]="true" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات پایانه فروش" [editable]="true" [(editMode)]="editMode">
|
||||||
<ng-template #moreActions>
|
<ng-template #moreActions>
|
||||||
<p-button type="button" variant="outlined" size="small" (onClick)="toPosLanding()"> ورود به پایانه </p-button>
|
<p-button type="button" variant="outlined" size="small" (onClick)="toPosLanding()"> ورود به پایانه </p-button>
|
||||||
@@ -20,6 +20,5 @@
|
|||||||
[editMode]="true"
|
[editMode]="true"
|
||||||
[posId]="posId()"
|
[posId]="posId()"
|
||||||
[initialValues]="pos() || undefined"
|
[initialValues]="pos() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -44,12 +44,17 @@ export class ConsumerPosPageComponent {
|
|||||||
|
|
||||||
toPosLanding() {
|
toPosLanding() {
|
||||||
this.cookieService.set(COOKIE_KEYS.POS_ID, '', new Date());
|
this.cookieService.set(COOKIE_KEYS.POS_ID, '', new Date());
|
||||||
|
|
||||||
|
console.log('COOKIE_KEYS.POS_ID', COOKIE_KEYS.POS_ID);
|
||||||
|
|
||||||
this.cookieService.set(COOKIE_KEYS.POS_ID, this.posId(), {
|
this.cookieService.set(COOKIE_KEYS.POS_ID, this.posId(), {
|
||||||
sameSite: 'Lax', // or 'Strict' for same-site requests only
|
sameSite: 'Lax', // or 'Strict' for same-site requests only
|
||||||
secure: false,
|
secure: false,
|
||||||
path: '/',
|
path: '/',
|
||||||
domain: 'localhost',
|
domain: window.location.hostname,
|
||||||
});
|
});
|
||||||
|
console.log('this.posId', this.posId());
|
||||||
|
|
||||||
window.open('/pos', '_blank');
|
window.open('/pos', '_blank');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<app-page-data-list
|
<app-page-data-list
|
||||||
[pageTitle]="'صورتحسابها'"
|
[pageTitle]="'صورتحسابها'"
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
emptyPlaceholderTitle="صورتحسابی یافت نشد"
|
emptyPlaceholderTitle="صورتحسابی یافت نشد"
|
||||||
[items]="items()"
|
[items]="items()"
|
||||||
[loading]="loading()"
|
[loading]="loading()"
|
||||||
[perPage]="responseMetaData()?.perPage"
|
[perPage]="responseMetaData()?.perPage"
|
||||||
@@ -10,4 +10,8 @@
|
|||||||
[showDetails]="true"
|
[showDetails]="true"
|
||||||
(onDetails)="toSinglePage($event)"
|
(onDetails)="toSinglePage($event)"
|
||||||
(onRefresh)="refresh()"
|
(onRefresh)="refresh()"
|
||||||
(onChangePage)="changePage($event)" />
|
(onChangePage)="changePage($event)">
|
||||||
|
<ng-template #status let-item>
|
||||||
|
<catalog-tax-provider-status-tag [status]="item.status.value" [translate]="item.status.translate" />
|
||||||
|
</ng-template>
|
||||||
|
</app-page-data-list>
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
// import { CatalogRoleTagComponent } from '@/shared/catalog/roles';
|
// import { CatalogRoleTagComponent } from '@/shared/catalog/roles';
|
||||||
import { Maybe } from '@/core';
|
import { Maybe } from '@/core';
|
||||||
|
import { IPaginatedQuery } from '@/core/models/service.model';
|
||||||
import { AbstractList } from '@/shared/abstractClasses/abstract-list';
|
import { AbstractList } from '@/shared/abstractClasses/abstract-list';
|
||||||
|
import { CatalogTaxProviderStatusTagComponent } from '@/shared/catalog';
|
||||||
import {
|
import {
|
||||||
IColumn,
|
IColumn,
|
||||||
PageDataListComponent,
|
PageDataListComponent,
|
||||||
} from '@/shared/components/pageDataList/page-data-list.component';
|
} from '@/shared/components/pageDataList/page-data-list.component';
|
||||||
import { IPaginatedQuery } from '@/core/models/service.model';
|
|
||||||
import { saleInvoiceListConfig } from '@/shared/constants/list-configs';
|
import { saleInvoiceListConfig } from '@/shared/constants/list-configs';
|
||||||
import { Component, inject, Input } from '@angular/core';
|
import { Component, inject, Input, TemplateRef, ViewChild } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { consumerSaleInvoicesNamedRoutes } from '../constants/routes';
|
import { consumerSaleInvoicesNamedRoutes } from '../constants/routes';
|
||||||
import { IConsumerSaleInvoicesResponse } from '../models';
|
import { IConsumerSaleInvoicesResponse } from '../models';
|
||||||
@@ -16,7 +17,7 @@ import { ConsumerSaleInvoicesService } from '../services/main.service';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'consumer-saleInvoice-list',
|
selector: 'consumer-saleInvoice-list',
|
||||||
templateUrl: './list.component.html',
|
templateUrl: './list.component.html',
|
||||||
imports: [PageDataListComponent],
|
imports: [PageDataListComponent, CatalogTaxProviderStatusTagComponent],
|
||||||
})
|
})
|
||||||
export class ConsumerSaleInvoiceListComponent extends AbstractList<
|
export class ConsumerSaleInvoiceListComponent extends AbstractList<
|
||||||
IConsumerSaleInvoicesResponse,
|
IConsumerSaleInvoicesResponse,
|
||||||
@@ -24,12 +25,21 @@ export class ConsumerSaleInvoiceListComponent extends AbstractList<
|
|||||||
> {
|
> {
|
||||||
@Input() fullHeight?: boolean;
|
@Input() fullHeight?: boolean;
|
||||||
@Input() header: IColumn[] = saleInvoiceListConfig.columns;
|
@Input() header: IColumn[] = saleInvoiceListConfig.columns;
|
||||||
|
@ViewChild('status', { static: true }) status!: TemplateRef<any>;
|
||||||
|
|
||||||
private readonly service = inject(ConsumerSaleInvoicesService);
|
private readonly service = inject(ConsumerSaleInvoicesService);
|
||||||
private readonly router = inject(Router);
|
private readonly router = inject(Router);
|
||||||
|
|
||||||
override setColumns(): void {
|
override setColumns(): void {
|
||||||
this.columns = this.header;
|
this.columns = this.header.map((header) => {
|
||||||
|
if (header.field === 'status') {
|
||||||
|
return {
|
||||||
|
...header,
|
||||||
|
customDataModel: this.status,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return header;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
override getDataRequest(payload: Maybe<IPaginatedQuery>) {
|
override getDataRequest(payload: Maybe<IPaginatedQuery>) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const consumerSaleInvoicesNamedRoutes: NamedRoutes<TConsumerSaleInvoicesR
|
|||||||
loadComponent: () =>
|
loadComponent: () =>
|
||||||
import('../../views/list.component').then((m) => m.ConsumerSaleInvoicesComponent),
|
import('../../views/list.component').then((m) => m.ConsumerSaleInvoicesComponent),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'صورتحسابهای صادر شده',
|
title: 'صورتحسابها',
|
||||||
pagePath: () => `/consumer/sale_invoices`,
|
pagePath: () => `/consumer/sale_invoices`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -18,7 +18,7 @@ export const consumerSaleInvoicesNamedRoutes: NamedRoutes<TConsumerSaleInvoicesR
|
|||||||
loadComponent: () =>
|
loadComponent: () =>
|
||||||
import('../../views/single.component').then((m) => m.ConsumerSaleInvoiceComponent),
|
import('../../views/single.component').then((m) => m.ConsumerSaleInvoiceComponent),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'صورتحساب صادر شده',
|
title: 'صورتحساب',
|
||||||
pagePath: (saleInvoiceId: string) => `/consumer/sale_invoices/${saleInvoiceId}`,
|
pagePath: (saleInvoiceId: string) => `/consumer/sale_invoices/${saleInvoiceId}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات کاربری" [editable]="false" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات کاربری" [editable]="false" [(editMode)]="editMode">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
||||||
<field-name [control]="form.controls.name" />
|
<field-name [control]="form.controls.name" />
|
||||||
<field-pos-type [control]="form.controls.pos_type" />
|
<!-- <field-pos-type [control]="form.controls.pos_type" /> -->
|
||||||
|
|
||||||
@if (form.controls.pos_type.value === "PSP") {
|
@if (form.controls.pos_type.value === 'PSP') {
|
||||||
<field-serial-number [control]="form.controls.serial_number" />
|
<field-serial-number [control]="form.controls.serial_number" />
|
||||||
<field-device-id [control]="form.controls.device_id" />
|
<field-device-id [control]="form.controls.device_id" />
|
||||||
<field-provider-id [control]="form.controls.provider_id" />
|
<field-provider-id [control]="form.controls.provider_id" />
|
||||||
@@ -13,8 +13,7 @@
|
|||||||
<field-username [control]="form.controls.username" />
|
<field-username [control]="form.controls.username" />
|
||||||
<shared-password-input
|
<shared-password-input
|
||||||
[passwordControl]="form.controls.password"
|
[passwordControl]="form.controls.password"
|
||||||
[confirmPasswordControl]="form.controls.confirmPassword"
|
[confirmPasswordControl]="form.controls.confirmPassword" />
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" />
|
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" />
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { AbstractForm } from '@/shared/abstractClasses';
|
|||||||
import {
|
import {
|
||||||
DeviceIdComponent,
|
DeviceIdComponent,
|
||||||
NameComponent,
|
NameComponent,
|
||||||
PosTypeComponent,
|
|
||||||
ProviderIdComponent,
|
ProviderIdComponent,
|
||||||
SerialNumberComponent,
|
SerialNumberComponent,
|
||||||
SharedPasswordInputComponent,
|
SharedPasswordInputComponent,
|
||||||
@@ -27,7 +26,6 @@ import { PartnerPosesService } from '../../services/poses.service';
|
|||||||
FormFooterActionsComponent,
|
FormFooterActionsComponent,
|
||||||
DeviceIdComponent,
|
DeviceIdComponent,
|
||||||
ProviderIdComponent,
|
ProviderIdComponent,
|
||||||
PosTypeComponent,
|
|
||||||
SerialNumberComponent,
|
SerialNumberComponent,
|
||||||
UsernameComponent,
|
UsernameComponent,
|
||||||
Divider,
|
Divider,
|
||||||
@@ -45,7 +43,7 @@ export class ConsumerPosFormContentComponent extends AbstractForm<IPosRequest, I
|
|||||||
initForm = () => {
|
initForm = () => {
|
||||||
const form = this.fb.group({
|
const form = this.fb.group({
|
||||||
name: fieldControl.name(this.initialValues?.name || ''),
|
name: fieldControl.name(this.initialValues?.name || ''),
|
||||||
pos_type: fieldControl.pos_type(this.initialValues?.pos_type || ''),
|
pos_type: fieldControl.pos_type(this.initialValues?.pos_type || 'PSP'),
|
||||||
serial_number: fieldControl.serial_number(this.initialValues?.serial_number || ''),
|
serial_number: fieldControl.serial_number(this.initialValues?.serial_number || ''),
|
||||||
device_id: fieldControl.device_id(this.initialValues?.device?.id || ''),
|
device_id: fieldControl.device_id(this.initialValues?.device?.id || ''),
|
||||||
provider_id: fieldControl.provider_id(this.initialValues?.provider?.id || ''),
|
provider_id: fieldControl.provider_id(this.initialValues?.provider?.id || ''),
|
||||||
|
|||||||
+3
-5
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات فعالیت اقتصادی" [editable]="true" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات فعالیت اقتصادی" [editable]="true" [(editMode)]="editMode">
|
||||||
<ng-template #moreActions>
|
<ng-template #moreActions>
|
||||||
<button pButton outlined size="small" (click)="showAccountsChargeDialog()">شارژ کاربر</button>
|
<button pButton outlined size="small" (click)="showAccountsChargeDialog()">شارژ کاربر</button>
|
||||||
@@ -22,13 +22,11 @@
|
|||||||
[consumerId]="consumerId()"
|
[consumerId]="consumerId()"
|
||||||
[businessActivityId]="businessId()"
|
[businessActivityId]="businessId()"
|
||||||
[initialValues]="businessActivity() || undefined"
|
[initialValues]="businessActivity() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
<partner-charge-account-form-dialog
|
<partner-charge-account-form-dialog
|
||||||
[(visible)]="visibleAccountsChargeForm"
|
[(visible)]="visibleAccountsChargeForm"
|
||||||
[consumerId]="consumerId()"
|
[consumerId]="consumerId()"
|
||||||
[businessId]="businessId()"
|
[businessId]="businessId()"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()">
|
||||||
>
|
|
||||||
</partner-charge-account-form-dialog>
|
</partner-charge-account-form-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات شعبه" [editable]="true" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات شعبه" [editable]="true" [(editMode)]="editMode">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
@@ -18,6 +18,5 @@
|
|||||||
[businessActivityId]="businessId()"
|
[businessActivityId]="businessId()"
|
||||||
[complexId]="complexId()"
|
[complexId]="complexId()"
|
||||||
[initialValues]="complex() || undefined"
|
[initialValues]="complex() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<app-page-data-list
|
<app-page-data-list
|
||||||
pageTitle="لیست مشتری"
|
pageTitle="مشتریها"
|
||||||
[addNewCtaLabel]="'افزودن مشتری'"
|
[addNewCtaLabel]="'افزودن مشتری'"
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
[showAdd]="true"
|
[showAdd]="true"
|
||||||
@@ -13,8 +13,7 @@
|
|||||||
(onAdd)="openAddForm()"
|
(onAdd)="openAddForm()"
|
||||||
(onDetails)="toSinglePage($event)"
|
(onDetails)="toSinglePage($event)"
|
||||||
(onEdit)="onEditClick($event)"
|
(onEdit)="onEditClick($event)"
|
||||||
(onRefresh)="refresh()"
|
(onRefresh)="refresh()" />
|
||||||
/>
|
|
||||||
<partner-create-consumer-wrapper [(visible)]="visibleCreateForm" (onSubmit)="refresh()" />
|
<partner-create-consumer-wrapper [(visible)]="visibleCreateForm" (onSubmit)="refresh()" />
|
||||||
|
|
||||||
<partner-consumer-form
|
<partner-consumer-form
|
||||||
@@ -22,5 +21,4 @@
|
|||||||
[editMode]="true"
|
[editMode]="true"
|
||||||
[consumerId]="selectedItemForEdit()?.id"
|
[consumerId]="selectedItemForEdit()?.id"
|
||||||
[initialValues]="selectedItemForEdit() || undefined"
|
[initialValues]="selectedItemForEdit() || undefined"
|
||||||
(onSubmit)="refresh()"
|
(onSubmit)="refresh()" />
|
||||||
/>
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات پایانه فروش" [editable]="true" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات پایانه فروش" [editable]="true" [(editMode)]="editMode">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
@@ -15,6 +15,5 @@
|
|||||||
[complexId]="complexId()"
|
[complexId]="complexId()"
|
||||||
[posId]="posId()"
|
[posId]="posId()"
|
||||||
[initialValues]="pos() || undefined"
|
[initialValues]="pos() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات مشتری" [editable]="true" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات مشتری" [editable]="true" [(editMode)]="editMode">
|
||||||
<ng-template #moreActions> </ng-template>
|
<ng-template #moreActions> </ng-template>
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
<app-key-value label="نام مشتری" [value]="consumer()?.name" />
|
<app-key-value label="نام مشتری" [value]="consumer()?.name" />
|
||||||
<app-key-value label="نوع مشتری" [value]="consumer()?.type?.translate" />
|
<app-key-value label="نوع مشتری" [value]="consumer()?.type?.translate" />
|
||||||
@if (consumer()?.type?.value === "LEGAL") {
|
@if (consumer()?.type?.value === 'LEGAL') {
|
||||||
<app-key-value label="شناسه ملی" [value]="consumer()?.legal?.registration_code" />
|
<app-key-value label="شناسه ملی" [value]="consumer()?.legal?.registration_code" />
|
||||||
} @else {
|
} @else {
|
||||||
<app-key-value label="شماره موبایل" [value]="consumer()?.individual?.mobile_number" />
|
<app-key-value label="شماره موبایل" [value]="consumer()?.individual?.mobile_number" />
|
||||||
@@ -28,6 +28,5 @@
|
|||||||
[editMode]="true"
|
[editMode]="true"
|
||||||
[consumerId]="consumerId()"
|
[consumerId]="consumerId()"
|
||||||
[initialValues]="consumer() || undefined"
|
[initialValues]="consumer() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<app-page-data-list
|
<app-page-data-list
|
||||||
[pageTitle]="'لیست مشتری'"
|
[pageTitle]="'مشتریها'"
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
emptyPlaceholderTitle="مشتری یافت نشد"
|
emptyPlaceholderTitle="مشتری یافت نشد"
|
||||||
[items]="items()"
|
[items]="items()"
|
||||||
@@ -8,5 +8,4 @@
|
|||||||
[showDetails]="true"
|
[showDetails]="true"
|
||||||
(onEdit)="onEditClick($event)"
|
(onEdit)="onEditClick($event)"
|
||||||
(onDetails)="toSinglePage($event)"
|
(onDetails)="toSinglePage($event)"
|
||||||
(onRefresh)="refresh()"
|
(onRefresh)="refresh()" />
|
||||||
/>
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات مشتری" [editable]="true" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات مشتری" [editable]="true" [(editMode)]="editMode">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
|
|||||||
@@ -1 +1,5 @@
|
|||||||
<shared-change-password-form-dialog [(visible)]="visible" [loading]="submitLoading()" (onSubmit)="submit($event)" />
|
<shared-change-password-form-dialog
|
||||||
|
[(visible)]="visible"
|
||||||
|
[showCurrentPasswordField]="true"
|
||||||
|
[loading]="submitLoading()"
|
||||||
|
(onSubmit)="submit($event)" />
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export class PosChangePasswordComponent extends AbstractDialog {
|
|||||||
this.submitLoading.set(true);
|
this.submitLoading.set(true);
|
||||||
|
|
||||||
this.service
|
this.service
|
||||||
.changePassword(payload.password)
|
.changePassword(payload)
|
||||||
.pipe(finalize(() => this.submitLoading.set(false)))
|
.pipe(finalize(() => this.submitLoading.set(false)))
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.toastService.success({
|
this.toastService.success({
|
||||||
|
|||||||
@@ -11,22 +11,17 @@
|
|||||||
<app-checkbox
|
<app-checkbox
|
||||||
[control]="form.controls.customer_national_id"
|
[control]="form.controls.customer_national_id"
|
||||||
name="customer_national_id"
|
name="customer_national_id"
|
||||||
label="نمایش کد ملی خریدار"
|
label="نمایش کد ملی خریدار" />
|
||||||
/>
|
|
||||||
<app-checkbox
|
<app-checkbox
|
||||||
[control]="form.controls.customer_postal_code"
|
[control]="form.controls.customer_postal_code"
|
||||||
name="customer_postal_code"
|
name="customer_postal_code"
|
||||||
label="نمایش کد پستی خریدار"
|
label="نمایش کد پستی خریدار" />
|
||||||
/>
|
|
||||||
<app-checkbox
|
<app-checkbox
|
||||||
[control]="form.controls.customer_economic_code"
|
[control]="form.controls.customer_economic_code"
|
||||||
name="customer_economic_code"
|
name="customer_economic_code"
|
||||||
label="نمایش شناسهملی / اقتصادی خریدار"
|
label="نمایش شناسهملی / اقتصادی خریدار" />
|
||||||
/>
|
|
||||||
<app-checkbox [control]="form.controls.payment_type" name="payment_type" label="نمایش نوع پرداخت" />
|
<app-checkbox [control]="form.controls.payment_type" name="payment_type" label="نمایش نوع پرداخت" />
|
||||||
<app-checkbox [control]="form.controls.show_payment_info" name="show_payment_info" label="نمایش جزییات پرداخت" />
|
<app-checkbox [control]="form.controls.show_payment_info" name="show_payment_info" label="نمایش جزییات پرداخت" />
|
||||||
<app-checkbox [control]="form.controls.show_items" name="show_items" label="نمایش کالاهای خریداری شده" />
|
<app-checkbox [control]="form.controls.show_items" name="show_items" label="نمایش کالاهای خریداری شده" />
|
||||||
|
|
||||||
<app-form-footer-actions (onCancel)="close()" />
|
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { AbstractForm } from '@/shared/abstractClasses';
|
import { AbstractForm } from '@/shared/abstractClasses';
|
||||||
import { AppCheckboxComponent } from '@/shared/components/checkbox/checkbox.component';
|
import { AppCheckboxComponent } from '@/shared/components/checkbox/checkbox.component';
|
||||||
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
|
||||||
import { Component, inject, signal } from '@angular/core';
|
import { Component, inject, signal } from '@angular/core';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
import { IPosConfigPrintRequestPayload, IPosConfigPrintResponse } from './models';
|
import { IPosConfigPrintRequestPayload, IPosConfigPrintResponse } from './models';
|
||||||
@@ -9,7 +8,7 @@ import { PosConfigPrintService } from './services/main.service';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'pos-config-print-form',
|
selector: 'pos-config-print-form',
|
||||||
templateUrl: 'form.component.html',
|
templateUrl: 'form.component.html',
|
||||||
imports: [ReactiveFormsModule, AppCheckboxComponent, FormFooterActionsComponent],
|
imports: [ReactiveFormsModule, AppCheckboxComponent],
|
||||||
})
|
})
|
||||||
export class PosConfigPrintFormComponent extends AbstractForm<
|
export class PosConfigPrintFormComponent extends AbstractForm<
|
||||||
IPosConfigPrintRequestPayload,
|
IPosConfigPrintRequestPayload,
|
||||||
@@ -37,6 +36,10 @@ export class PosConfigPrintFormComponent extends AbstractForm<
|
|||||||
show_items: [false],
|
show_items: [false],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
form.valueChanges.subscribe(() => {
|
||||||
|
this.submitForm();
|
||||||
|
});
|
||||||
|
|
||||||
return form;
|
return form;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -52,7 +55,7 @@ export class PosConfigPrintFormComponent extends AbstractForm<
|
|||||||
|
|
||||||
override submitForm() {
|
override submitForm() {
|
||||||
const formValue = this.form.value as IPosConfigPrintRequestPayload;
|
const formValue = this.form.value as IPosConfigPrintRequestPayload;
|
||||||
this.toastService.success({ text: 'تغییرات با موفقیت اعمال شد.' });
|
// this.toastService.success({ text: 'تغییرات با موفقیت اعمال شد.' });
|
||||||
return this.service.submit(formValue);
|
return this.service.submit(formValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,17 +15,15 @@ export interface IPosConfigPrintRequestPayload {
|
|||||||
payment_type: boolean;
|
payment_type: boolean;
|
||||||
show_payment_info: boolean;
|
show_payment_info: boolean;
|
||||||
show_items: boolean;
|
show_items: boolean;
|
||||||
items: {
|
item_name: boolean;
|
||||||
name: boolean;
|
item_sku: boolean;
|
||||||
sku: boolean;
|
item_quantity: boolean;
|
||||||
quantity: boolean;
|
item_base_amount: boolean;
|
||||||
base_amount: boolean;
|
item_tax: boolean;
|
||||||
tax: boolean;
|
item_discount: boolean;
|
||||||
discount: boolean;
|
item_karat: boolean;
|
||||||
karat: boolean;
|
item_profit: boolean;
|
||||||
profit: boolean;
|
item_commission: boolean;
|
||||||
commission: boolean;
|
item_wage: boolean;
|
||||||
wage: boolean;
|
item_total_amount: boolean;
|
||||||
total_amount: boolean;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,12 @@ export class PosConfigPrintService {
|
|||||||
get(): IPosConfigPrintResponse {
|
get(): IPosConfigPrintResponse {
|
||||||
const data = window.localStorage.getItem(LOCAL_STORAGE_KEYS.POS_CONFIG_PRINT);
|
const data = window.localStorage.getItem(LOCAL_STORAGE_KEYS.POS_CONFIG_PRINT);
|
||||||
if (data) {
|
if (data) {
|
||||||
return JSON.parse(data) as IPosConfigPrintResponse;
|
const dataObject = JSON.parse(data) as Record<keyof IPosConfigPrintResponse, string>;
|
||||||
|
return Object.keys(dataObject).reduce((prev, curr) => {
|
||||||
|
const key = curr as keyof IPosConfigPrintResponse;
|
||||||
|
prev[key] = dataObject[key] === 'true';
|
||||||
|
return prev;
|
||||||
|
}, {} as IPosConfigPrintResponse);
|
||||||
}
|
}
|
||||||
const defaultData = {
|
const defaultData = {
|
||||||
business_name: true,
|
business_name: true,
|
||||||
@@ -23,25 +28,37 @@ export class PosConfigPrintService {
|
|||||||
customer_economic_code: true,
|
customer_economic_code: true,
|
||||||
payment_type: true,
|
payment_type: true,
|
||||||
show_payment_info: true,
|
show_payment_info: true,
|
||||||
show_items: false,
|
show_items: true,
|
||||||
items: {
|
|
||||||
name: false,
|
item_name: false,
|
||||||
sku: false,
|
item_sku: false,
|
||||||
quantity: false,
|
item_quantity: false,
|
||||||
base_amount: false,
|
item_base_amount: false,
|
||||||
tax: false,
|
item_tax: false,
|
||||||
discount: false,
|
item_discount: false,
|
||||||
karat: false,
|
item_karat: false,
|
||||||
profit: false,
|
item_profit: false,
|
||||||
commission: false,
|
item_commission: false,
|
||||||
wage: false,
|
item_wage: false,
|
||||||
total_amount: false,
|
item_total_amount: false,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
this.submit(defaultData);
|
this.submit(defaultData);
|
||||||
return defaultData;
|
return defaultData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getVisibleItems() {
|
||||||
|
const items = this.get();
|
||||||
|
return Object.keys(items).reduce((result, key) => {
|
||||||
|
const itemKey = key as keyof IPosConfigPrintRequestPayload;
|
||||||
|
|
||||||
|
if (items[itemKey]) {
|
||||||
|
result[itemKey] = items[itemKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}, {} as Partial<IPosConfigPrintRequestPayload>);
|
||||||
|
}
|
||||||
|
|
||||||
submit(data: IPosConfigPrintRequestPayload) {
|
submit(data: IPosConfigPrintRequestPayload) {
|
||||||
window.localStorage.setItem(LOCAL_STORAGE_KEYS.POS_CONFIG_PRINT, JSON.stringify(data));
|
window.localStorage.setItem(LOCAL_STORAGE_KEYS.POS_CONFIG_PRINT, JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<div class="bg-surface-card">
|
<div class="bg-surface-card">
|
||||||
<app-inner-pages-header pageTitle="صورتحسابهای صادر شده" [backRoute]="backRoute">
|
<app-inner-pages-header pageTitle="صورتحسابها" [backRoute]="backRoute">
|
||||||
<ng-template #actions>
|
<ng-template #actions>
|
||||||
<div class="flex gap-1">
|
<div class="flex gap-1">
|
||||||
<p-button
|
<p-button
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
}
|
}
|
||||||
} @else if (!items() || items().length === 0) {
|
} @else if (!items() || items().length === 0) {
|
||||||
<div class="col-span-1">
|
<div class="col-span-1">
|
||||||
<p class="text-muted-color text-center">صورتحسابی یافت نشد.</p>
|
<p class="text-muted-color text-center">صورتحسابی یافت نشد.</p>
|
||||||
</div>
|
</div>
|
||||||
} @else {
|
} @else {
|
||||||
@for (item of items(); track item.id) {
|
@for (item of items(); track item.id) {
|
||||||
|
|||||||
+10
-14
@@ -3,13 +3,14 @@ import { ToastService } from '@/core/services/toast.service';
|
|||||||
import { PosInfoStore } from '@/domains/pos/store';
|
import { PosInfoStore } from '@/domains/pos/store';
|
||||||
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
|
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
|
||||||
import { SharedLightBottomsheetComponent } from '@/shared/components/dialog/light-bottomsheet.component';
|
import { SharedLightBottomsheetComponent } from '@/shared/components/dialog/light-bottomsheet.component';
|
||||||
import { formatJalali } from '@/utils';
|
import { prepareInvoicePrintPayload } from '@/shared/components/invoices/prepare-print.util';
|
||||||
import { Component, computed, inject, Input, signal } from '@angular/core';
|
import { Component, computed, inject, Input, signal } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { QRCodeComponent } from 'angularx-qrcode';
|
import { QRCodeComponent } from 'angularx-qrcode';
|
||||||
import { ButtonDirective } from 'primeng/button';
|
import { ButtonDirective } from 'primeng/button';
|
||||||
import { finalize } from 'rxjs';
|
import { finalize } from 'rxjs';
|
||||||
import { posSaleInvoicesNamedRoutes } from '../../../saleInvoices/constants';
|
import { posSaleInvoicesNamedRoutes } from '../../../saleInvoices/constants';
|
||||||
|
import { PosConfigPrintService } from '../../../configs/components/print/services/main.service';
|
||||||
import { PosSaleInvoicesService } from '../../../saleInvoices/services/main.service';
|
import { PosSaleInvoicesService } from '../../../saleInvoices/services/main.service';
|
||||||
import { IPosOrderResponse } from '../../models';
|
import { IPosOrderResponse } from '../../models';
|
||||||
|
|
||||||
@@ -22,6 +23,7 @@ export class PosOrderSubmittedDialogComponent extends AbstractDialog {
|
|||||||
@Input({ required: true }) invoice!: IPosOrderResponse;
|
@Input({ required: true }) invoice!: IPosOrderResponse;
|
||||||
private readonly nativeBridgeService = inject(NativeBridgeService);
|
private readonly nativeBridgeService = inject(NativeBridgeService);
|
||||||
private readonly service = inject(PosSaleInvoicesService);
|
private readonly service = inject(PosSaleInvoicesService);
|
||||||
|
private readonly printConfigService = inject(PosConfigPrintService);
|
||||||
private readonly toastService = inject(ToastService);
|
private readonly toastService = inject(ToastService);
|
||||||
private readonly posInfoStore = inject(PosInfoStore);
|
private readonly posInfoStore = inject(PosInfoStore);
|
||||||
private readonly router = inject(Router);
|
private readonly router = inject(Router);
|
||||||
@@ -60,19 +62,13 @@ export class PosOrderSubmittedDialogComponent extends AbstractDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
printInvoice() {
|
printInvoice() {
|
||||||
const printResult = this.nativeBridgeService.print([
|
const mustPrintConfig = this.printConfigService.getVisibleItems();
|
||||||
{
|
const printItems = prepareInvoicePrintPayload(this.invoice, mustPrintConfig, this.posName());
|
||||||
title: `فروشگاه ${this.posName()}`,
|
if (!printItems?.length) {
|
||||||
items: [
|
this.toastService.warn({ text: 'اطلاعات کافی برای چاپ صورتحساب وجود ندارد.' });
|
||||||
{
|
return;
|
||||||
label: 'شماره صورتحساب',
|
}
|
||||||
value: this.invoice.code,
|
this.nativeBridgeService.print(printItems);
|
||||||
},
|
|
||||||
{ label: 'تاریخ', value: formatJalali(this.invoice.invoice_date, 'YYYY/MM/DD') },
|
|
||||||
{ label: 'مبلغ کل', value: this.invoice.total_amount },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sendToTsp() {}
|
sendToTsp() {}
|
||||||
|
|||||||
@@ -2,13 +2,18 @@ import { HttpClient } from '@angular/common/http';
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
interface IChangePasswordSubmitPayload {
|
||||||
|
currentPassword: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class PosChangePasswordService {
|
export class PosChangePasswordService {
|
||||||
constructor(private readonly http: HttpClient) {}
|
constructor(private readonly http: HttpClient) {}
|
||||||
|
|
||||||
changePassword(password: string): Observable<unknown> {
|
changePassword(payload: IChangePasswordSubmitPayload): Observable<unknown> {
|
||||||
return this.http.put('/api/v1/pos/update-password', { password });
|
return this.http.put('/api/v1/pos/update-password', payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,13 @@
|
|||||||
[modal]="true"
|
[modal]="true"
|
||||||
[style]="{ width: '500px' }"
|
[style]="{ width: '500px' }"
|
||||||
[closable]="true"
|
[closable]="true"
|
||||||
(onHide)="close()"
|
(onHide)="close()">
|
||||||
>
|
|
||||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
||||||
<field-name [control]="form.controls.name" />
|
<field-name [control]="form.controls.name" />
|
||||||
<field-serial-number [control]="form.controls.serial_number" />
|
<field-serial-number [control]="form.controls.serial_number" />
|
||||||
<!-- <app-input label="مدل دستگاه" [control]="form.controls.model" name="model" /> -->
|
<!-- <app-input label="مدل دستگاه" [control]="form.controls.model" name="model" /> -->
|
||||||
<field-pos-type [control]="form.controls.pos_type" />
|
<!-- <field-pos-type [control]="form.controls.pos_type" /> -->
|
||||||
@if (form.controls.pos_type.value === "PSP") {
|
@if (form.controls.pos_type.value === 'PSP') {
|
||||||
<field-device-id [control]="form.controls.device_id" />
|
<field-device-id [control]="form.controls.device_id" />
|
||||||
<field-provider-id [control]="form.controls.provider_id" />
|
<field-provider-id [control]="form.controls.provider_id" />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { AbstractFormDialog } from '@/shared/abstractClasses';
|
|||||||
import {
|
import {
|
||||||
DeviceIdComponent,
|
DeviceIdComponent,
|
||||||
NameComponent,
|
NameComponent,
|
||||||
PosTypeComponent,
|
|
||||||
ProviderIdComponent,
|
ProviderIdComponent,
|
||||||
SerialNumberComponent,
|
SerialNumberComponent,
|
||||||
} from '@/shared/components';
|
} from '@/shared/components';
|
||||||
@@ -25,7 +24,6 @@ import { AdminPosesService } from '../../services/poses.service';
|
|||||||
FormFooterActionsComponent,
|
FormFooterActionsComponent,
|
||||||
DeviceIdComponent,
|
DeviceIdComponent,
|
||||||
ProviderIdComponent,
|
ProviderIdComponent,
|
||||||
PosTypeComponent,
|
|
||||||
SerialNumberComponent,
|
SerialNumberComponent,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
@@ -42,7 +40,7 @@ export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IP
|
|||||||
name: fieldControl.name(this.initialValues?.name || ''),
|
name: fieldControl.name(this.initialValues?.name || ''),
|
||||||
serial_number: fieldControl.serial_number(this.initialValues?.serial_number || '', true),
|
serial_number: fieldControl.serial_number(this.initialValues?.serial_number || '', true),
|
||||||
// model: [this.initialValues?.model || '', [Validators.required]],
|
// model: [this.initialValues?.model || '', [Validators.required]],
|
||||||
pos_type: fieldControl.pos_type(this.initialValues?.pos_type || ''),
|
pos_type: fieldControl.pos_type(this.initialValues?.pos_type || 'PSP'),
|
||||||
device_id: fieldControl.device_id(this.initialValues?.device?.id || ''),
|
device_id: fieldControl.device_id(this.initialValues?.device?.id || ''),
|
||||||
provider_id: fieldControl.provider_id(this.initialValues?.provider?.id || ''),
|
provider_id: fieldControl.provider_id(this.initialValues?.provider?.id || ''),
|
||||||
});
|
});
|
||||||
@@ -54,7 +52,7 @@ export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IP
|
|||||||
this.fb.control<string>(this.initialValues?.device?.id ?? '', {
|
this.fb.control<string>(this.initialValues?.device?.id ?? '', {
|
||||||
nonNullable: true,
|
nonNullable: true,
|
||||||
validators: fieldControl.device_id('', true)[1],
|
validators: fieldControl.device_id('', true)[1],
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
form.addControl(
|
form.addControl(
|
||||||
@@ -62,7 +60,7 @@ export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IP
|
|||||||
this.fb.control<string>(this.initialValues?.provider?.id ?? '', {
|
this.fb.control<string>(this.initialValues?.provider?.id ?? '', {
|
||||||
nonNullable: true,
|
nonNullable: true,
|
||||||
validators: fieldControl.provider_id('', true)[1],
|
validators: fieldControl.provider_id('', true)[1],
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
<app-page-data-list
|
<app-page-data-list
|
||||||
pageTitle="لیست پایانههای فروش"
|
pageTitle="پایانههای فروش"
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
emptyPlaceholderTitle="پایانه فروشی یافت نشد."
|
emptyPlaceholderTitle="پایانه فروشی یافت نشد."
|
||||||
[items]="items()"
|
[items]="items()"
|
||||||
[loading]="loading()"
|
[loading]="loading()"
|
||||||
[showDetails]="true"
|
[showDetails]="true"
|
||||||
(onDetails)="toSinglePage($event)"
|
(onDetails)="toSinglePage($event)"
|
||||||
(onRefresh)="refresh()"
|
(onRefresh)="refresh()">
|
||||||
>
|
|
||||||
</app-page-data-list>
|
</app-page-data-list>
|
||||||
<superAdmin-consumer-pos-form
|
<superAdmin-consumer-pos-form
|
||||||
[(visible)]="visibleForm"
|
[(visible)]="visibleForm"
|
||||||
@@ -17,5 +16,4 @@
|
|||||||
[complexId]="complexId"
|
[complexId]="complexId"
|
||||||
[posId]="selectedItemForEdit()?.id || ''"
|
[posId]="selectedItemForEdit()?.id || ''"
|
||||||
[initialValues]="selectedItemForEdit() || undefined"
|
[initialValues]="selectedItemForEdit() || undefined"
|
||||||
(onSubmit)="refresh()"
|
(onSubmit)="refresh()" />
|
||||||
/>
|
|
||||||
|
|||||||
+2
-3
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات فعالیت اقتصادی" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات فعالیت اقتصادی" [(editMode)]="editMode">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
@@ -19,6 +19,5 @@
|
|||||||
[consumerId]="consumerId()"
|
[consumerId]="consumerId()"
|
||||||
[businessActivityId]="businessId()"
|
[businessActivityId]="businessId()"
|
||||||
[initialValues]="businessActivity() || undefined"
|
[initialValues]="businessActivity() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات شعبه" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات شعبه" [(editMode)]="editMode">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
@@ -18,6 +18,5 @@
|
|||||||
[businessActivityId]="businessId()"
|
[businessActivityId]="businessId()"
|
||||||
[complexId]="complexId()"
|
[complexId]="complexId()"
|
||||||
[initialValues]="complex() || undefined"
|
[initialValues]="complex() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات پایانه فروش" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات پایانه فروش" [(editMode)]="editMode">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
@@ -15,6 +15,5 @@
|
|||||||
[complexId]="complexId()"
|
[complexId]="complexId()"
|
||||||
[posId]="posId()"
|
[posId]="posId()"
|
||||||
[initialValues]="pos() || undefined"
|
[initialValues]="pos() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات مشتری" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات مشتری" [(editMode)]="editMode">
|
||||||
<ng-template #moreActions> </ng-template>
|
<ng-template #moreActions> </ng-template>
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
<app-key-value label="نام مشتری" [value]="consumer()?.name" />
|
<app-key-value label="نام مشتری" [value]="consumer()?.name" />
|
||||||
<app-key-value label="نوع مشتری" [value]="consumer()?.type?.translate" />
|
<app-key-value label="نوع مشتری" [value]="consumer()?.type?.translate" />
|
||||||
@if (consumer()?.type?.value === "LEGAL") {
|
@if (consumer()?.type?.value === 'LEGAL') {
|
||||||
<app-key-value label="شناسه ملی" [value]="consumer()?.legal?.registration_code" />
|
<app-key-value label="شناسه ملی" [value]="consumer()?.legal?.registration_code" />
|
||||||
} @else {
|
} @else {
|
||||||
<app-key-value label="شماره موبایل" [value]="consumer()?.individual?.mobile_number" />
|
<app-key-value label="شماره موبایل" [value]="consumer()?.individual?.mobile_number" />
|
||||||
@@ -28,6 +28,5 @@
|
|||||||
[editMode]="true"
|
[editMode]="true"
|
||||||
[consumerId]="consumerId()"
|
[consumerId]="consumerId()"
|
||||||
[initialValues]="consumer() || undefined"
|
[initialValues]="consumer() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات صنف" [editable]="true" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات صنف" [editable]="true" [(editMode)]="editMode">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
@@ -8,13 +8,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</app-card-data>
|
</app-card-data>
|
||||||
|
|
||||||
<div class="max-h-125 flex">
|
<div class="flex max-h-125">
|
||||||
<admin-guild-good-categories-list [guildId]="guildId()" [showAllBtn]="true" class="w-full" />
|
<admin-guild-good-categories-list [guildId]="guildId()" [showAllBtn]="true" class="w-full" />
|
||||||
</div>
|
</div>
|
||||||
<div class="max-h-125 flex">
|
<div class="flex max-h-125">
|
||||||
<admin-guild-goods-list [guildId]="guildId()" [showAllBtn]="true" class="w-full" />
|
<admin-guild-goods-list [guildId]="guildId()" [showAllBtn]="true" class="w-full" />
|
||||||
</div>
|
</div>
|
||||||
<div class="max-h-125 flex">
|
<div class="flex max-h-125">
|
||||||
<admin-guild-stock-keeping-units-list [guildId]="guildId()" class="w-full" />
|
<admin-guild-stock-keeping-units-list [guildId]="guildId()" class="w-full" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -23,6 +23,5 @@
|
|||||||
[editMode]="true"
|
[editMode]="true"
|
||||||
[guildId]="guildId()"
|
[guildId]="guildId()"
|
||||||
[initialValues]="guild() || undefined"
|
[initialValues]="guild() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات شریک تجاری" [editable]="true" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات شریک تجاری" [editable]="true" [(editMode)]="editMode">
|
||||||
<ng-template #moreActions>
|
<ng-template #moreActions>
|
||||||
<p-button outlined size="small" (onClick)="openChargeAccountDialog()"> شارژ کاربر </p-button>
|
<p-button outlined size="small" (onClick)="openChargeAccountDialog()"> شارژ کاربر </p-button>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<app-key-value label="عنوان" [value]="partner()?.name" />
|
<app-key-value label="عنوان" [value]="partner()?.name" />
|
||||||
<app-key-value label="کد" [value]="partner()?.code" />
|
<app-key-value label="کد" [value]="partner()?.code" />
|
||||||
|
|
||||||
<div class="col-span-3 grid grid-cols-3 gap-4 mt-6">
|
<div class="col-span-3 mt-6 grid grid-cols-3 gap-4">
|
||||||
<partner-license-info-template
|
<partner-license-info-template
|
||||||
title="لایسنسها"
|
title="لایسنسها"
|
||||||
[total]="partner()?.licenses_status?.total || 0"
|
[total]="partner()?.licenses_status?.total || 0"
|
||||||
@@ -19,8 +19,7 @@
|
|||||||
(partner()?.licenses_status?.total || 0) -
|
(partner()?.licenses_status?.total || 0) -
|
||||||
(partner()?.licenses_status?.used || 0) -
|
(partner()?.licenses_status?.used || 0) -
|
||||||
(partner()?.licenses_status?.expired || 0)
|
(partner()?.licenses_status?.expired || 0)
|
||||||
"
|
" />
|
||||||
/>
|
|
||||||
|
|
||||||
<partner-license-info-template
|
<partner-license-info-template
|
||||||
title="شارژ کاربران"
|
title="شارژ کاربران"
|
||||||
@@ -31,8 +30,7 @@
|
|||||||
(partner()?.account_quota_status?.total || 0) -
|
(partner()?.account_quota_status?.total || 0) -
|
||||||
(partner()?.account_quota_status?.used || 0) -
|
(partner()?.account_quota_status?.used || 0) -
|
||||||
(partner()?.account_quota_status?.expired || 0)
|
(partner()?.account_quota_status?.expired || 0)
|
||||||
"
|
" />
|
||||||
/>
|
|
||||||
|
|
||||||
<partner-license-info-template
|
<partner-license-info-template
|
||||||
title="تمدید لایسنسها"
|
title="تمدید لایسنسها"
|
||||||
@@ -43,8 +41,7 @@
|
|||||||
(partner()?.license_renew_status?.total || 0) -
|
(partner()?.license_renew_status?.total || 0) -
|
||||||
(partner()?.license_renew_status?.used || 0) -
|
(partner()?.license_renew_status?.used || 0) -
|
||||||
(partner()?.license_renew_status?.expired || 0)
|
(partner()?.license_renew_status?.expired || 0)
|
||||||
"
|
" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<!--
|
<!--
|
||||||
<p-divider align="center" class="col-span-3">اطلاعات لایسنسها</p-divider>
|
<p-divider align="center" class="col-span-3">اطلاعات لایسنسها</p-divider>
|
||||||
@@ -98,19 +95,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</app-card-data>
|
</app-card-data>
|
||||||
|
|
||||||
<div class="max-h-125 flex">
|
<div class="flex max-h-125">
|
||||||
<admin-partner-licenses [partnerId]="partnerId()" class="w-full" />
|
<admin-partner-licenses [partnerId]="partnerId()" class="w-full" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="max-h-125 flex">
|
<div class="flex max-h-125">
|
||||||
<admin-partner-chargeLicenseTransaction-list [partnerId]="partnerId()" class="w-full" />
|
<admin-partner-chargeLicenseTransaction-list [partnerId]="partnerId()" class="w-full" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="max-h-125 flex">
|
<div class="flex max-h-125">
|
||||||
<admin-partner-chargeAccount-list [partnerId]="partnerId()" class="w-full"></admin-partner-chargeAccount-list>
|
<admin-partner-chargeAccount-list [partnerId]="partnerId()" class="w-full"></admin-partner-chargeAccount-list>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="max-h-125 flex">
|
<div class="flex max-h-125">
|
||||||
<superAdmin-partner-account-list [partnerId]="partnerId()" class="w-full" />
|
<superAdmin-partner-account-list [partnerId]="partnerId()" class="w-full" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -120,17 +117,14 @@
|
|||||||
[editMode]="true"
|
[editMode]="true"
|
||||||
[partnerId]="partnerId()"
|
[partnerId]="partnerId()"
|
||||||
[initialValues]="partner() || undefined"
|
[initialValues]="partner() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
|
|
||||||
<partner-charge-license-form-dialog
|
<partner-charge-license-form-dialog
|
||||||
[(visible)]="visibleChargeFormDialog"
|
[(visible)]="visibleChargeFormDialog"
|
||||||
[partnerId]="partnerId()"
|
[partnerId]="partnerId()"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
|
|
||||||
<admin-partner-charge-account-form-dialog
|
<admin-partner-charge-account-form-dialog
|
||||||
[(visible)]="visibleChargeAccountFormDialog"
|
[(visible)]="visibleChargeAccountFormDialog"
|
||||||
[partnerId]="partnerId()"
|
[partnerId]="partnerId()"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()"></admin-partner-charge-account-form-dialog>
|
||||||
></admin-partner-charge-account-form-dialog>
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-4">
|
||||||
<app-card-data cardTitle="اطلاعات کاربر" [editable]="true" [(editMode)]="editMode">
|
<app-card-data cardTitle="اطلاعات کاربر" [editable]="true" [(editMode)]="editMode">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="listKeyValue">
|
<div class="listKeyValue">
|
||||||
@@ -15,6 +15,5 @@
|
|||||||
[editMode]="true"
|
[editMode]="true"
|
||||||
[userId]="userId()"
|
[userId]="userId()"
|
||||||
[initialValues]="user() || undefined"
|
[initialValues]="user() || undefined"
|
||||||
(onSubmit)="getData()"
|
(onSubmit)="getData()" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
<app-sidebar></app-sidebar>
|
<app-sidebar></app-sidebar>
|
||||||
}
|
}
|
||||||
<div
|
<div
|
||||||
[class]="`flex flex-col justify-between ${!showMenu() ? 'hideMenu m0 ps-0' : ''} grow ${isFullPage ? 'isFullPage p-0 ps-0' : ''}`">
|
[class]="`layout-main-container p-4 ps-1 ${!showMenu() ? 'hideMenu' : ''} grow ${isFullPage ? 'isFullPage' : ''}`">
|
||||||
<div class="flex flex-1 flex-col gap-4">
|
<div class="layout-main flex flex-1 flex-col gap-4">
|
||||||
@if (showBreadcrumb) {
|
@if (showBreadcrumb) {
|
||||||
<app-breadcrumb class="shrink-0 overflow-hidden rounded-md" />
|
<app-breadcrumb class="shrink-0 overflow-hidden rounded-md" />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
<div class="layout-sidebar flex flex-col gap-4">
|
<div class="layout-sidebar">
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
<div class="grow">
|
<div class="grow">
|
||||||
<app-menu></app-menu>
|
<app-menu></app-menu>
|
||||||
</div>
|
</div>
|
||||||
<div class="shrink-0 sticky bottom-0">
|
<div class="sticky bottom-0 shrink-0">
|
||||||
<p-divider class="mb-1!" />
|
<p-divider class="mb-1!" />
|
||||||
<div class="py-2 w-full text-center flex items-center gap-2">
|
<div class="flex w-full items-center gap-2 py-2 text-center">
|
||||||
<div class="w-10 h-10">
|
<div class="h-10 w-10">
|
||||||
<img [src]="logo" alt="Logo" class="object-contain" />
|
<img [src]="logo" alt="Logo" class="object-contain" />
|
||||||
</div>
|
</div>
|
||||||
<span class="text-muted-color text-sm font-medium">مدیریت صورتحسابهای مالیاتی پاژن</span>
|
<span class="text-muted-color text-sm font-medium">مدیریت صورتحسابهای مالیاتی پاژن</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
<div class="min-h-dvh p-4">
|
<div class="min-h-dvh p-4">
|
||||||
<shared-sale-invoice-single-view [loading]="loading()" [invoice]="invoice()" />
|
<p-card class="mb-4">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span class="text-lg font-bold">صورتحساب شماره {{ invoice()?.invoice_number }}</span>
|
||||||
|
<button pButton type="button" icon="pi pi-share-alt" outlined (onClick)="share()"></button>
|
||||||
|
</div>
|
||||||
|
</p-card>
|
||||||
|
<shared-sale-invoice-single-info-card [loading]="loading()" [invoice]="invoice()" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import { SharedSaleInvoiceSingleViewComponent } from '@/shared/components/invoices/sale-invoice-single-view.component';
|
import { SaleInvoiceSingleInfoCardComponent } from '@/shared/components/invoices/sale-invoice-single-info-card.component';
|
||||||
import pageParamsUtils from '@/utils/page-params.utils';
|
import pageParamsUtils from '@/utils/page-params.utils';
|
||||||
import { Component, computed, inject, signal } from '@angular/core';
|
import { Component, computed, inject, signal } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { ButtonDirective } from 'primeng/button';
|
||||||
|
import { Card } from 'primeng/card';
|
||||||
import { PublicSaleInvoiceStore } from '../store/main.store';
|
import { PublicSaleInvoiceStore } from '../store/main.store';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'public-saleInvoice',
|
selector: 'public-saleInvoice',
|
||||||
templateUrl: './single.component.html',
|
templateUrl: './single.component.html',
|
||||||
imports: [SharedSaleInvoiceSingleViewComponent],
|
imports: [SaleInvoiceSingleInfoCardComponent, Card, ButtonDirective],
|
||||||
})
|
})
|
||||||
export class PublicSaleInvoiceComponent {
|
export class PublicSaleInvoiceComponent {
|
||||||
private readonly route = inject(ActivatedRoute);
|
private readonly route = inject(ActivatedRoute);
|
||||||
@@ -22,4 +24,14 @@ export class PublicSaleInvoiceComponent {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.store.getData(this.invoiceId());
|
this.store.getData(this.invoiceId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async share() {
|
||||||
|
if (navigator.share) {
|
||||||
|
await navigator.share({
|
||||||
|
title: window.document.title,
|
||||||
|
text: 'برای مشاهده صورتحساب اینجا کلیک کنید.',
|
||||||
|
url: window.location.href,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
IPaginatedResponse,
|
IPaginatedResponse,
|
||||||
IResponseMetadata,
|
IResponseMetadata,
|
||||||
} from '@/core/models/service.model';
|
} from '@/core/models/service.model';
|
||||||
import { Component, signal } from '@angular/core';
|
import { Component, Input, signal } from '@angular/core';
|
||||||
import { catchError, finalize, Observable } from 'rxjs';
|
import { catchError, finalize, Observable } from 'rxjs';
|
||||||
import { IColumn } from '../components/pageDataList/page-data-list.component';
|
import { IColumn } from '../components/pageDataList/page-data-list.component';
|
||||||
|
|
||||||
@@ -14,6 +14,8 @@ import { IColumn } from '../components/pageDataList/page-data-list.component';
|
|||||||
template: '',
|
template: '',
|
||||||
})
|
})
|
||||||
export abstract class AbstractList<ResponseModel, RequestParams = null> {
|
export abstract class AbstractList<ResponseModel, RequestParams = null> {
|
||||||
|
@Input() withPagination?: boolean = false;
|
||||||
|
|
||||||
columns = [] as IColumn[];
|
columns = [] as IColumn[];
|
||||||
loading = signal(false);
|
loading = signal(false);
|
||||||
items = signal<ResponseModel[]>([]);
|
items = signal<ResponseModel[]>([]);
|
||||||
@@ -21,7 +23,6 @@ export abstract class AbstractList<ResponseModel, RequestParams = null> {
|
|||||||
requestPayload = signal<Maybe<RequestParams>>(null);
|
requestPayload = signal<Maybe<RequestParams>>(null);
|
||||||
selectedItemForEdit = signal<Maybe<ResponseModel>>(null);
|
selectedItemForEdit = signal<Maybe<ResponseModel>>(null);
|
||||||
editMode = signal(false);
|
editMode = signal(false);
|
||||||
withPagination = signal(false);
|
|
||||||
responseMetaData = signal<Maybe<IResponseMetadata>>(null);
|
responseMetaData = signal<Maybe<IResponseMetadata>>(null);
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -43,7 +44,7 @@ export abstract class AbstractList<ResponseModel, RequestParams = null> {
|
|||||||
}),
|
}),
|
||||||
catchError((error) => {
|
catchError((error) => {
|
||||||
throw error;
|
throw error;
|
||||||
}),
|
})
|
||||||
)
|
)
|
||||||
.subscribe((res) => {
|
.subscribe((res) => {
|
||||||
if ('meta' in res) {
|
if ('meta' in res) {
|
||||||
@@ -60,7 +61,7 @@ export abstract class AbstractList<ResponseModel, RequestParams = null> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract getDataRequest(
|
abstract getDataRequest(
|
||||||
payload: Maybe<RequestParams>,
|
payload: Maybe<RequestParams>
|
||||||
): Observable<IPaginatedResponse<ResponseModel> | IListingResponse<ResponseModel>> | void;
|
): Observable<IPaginatedResponse<ResponseModel> | IListingResponse<ResponseModel>> | void;
|
||||||
|
|
||||||
abstract setColumns(): void;
|
abstract setColumns(): void;
|
||||||
@@ -90,7 +91,7 @@ export abstract class AbstractList<ResponseModel, RequestParams = null> {
|
|||||||
...(prev || {}),
|
...(prev || {}),
|
||||||
page,
|
page,
|
||||||
...(perPage ? ({ pageSize: perPage } as IPaginatedQuery) : {}),
|
...(perPage ? ({ pageSize: perPage } as IPaginatedQuery) : {}),
|
||||||
}) as any,
|
}) as any
|
||||||
);
|
);
|
||||||
this.responseMetaData.update((prev) => (prev ? { ...prev, page } : prev));
|
this.responseMetaData.update((prev) => (prev ? { ...prev, page } : prev));
|
||||||
this.getData();
|
this.getData();
|
||||||
|
|||||||
+16
-3
@@ -4,13 +4,26 @@
|
|||||||
[modal]="true"
|
[modal]="true"
|
||||||
[style]="{ width: '500px' }"
|
[style]="{ width: '500px' }"
|
||||||
[closable]="true"
|
[closable]="true"
|
||||||
(onHide)="close()"
|
(onHide)="close()">
|
||||||
>
|
|
||||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
||||||
|
@if (showCurrentPasswordField && form.controls.currentPassword) {
|
||||||
|
<uikit-field label="رمز عبور فعلی" pSize="large" [control]="form.controls.currentPassword">
|
||||||
|
<p-password
|
||||||
|
id="password1"
|
||||||
|
name="password"
|
||||||
|
[formControl]="form.controls.currentPassword"
|
||||||
|
autocomplete="password"
|
||||||
|
[toggleMask]="true"
|
||||||
|
[fluid]="true"
|
||||||
|
[feedback]="false"
|
||||||
|
size="large"
|
||||||
|
[invalid]="form.controls.currentPassword.touched && form.controls.currentPassword.invalid" />
|
||||||
|
</uikit-field>
|
||||||
|
}
|
||||||
<shared-password-input
|
<shared-password-input
|
||||||
[passwordControl]="form.controls.password"
|
[passwordControl]="form.controls.password"
|
||||||
[confirmPasswordControl]="form.controls.confirmPassword"
|
[confirmPasswordControl]="form.controls.confirmPassword"
|
||||||
/>
|
[isRenewal]="true" />
|
||||||
|
|
||||||
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="loading()" (onCancel)="close()" />
|
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="loading()" (onCancel)="close()" />
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+25
-2
@@ -2,11 +2,14 @@ import { MustMatch, password } from '@/core/validators';
|
|||||||
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
|
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
|
||||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||||
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
||||||
import { Component, EventEmitter, Output, input } from '@angular/core';
|
import { UikitFieldComponent } from '@/uikit';
|
||||||
|
import { Component, EventEmitter, Input, Output, input } from '@angular/core';
|
||||||
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
|
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
|
import { Password } from 'primeng/password';
|
||||||
import { SharedPasswordInputComponent } from '../passwordInput/password-input.component';
|
import { SharedPasswordInputComponent } from '../passwordInput/password-input.component';
|
||||||
|
|
||||||
export interface IChangePasswordSubmitPayload {
|
export interface IChangePasswordSubmitPayload {
|
||||||
|
currentPassword: string;
|
||||||
password: string;
|
password: string;
|
||||||
confirmPassword: string;
|
confirmPassword: string;
|
||||||
}
|
}
|
||||||
@@ -19,9 +22,13 @@ export interface IChangePasswordSubmitPayload {
|
|||||||
SharedDialogComponent,
|
SharedDialogComponent,
|
||||||
FormFooterActionsComponent,
|
FormFooterActionsComponent,
|
||||||
SharedPasswordInputComponent,
|
SharedPasswordInputComponent,
|
||||||
|
UikitFieldComponent,
|
||||||
|
Password,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class ChangePasswordFormDialogComponent extends AbstractDialog {
|
export class ChangePasswordFormDialogComponent extends AbstractDialog {
|
||||||
|
@Input() showCurrentPasswordField = false;
|
||||||
|
|
||||||
title = input<string>('');
|
title = input<string>('');
|
||||||
loading = input<boolean>(false);
|
loading = input<boolean>(false);
|
||||||
|
|
||||||
@@ -29,8 +36,10 @@ export class ChangePasswordFormDialogComponent extends AbstractDialog {
|
|||||||
|
|
||||||
private readonly fb = new FormBuilder();
|
private readonly fb = new FormBuilder();
|
||||||
|
|
||||||
form = this.fb.group(
|
initForm() {
|
||||||
|
const form = this.fb.group(
|
||||||
{
|
{
|
||||||
|
currentPassword: ['', [Validators.required]],
|
||||||
password: ['', [Validators.required, password()]],
|
password: ['', [Validators.required, password()]],
|
||||||
confirmPassword: ['', [Validators.required]],
|
confirmPassword: ['', [Validators.required]],
|
||||||
},
|
},
|
||||||
@@ -39,6 +48,16 @@ export class ChangePasswordFormDialogComponent extends AbstractDialog {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!this.showCurrentPasswordField) {
|
||||||
|
// @ts-ignore
|
||||||
|
form.removeControl('currentPassword');
|
||||||
|
}
|
||||||
|
|
||||||
|
return form;
|
||||||
|
}
|
||||||
|
|
||||||
|
form = this.initForm();
|
||||||
|
|
||||||
get dialogHeader() {
|
get dialogHeader() {
|
||||||
return this.title() ? `تغییر رمز عبور ${this.title()}` : 'تغییر رمز عبور';
|
return this.title() ? `تغییر رمز عبور ${this.title()}` : 'تغییر رمز عبور';
|
||||||
}
|
}
|
||||||
@@ -56,4 +75,8 @@ export class ChangePasswordFormDialogComponent extends AbstractDialog {
|
|||||||
this.form.reset();
|
this.form.reset();
|
||||||
super.close();
|
super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnChanges() {
|
||||||
|
this.form = this.initForm();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,9 @@
|
|||||||
</header>
|
</header>
|
||||||
}
|
}
|
||||||
<div class="light-bottomsheet-body p-4">
|
<div class="light-bottomsheet-body p-4">
|
||||||
|
@if (contentRendered) {
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import { Button } from 'primeng/button';
|
|||||||
.light-bottomsheet-mask {
|
.light-bottomsheet-mask {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
background: rgba(15, 23, 42, 0.22);
|
background: rgba(15, 23, 42, 0.52);
|
||||||
}
|
}
|
||||||
|
|
||||||
.light-bottomsheet-panel {
|
.light-bottomsheet-panel {
|
||||||
@@ -105,10 +105,12 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy, OnCha
|
|||||||
@Input() style: Record<string, string> | undefined;
|
@Input() style: Record<string, string> | undefined;
|
||||||
@Input() mobileDrawerHeight = '90vh';
|
@Input() mobileDrawerHeight = '90vh';
|
||||||
@Input() transitionOptions = '130ms cubic-bezier(0.2, 0, 0, 1)';
|
@Input() transitionOptions = '130ms cubic-bezier(0.2, 0, 0, 1)';
|
||||||
@Input() closeUnmountDelay = 150;
|
@Input() closeUnmountDelay = 20;
|
||||||
|
|
||||||
@Output() onHide = new EventEmitter<any>();
|
@Output() onHide = new EventEmitter<any>();
|
||||||
rendered = false;
|
rendered = false;
|
||||||
|
contentRendered = false;
|
||||||
|
private isClosing = false;
|
||||||
private closeTimer: ReturnType<typeof setTimeout> | null = null;
|
private closeTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
private originalParent: Node | null = null;
|
private originalParent: Node | null = null;
|
||||||
@@ -127,14 +129,16 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy, OnCha
|
|||||||
this.originalParent = host.parentNode;
|
this.originalParent = host.parentNode;
|
||||||
this.renderer.appendChild(this.document.body, host);
|
this.renderer.appendChild(this.document.body, host);
|
||||||
this.rendered = this.visible;
|
this.rendered = this.visible;
|
||||||
|
this.contentRendered = this.visible;
|
||||||
this.syncZIndex();
|
this.syncZIndex();
|
||||||
this.toggleBodyScrollLock(this.visible);
|
this.toggleBodyScrollLock(this.visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (changes['visible'] && this.visible) {
|
if (changes['visible'] && this.visible && !this.isClosing) {
|
||||||
this.clearCloseTimer();
|
this.clearCloseTimer();
|
||||||
this.rendered = true;
|
this.rendered = true;
|
||||||
|
this.contentRendered = true;
|
||||||
this.syncZIndex();
|
this.syncZIndex();
|
||||||
}
|
}
|
||||||
if (changes['visible']) {
|
if (changes['visible']) {
|
||||||
@@ -159,18 +163,20 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy, OnCha
|
|||||||
}
|
}
|
||||||
|
|
||||||
onVisibilityChange(nextValue: boolean) {
|
onVisibilityChange(nextValue: boolean) {
|
||||||
this.visible = nextValue;
|
|
||||||
this.visibleChange.emit(nextValue);
|
|
||||||
this.toggleBodyScrollLock(nextValue);
|
|
||||||
if (nextValue) {
|
if (nextValue) {
|
||||||
|
this.visible = nextValue;
|
||||||
|
this.isClosing = false;
|
||||||
this.clearCloseTimer();
|
this.clearCloseTimer();
|
||||||
this.rendered = true;
|
this.rendered = true;
|
||||||
|
this.contentRendered = true;
|
||||||
this.syncZIndex();
|
this.syncZIndex();
|
||||||
}
|
}
|
||||||
if (!nextValue) {
|
if (!nextValue) {
|
||||||
|
this.isClosing = true;
|
||||||
this.scheduleUnmount();
|
this.scheduleUnmount();
|
||||||
this.onHide.emit();
|
|
||||||
}
|
}
|
||||||
|
this.visibleChange.emit(nextValue);
|
||||||
|
this.toggleBodyScrollLock(nextValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMaskClick() {
|
onMaskClick() {
|
||||||
@@ -217,12 +223,14 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy, OnCha
|
|||||||
}
|
}
|
||||||
|
|
||||||
private scheduleUnmount() {
|
private scheduleUnmount() {
|
||||||
this.clearCloseTimer();
|
|
||||||
this.closeTimer = setTimeout(() => {
|
|
||||||
if (!this.visible) {
|
if (!this.visible) {
|
||||||
|
this.isClosing = false;
|
||||||
|
this.contentRendered = false;
|
||||||
this.rendered = false;
|
this.rendered = false;
|
||||||
|
this.onHide.emit();
|
||||||
}
|
}
|
||||||
}, this.closeUnmountDelay);
|
this.clearCloseTimer();
|
||||||
|
this.closeTimer = setTimeout(() => {}, this.closeUnmountDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private clearCloseTimer() {
|
private clearCloseTimer() {
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
<div class="bg-surface-card flex items-center p-4">
|
<div class="bg-surface-card flex items-center px-4 py-3">
|
||||||
<div class="grow">
|
<div class="grow">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
@if (backRoute) {
|
@if (backRoute || onBackClick) {
|
||||||
<p-button icon="pi pi-arrow-right" aria-label="بازگشت" outlined size="small" [routerLink]="backRoute" />
|
<p-button
|
||||||
|
icon="pi pi-arrow-right"
|
||||||
|
aria-label="بازگشت"
|
||||||
|
outlined
|
||||||
|
size="small"
|
||||||
|
[routerLink]="backRoute"
|
||||||
|
(click)="onBackClick.emit()" />
|
||||||
}
|
}
|
||||||
<h5 class="py-1.5 font-bold">{{ pageTitle }}</h5>
|
<h5 class="py-1.25 text-lg! font-bold">{{ pageTitle }}</h5>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (actions) {
|
@if (actions) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Maybe } from '@/core';
|
import { Maybe } from '@/core';
|
||||||
import { NgTemplateOutlet } from '@angular/common';
|
import { NgTemplateOutlet } from '@angular/common';
|
||||||
import { Component, ContentChild, Input, TemplateRef } from '@angular/core';
|
import { Component, ContentChild, EventEmitter, Input, Output, TemplateRef } from '@angular/core';
|
||||||
import { RouterLink, UrlTree } from '@angular/router';
|
import { RouterLink, UrlTree } from '@angular/router';
|
||||||
import { Button } from 'primeng/button';
|
import { Button } from 'primeng/button';
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@ import { Button } from 'primeng/button';
|
|||||||
export class InnerPagesHeaderComponent {
|
export class InnerPagesHeaderComponent {
|
||||||
@Input() pageTitle!: string;
|
@Input() pageTitle!: string;
|
||||||
@Input() backRoute?: UrlTree | string | any[];
|
@Input() backRoute?: UrlTree | string | any[];
|
||||||
|
@Output() onBackClick = new EventEmitter<void>();
|
||||||
@ContentChild('actions', { static: true }) actions?: Maybe<TemplateRef<any>>;
|
@ContentChild('actions', { static: true }) actions?: Maybe<TemplateRef<any>>;
|
||||||
constructor() {}
|
constructor() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,8 +243,6 @@ export class InputComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private isOutOfRange(numericValue: number): { min: boolean; max: boolean } {
|
private isOutOfRange(numericValue: number): { min: boolean; max: boolean } {
|
||||||
console.log('min', this.min, 'max', this.max, 'numericValue', numericValue);
|
|
||||||
|
|
||||||
const min = this.min !== undefined && this.min !== null ? this.min : Number.NEGATIVE_INFINITY;
|
const min = this.min !== undefined && this.min !== null ? this.min : Number.NEGATIVE_INFINITY;
|
||||||
const max = this.max !== undefined && this.max !== null ? this.max : Number.POSITIVE_INFINITY;
|
const max = this.max !== undefined && this.max !== null ? this.max : Number.POSITIVE_INFINITY;
|
||||||
|
|
||||||
@@ -277,12 +275,9 @@ export class InputComponent {
|
|||||||
const controlValue = isIdentifierField ? value : value === '' ? '' : numericValue;
|
const controlValue = isIdentifierField ? value : value === '' ? '' : numericValue;
|
||||||
this.control.setValue(controlValue);
|
this.control.setValue(controlValue);
|
||||||
target.value = value;
|
target.value = value;
|
||||||
console.log('value', value, 'controlValue', controlValue, 'numericValue', numericValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onInput($event: Event) {
|
onInput($event: Event) {
|
||||||
console.log('$event', $event);
|
|
||||||
|
|
||||||
const target = $event.target as HTMLInputElement | null;
|
const target = $event.target as HTMLInputElement | null;
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
|
|
||||||
@@ -296,14 +291,10 @@ export class InputComponent {
|
|||||||
value = this.normalizeLeadingZeros(value, allowDecimal);
|
value = this.normalizeLeadingZeros(value, allowDecimal);
|
||||||
|
|
||||||
value = this.enforceMaxLength(value);
|
value = this.enforceMaxLength(value);
|
||||||
console.log('$value', value);
|
|
||||||
let numericValue = this.parseNumericValue(value);
|
let numericValue = this.parseNumericValue(value);
|
||||||
|
|
||||||
const range = this.isOutOfRange(numericValue);
|
const range = this.isOutOfRange(numericValue);
|
||||||
console.log('$range', range);
|
|
||||||
if (value !== '' && (range.min || range.max)) {
|
if (value !== '' && (range.min || range.max)) {
|
||||||
console.log('in if');
|
|
||||||
|
|
||||||
this.notifyRangeError(range);
|
this.notifyRangeError(range);
|
||||||
value = this.lastValidNumericValue;
|
value = this.lastValidNumericValue;
|
||||||
numericValue = this.parseNumericValue(value);
|
numericValue = this.parseNumericValue(value);
|
||||||
|
|||||||
@@ -41,9 +41,9 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<pos-order-price-info-card [info]="getTotalPriceInfo()" />
|
<pos-order-price-info-card [info]="totalPriceInfo" />
|
||||||
|
|
||||||
<app-form-footer-actions />
|
<app-form-footer-actions [loading]="submitLoading()" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<shared-light-bottomsheet
|
<shared-light-bottomsheet
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export class SharedCorrectionFormComponent extends AbstractForm<
|
|||||||
CorrectionInvoiceFormValue,
|
CorrectionInvoiceFormValue,
|
||||||
IInvoiceItem[]
|
IInvoiceItem[]
|
||||||
> {
|
> {
|
||||||
|
@Input() beforeSubmit?: (payload: CorrectionInvoiceFormValue) => Promise<boolean> | boolean;
|
||||||
@Input({ required: true }) invoiceDate!: string;
|
@Input({ required: true }) invoiceDate!: string;
|
||||||
@Input() visible = false;
|
@Input() visible = false;
|
||||||
|
|
||||||
@@ -48,6 +49,12 @@ export class SharedCorrectionFormComponent extends AbstractForm<
|
|||||||
|
|
||||||
itemDrafts: Record<string, TCorrectionItemPayload> = {};
|
itemDrafts: Record<string, TCorrectionItemPayload> = {};
|
||||||
mappedInitialItems: TCorrectionItemPayload[] = [];
|
mappedInitialItems: TCorrectionItemPayload[] = [];
|
||||||
|
totalPriceInfo = {
|
||||||
|
totalBaseAmount: 0,
|
||||||
|
discountAmount: 0,
|
||||||
|
taxAmount: 0,
|
||||||
|
totalAmount: 0,
|
||||||
|
};
|
||||||
showItemEditSheet = signal(false);
|
showItemEditSheet = signal(false);
|
||||||
activeItemIndex = signal<number | null>(null);
|
activeItemIndex = signal<number | null>(null);
|
||||||
|
|
||||||
@@ -57,6 +64,7 @@ export class SharedCorrectionFormComponent extends AbstractForm<
|
|||||||
);
|
);
|
||||||
this.itemDrafts = {};
|
this.itemDrafts = {};
|
||||||
this.mappedInitialItems = (this.initialValues || []).map((item) => this.mapToInitialItem(item));
|
this.mappedInitialItems = (this.initialValues || []).map((item) => this.mapToInitialItem(item));
|
||||||
|
this.recalculateTotalPriceInfo();
|
||||||
this.showItemEditSheet.set(false);
|
this.showItemEditSheet.set(false);
|
||||||
this.activeItemIndex.set(null);
|
this.activeItemIndex.set(null);
|
||||||
}
|
}
|
||||||
@@ -91,9 +99,9 @@ export class SharedCorrectionFormComponent extends AbstractForm<
|
|||||||
good_id: item.good_id,
|
good_id: item.good_id,
|
||||||
unit_price: Number(item.unit_price || 0),
|
unit_price: Number(item.unit_price || 0),
|
||||||
quantity: Number(item.quantity || 0),
|
quantity: Number(item.quantity || 0),
|
||||||
discount_amount: Number(item.discount || 0),
|
discount_amount: Number(item.discount_amount || 0),
|
||||||
total_amount: Number(item.total_amount || 0),
|
total_amount: Number(item.total_amount || 0),
|
||||||
tax_amount: 0,
|
tax_amount: Number(item.tax_amount || 0),
|
||||||
base_total_amount: Number(item.unit_price || 0) * Number(item.quantity || 0),
|
base_total_amount: Number(item.unit_price || 0) * Number(item.quantity || 0),
|
||||||
measure_unit: (item.good_snapshot?.measure_unit || {}) as ISummary,
|
measure_unit: (item.good_snapshot?.measure_unit || {}) as ISummary,
|
||||||
};
|
};
|
||||||
@@ -158,9 +166,6 @@ export class SharedCorrectionFormComponent extends AbstractForm<
|
|||||||
const previews = (this.initialValues || [])
|
const previews = (this.initialValues || [])
|
||||||
.map((_, index) => this.getItemPreview(index))
|
.map((_, index) => this.getItemPreview(index))
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
|
|
||||||
console.log('previews', previews);
|
|
||||||
|
|
||||||
return previews.reduce(
|
return previews.reduce(
|
||||||
(acc, item: any) => {
|
(acc, item: any) => {
|
||||||
acc.totalBaseAmount += Number(item.base_total_amount || 0);
|
acc.totalBaseAmount += Number(item.base_total_amount || 0);
|
||||||
@@ -178,6 +183,10 @@ export class SharedCorrectionFormComponent extends AbstractForm<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private recalculateTotalPriceInfo() {
|
||||||
|
this.totalPriceInfo = this.getTotalPriceInfo();
|
||||||
|
}
|
||||||
|
|
||||||
saveActiveItemDraft(
|
saveActiveItemDraft(
|
||||||
goldForm?: SharedGoldPayloadFormComponent,
|
goldForm?: SharedGoldPayloadFormComponent,
|
||||||
standardForm?: SharedStandardPayloadFormComponent
|
standardForm?: SharedStandardPayloadFormComponent
|
||||||
@@ -200,10 +209,11 @@ export class SharedCorrectionFormComponent extends AbstractForm<
|
|||||||
id: item.id,
|
id: item.id,
|
||||||
pricing_model: item.good_snapshot?.pricing_model || '',
|
pricing_model: item.good_snapshot?.pricing_model || '',
|
||||||
};
|
};
|
||||||
|
this.recalculateTotalPriceInfo();
|
||||||
this.backToList();
|
this.backToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
override submitForm() {
|
private buildSubmitPayload(): CorrectionInvoiceFormValue | null {
|
||||||
const items =
|
const items =
|
||||||
this.initialValues?.map(
|
this.initialValues?.map(
|
||||||
(item, index) => this.itemDrafts[item.id] || this.mappedInitialItems[index]
|
(item, index) => this.itemDrafts[item.id] || this.mappedInitialItems[index]
|
||||||
@@ -217,12 +227,33 @@ export class SharedCorrectionFormComponent extends AbstractForm<
|
|||||||
|
|
||||||
if (!hasChanges) {
|
if (!hasChanges) {
|
||||||
this.toastService.warn({ text: 'هیچ تغییری در مقادیر ثبت نشده است.' });
|
this.toastService.warn({ text: 'هیچ تغییری در مقادیر ثبت نشده است.' });
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onSubmit.emit({
|
return {
|
||||||
invoice_date: this.form.controls.invoice_date.value || '',
|
invoice_date: this.form.controls.invoice_date.value || '',
|
||||||
items,
|
items,
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
override async submit() {
|
||||||
|
this.form.markAllAsTouched();
|
||||||
|
if (!this.form.valid) return;
|
||||||
|
|
||||||
|
const payload = this.buildSubmitPayload();
|
||||||
|
if (!payload) return;
|
||||||
|
|
||||||
|
this.submitLoading.set(true);
|
||||||
|
try {
|
||||||
|
const canSubmit = (await this.beforeSubmit?.(payload)) ?? true;
|
||||||
|
if (!canSubmit) return;
|
||||||
|
this.onSubmit.emit(payload);
|
||||||
|
} finally {
|
||||||
|
this.submitLoading.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override submitForm() {
|
||||||
|
// Submit flow is handled in overridden async submit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,177 @@
|
|||||||
|
import { INativePrintRequest } from '@/core/services/native-bridge.service';
|
||||||
|
import { formatJalali, formatWithCurrency } from '@/utils';
|
||||||
|
|
||||||
|
export function prepareInvoicePrintPayload(
|
||||||
|
invoice: any,
|
||||||
|
mustPrintConfig: Record<string, any>,
|
||||||
|
posName?: string
|
||||||
|
): INativePrintRequest[] | null {
|
||||||
|
if (!invoice) return null;
|
||||||
|
|
||||||
|
const defaultPrintItems: INativePrintRequest[] = [
|
||||||
|
{
|
||||||
|
title: 'اطلاعات صورتحساب',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: 'شماره',
|
||||||
|
value: String(invoice.invoice_number ?? invoice.code ?? '-'),
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'شماره منحصر به فرد مالیاتی',
|
||||||
|
value: String(invoice.tax_id || '-'),
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'نوع',
|
||||||
|
value: String(invoice.type?.translate || '-'),
|
||||||
|
show: mustPrintConfig['invoice_template'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'موضوع',
|
||||||
|
value: String(invoice.pos?.complex?.business_activity?.guild?.name || '-'),
|
||||||
|
show: mustPrintConfig['invoice_template'] ?? true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'تاریخ',
|
||||||
|
value: String(invoice.invoice_date ? formatJalali(invoice.invoice_date) : '-'),
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'وضعیت صدور',
|
||||||
|
value: String(invoice.status?.translate || '-'),
|
||||||
|
show: mustPrintConfig['show_payment_info'] ?? true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
.filter((item: any) => item.show)
|
||||||
|
.map(({ label, value }) => ({ label, value })),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `اطلاعات فروشنده`,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: 'فروشگاه',
|
||||||
|
value: String(invoice.pos?.complex?.business_activity?.name || '-'),
|
||||||
|
show: mustPrintConfig['business_name'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'شعبه',
|
||||||
|
value: String(invoice.pos?.complex?.name || '-'),
|
||||||
|
show: mustPrintConfig['complex_name'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'پایانه فروش',
|
||||||
|
value: String(invoice.pos?.name || posName || '-'),
|
||||||
|
show: mustPrintConfig['pos_name'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'شماره اقتصادی',
|
||||||
|
value: String(invoice.pos?.complex?.business_activity?.economic_code || '-'),
|
||||||
|
show: mustPrintConfig['economic_code'],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
.filter((item: any) => item.show)
|
||||||
|
.map(({ label, value }) => ({ label, value })),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `اطلاعات خریدار`,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: 'نام خریدار',
|
||||||
|
value: String(
|
||||||
|
(invoice.customer
|
||||||
|
? invoice.customer.type === 'LEGAL'
|
||||||
|
? invoice.customer.legal?.company_name
|
||||||
|
: `${invoice.customer.individual?.first_name || ''} ${
|
||||||
|
invoice.customer.individual?.last_name || ''
|
||||||
|
}`.trim()
|
||||||
|
: invoice.unknown_customer?.name) || '-'
|
||||||
|
),
|
||||||
|
show: mustPrintConfig['customer_name'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'شماره اقتصادی',
|
||||||
|
value: String(
|
||||||
|
(invoice.customer
|
||||||
|
? invoice.customer.type === 'LEGAL'
|
||||||
|
? invoice.customer.legal?.economic_code
|
||||||
|
: invoice.customer.individual?.economic_code || '-'
|
||||||
|
: '-') || '-'
|
||||||
|
),
|
||||||
|
show: mustPrintConfig['customer_economic_code'],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
.filter((item: any) => item.show)
|
||||||
|
.map(({ label, value }) => ({ label, value })),
|
||||||
|
},
|
||||||
|
].filter((item) => item.items.length);
|
||||||
|
|
||||||
|
if (mustPrintConfig['show_items'] && Array.isArray(invoice.items)) {
|
||||||
|
for (const item of invoice.items) {
|
||||||
|
defaultPrintItems.push({
|
||||||
|
title: 'جزییات صورتحساب',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: 'شرح',
|
||||||
|
value: String(item.good_snapshot?.name || '-'),
|
||||||
|
show: mustPrintConfig['item_name'] ?? true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'شناسه کالا / خدمت',
|
||||||
|
value: String(item.sku_code || '-'),
|
||||||
|
show: mustPrintConfig['item_sku'] ?? true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'تعداد / مقدار',
|
||||||
|
value: `${item.quantity || 0} ${item.measure_unit_text || ''}`.trim(),
|
||||||
|
show: mustPrintConfig['item_quantity'] ?? true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'قیمت واحد',
|
||||||
|
value: formatWithCurrency(item.unit_price || 0),
|
||||||
|
show: mustPrintConfig['item_base_amount'] ?? true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'اجرت',
|
||||||
|
value: formatWithCurrency(item.payload?.wages || 0),
|
||||||
|
show:
|
||||||
|
(mustPrintConfig['item_wage'] ?? true) && item.good_snapshot?.pricing_model === 'GOLD',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'سود',
|
||||||
|
value: formatWithCurrency(item.payload?.profit || 0),
|
||||||
|
show:
|
||||||
|
(mustPrintConfig['item_profit'] ?? true) &&
|
||||||
|
item.good_snapshot?.pricing_model === 'GOLD',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'حقالعمل',
|
||||||
|
value: formatWithCurrency(item.payload?.commission || 0),
|
||||||
|
show:
|
||||||
|
(mustPrintConfig['item_commission'] ?? true) &&
|
||||||
|
item.good_snapshot?.pricing_model === 'GOLD',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'مالیات بر ارزش افزوده',
|
||||||
|
value: formatWithCurrency(item.tax_amount || 0),
|
||||||
|
show: mustPrintConfig['item_tax'] ?? true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'تخفیف',
|
||||||
|
value: formatWithCurrency(item.discount_amount || 0),
|
||||||
|
show: mustPrintConfig['item_discount'] ?? true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'مبلغ کل',
|
||||||
|
value: formatWithCurrency(item.total_amount || 0),
|
||||||
|
show: mustPrintConfig['item_total_amount'] ?? true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
.filter((part: any) => part.show)
|
||||||
|
.map(({ label, value }) => ({ label, value })),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultPrintItems;
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<ol class="list-disc ps-4">
|
<ol class="list-disc ps-4">
|
||||||
<li>تعداد محصولات/خدمات خود را کم و یا حذف کنید</li>
|
<li>تعداد محصولات/خدمات خود را کم و یا حذف کنید</li>
|
||||||
<li>حداقل ۱ خدمت/سرویس بایستی باقی بماند</li>
|
<li>حداقل ۱ خدمت/سرویس بایستی باقی بماند</li>
|
||||||
<li>تخفیفها، مالیات و قیمت نهایی تمام شده با توجه به مقادیر فاکتور اصلی به صورت سیستمی محاسبه خواهند شد.</li>
|
<li>تخفیفها، مالیات و مبلغ کل تمام شده با توجه به مقادیر فاکتور اصلی به صورت سیستمی محاسبه خواهند شد.</li>
|
||||||
</ol>
|
</ol>
|
||||||
</p-message>
|
</p-message>
|
||||||
|
|
||||||
|
|||||||
@@ -40,12 +40,13 @@ export interface IInvoiceItem {
|
|||||||
measure_unit_text: string;
|
measure_unit_text: string;
|
||||||
sku_code: string;
|
sku_code: string;
|
||||||
unit_price: string;
|
unit_price: string;
|
||||||
discount: string;
|
discount_amount: string;
|
||||||
total_amount: string;
|
total_amount: string;
|
||||||
notes?: string;
|
notes?: string;
|
||||||
payload: Payload;
|
payload: Payload;
|
||||||
good_snapshot: Goodsnapshot;
|
good_snapshot: Goodsnapshot;
|
||||||
good: GoodSummary;
|
good: GoodSummary;
|
||||||
|
tax_amount: string;
|
||||||
}
|
}
|
||||||
interface GoodSummary {
|
interface GoodSummary {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -132,7 +133,12 @@ interface Pos extends ISummary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Complex extends ISummary {
|
interface Complex extends ISummary {
|
||||||
business_activity: ISummary;
|
business_activity: BusinessActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BusinessActivity extends ISummary {
|
||||||
|
economic_code: string;
|
||||||
|
guild: ISummary;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConsumerAccount {
|
interface ConsumerAccount {
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
@if (invoice) {
|
||||||
|
<p-card>
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div class="listKeyValue">
|
||||||
|
<app-key-value label="شماره منحصر به فرد مالیاتی" [value]="invoice.tax_id" />
|
||||||
|
<app-key-value label="تاریخ صورتحساب" [value]="invoice.invoice_date" type="date" />
|
||||||
|
<app-key-value label="تاریخ ایجاد" [value]="invoice.created_at" type="dateTime" />
|
||||||
|
<app-key-value label="نوع">
|
||||||
|
<catalog-invoice-type-tag [status]="invoice.type.value" />
|
||||||
|
</app-key-value>
|
||||||
|
<app-key-value label="وضعیت صدور">
|
||||||
|
<catalog-tax-provider-status-tag [status]="invoice.status.value" [translate]="invoice.status.translate" />
|
||||||
|
</app-key-value>
|
||||||
|
<div class="col-span-full">
|
||||||
|
<app-key-value label="توضیحات" [value]="invoice.notes || '----'" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p-divider align="center"> اطلاعات مالی</p-divider>
|
||||||
|
<div class="grid items-center gap-3 sm:grid-cols-2 sm:gap-4 md:grid-cols-3">
|
||||||
|
<app-key-value label="تخفیف" [value]="invoice.discount_amount" type="price" />
|
||||||
|
<app-key-value label="مالیات" [value]="invoice.tax_amount" type="price" />
|
||||||
|
<app-key-value label="مجموع قابل پرداخت" [value]="invoice.total_amount" type="price" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p-divider align="center"> اطلاعات پرداخت</p-divider>
|
||||||
|
<div class="grid items-center gap-3 sm:grid-cols-2 sm:gap-4 md:grid-cols-3">
|
||||||
|
<app-key-value label="نحوهی تسویهحساب">
|
||||||
|
<catalog-invoice-settlement-type-tag [type]="invoice.settlement_type.value" />
|
||||||
|
</app-key-value>
|
||||||
|
|
||||||
|
@for (payment of invoice.payments; track $index) {
|
||||||
|
<app-key-value
|
||||||
|
[label]="`${payment.payment_method === 'SET_OFF' ? 'تهاتر' : payment.payment_method === 'TERMINAL' ? 'پوز' : 'نقدی/ کارتخوان دیگر/ کارت به کارت'}`"
|
||||||
|
[value]="payment.amount"
|
||||||
|
type="price" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p-divider align="center"> اطلاعات صادر کننده </p-divider>
|
||||||
|
<div class="listKeyValue">
|
||||||
|
<app-key-value label="کسب و کار" [value]="invoice.pos!.complex.business_activity.name" />
|
||||||
|
<app-key-value label="مجموعه" [value]="invoice.pos!.complex.name" />
|
||||||
|
<app-key-value label="پایانه فروش" [value]="invoice.pos!.name" />
|
||||||
|
@if (invoice.consumer_account?.account?.username) {
|
||||||
|
<app-key-value label="ایجاد کننده" [value]="invoice.consumer_account.account.username" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (variant !== 'customer') {
|
||||||
|
<p-divider align="center"> اطلاعات مشتری </p-divider>
|
||||||
|
@if (invoice.customer) {
|
||||||
|
<div class="listKeyValue">
|
||||||
|
@if (invoice.customer.type === 'INDIVIDUAL') {
|
||||||
|
<app-key-value label="نوع مشتری" value="حقیقی" />
|
||||||
|
<app-key-value label="نام" [value]="invoice.customer.individual?.first_name" />
|
||||||
|
<app-key-value label="نام خانوادگی" [value]="invoice.customer.individual?.last_name" />
|
||||||
|
<app-key-value label="کد اقتصادی" [value]="invoice.customer.individual?.economic_code" />
|
||||||
|
<app-key-value label="کد ملی" [value]="invoice.customer.individual?.national_id" />
|
||||||
|
<app-key-value label="کد پستی" [value]="invoice.customer.individual?.postal_code" />
|
||||||
|
} @else {
|
||||||
|
<app-key-value label="نوع مشتری" value="حقوقی" />
|
||||||
|
<app-key-value label="نام شرکت" [value]="invoice.customer.legal?.company_name" />
|
||||||
|
<app-key-value label="کد اقتصادی" [value]="invoice.customer.legal?.economic_code" />
|
||||||
|
<app-key-value label="کد ثبتی" [value]="invoice.customer.legal?.registration_number" />
|
||||||
|
<app-key-value label="کد پستی" [value]="invoice.customer.legal?.postal_code" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
} @else if (invoice.unknown_customer) {
|
||||||
|
<div class="listKeyValue">
|
||||||
|
<app-key-value label="نوع مشتری" value="نوع دوم" />
|
||||||
|
<app-key-value label="عنوان" [value]="invoice.unknown_customer.name" />
|
||||||
|
<app-key-value label="کد ثبتی" [value]="invoice.unknown_customer.national_code" />
|
||||||
|
</div>
|
||||||
|
} @else {
|
||||||
|
<p class="text-text-color pt-3 pb-5 text-center">اطلاعات مشتری ثبت نشده است.</p>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<p-divider align="center"> کالاهای خریداری شده </p-divider>
|
||||||
|
<app-page-data-list
|
||||||
|
[columns]="columns"
|
||||||
|
[items]="invoice.items"
|
||||||
|
[loading]="loading"
|
||||||
|
pageTitle=""
|
||||||
|
[showRefresh]="false">
|
||||||
|
<ng-template #totalAmount let-item>
|
||||||
|
@if (!item.discount_amount) {
|
||||||
|
<span [appPriceMask]="item.total_amount"></span>
|
||||||
|
}
|
||||||
|
</ng-template>
|
||||||
|
</app-page-data-list>
|
||||||
|
</div>
|
||||||
|
</p-card>
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import { Maybe } from '@/core';
|
||||||
|
import {
|
||||||
|
CatalogInvoiceTypeTagComponent,
|
||||||
|
CatalogTaxProviderStatusTagComponent,
|
||||||
|
} from '@/shared/catalog';
|
||||||
|
import { CatalogInvoiceSettlementTypeTagComponent } from '@/shared/catalog/invoiceSettlementType';
|
||||||
|
import { PriceMaskDirective } from '@/shared/directives';
|
||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { Card } from 'primeng/card';
|
||||||
|
import { Divider } from 'primeng/divider';
|
||||||
|
import { KeyValueComponent } from '../key-value.component/key-value.component';
|
||||||
|
import { IColumn, PageDataListComponent } from '../pageDataList/page-data-list.component';
|
||||||
|
import { ISaleInvoiceFullResponse } from './sale-invoice-full-response.model';
|
||||||
|
|
||||||
|
export type TSaleInvoiceSingleViewVariant = 'full' | 'customer' | 'pos';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'shared-sale-invoice-single-info-card',
|
||||||
|
templateUrl: './sale-invoice-single-info-card.component.html',
|
||||||
|
imports: [
|
||||||
|
Card,
|
||||||
|
KeyValueComponent,
|
||||||
|
CatalogInvoiceTypeTagComponent,
|
||||||
|
CatalogTaxProviderStatusTagComponent,
|
||||||
|
Divider,
|
||||||
|
CatalogInvoiceSettlementTypeTagComponent,
|
||||||
|
PageDataListComponent,
|
||||||
|
PriceMaskDirective,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class SaleInvoiceSingleInfoCardComponent {
|
||||||
|
@Input({ required: true }) loading!: boolean;
|
||||||
|
@Input() invoice!: Maybe<ISaleInvoiceFullResponse>;
|
||||||
|
@Input() variant: TSaleInvoiceSingleViewVariant = 'full';
|
||||||
|
|
||||||
|
columns: IColumn[] = [
|
||||||
|
{
|
||||||
|
field: 'name',
|
||||||
|
header: 'عنوان',
|
||||||
|
type: 'nested',
|
||||||
|
nestedOption: {
|
||||||
|
path: 'good_snapshot.name',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'sku_code',
|
||||||
|
header: 'شناسه کالا',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'unit_price',
|
||||||
|
header: 'قیمت واحد',
|
||||||
|
type: 'price',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'quantity',
|
||||||
|
header: 'مقدار',
|
||||||
|
customDataModel(item) {
|
||||||
|
return `${item.quantity} ${item.measure_unit_text}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'commission',
|
||||||
|
header: 'کارمزد',
|
||||||
|
type: 'nested',
|
||||||
|
nestedOption: {
|
||||||
|
path: 'payload.commission',
|
||||||
|
type: 'price',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'wages',
|
||||||
|
header: 'اجرت',
|
||||||
|
type: 'nested',
|
||||||
|
nestedOption: {
|
||||||
|
path: 'payload.wages',
|
||||||
|
type: 'price',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'profit',
|
||||||
|
header: 'سود',
|
||||||
|
type: 'nested',
|
||||||
|
nestedOption: {
|
||||||
|
path: 'payload.profit',
|
||||||
|
type: 'price',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'discount_amount',
|
||||||
|
header: 'تخفیف',
|
||||||
|
type: 'price',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'tax_amount',
|
||||||
|
header: 'مالیات',
|
||||||
|
type: 'price',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'total_amount',
|
||||||
|
header: 'قابل پرداخت',
|
||||||
|
type: 'price',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -3,106 +3,22 @@
|
|||||||
} @else if (!invoice) {
|
} @else if (!invoice) {
|
||||||
<uikit-empty-state> </uikit-empty-state>
|
<uikit-empty-state> </uikit-empty-state>
|
||||||
} @else {
|
} @else {
|
||||||
<app-inner-pages-header [pageTitle]="`صورتحساب ${invoice.invoice_number}`" [backRoute]="backRoute">
|
<app-inner-pages-header [pageTitle]="`صورتحساب ${invoice.invoice_number}`" (onBackClick)="backToPrevPage()">
|
||||||
<ng-template #actions>
|
<ng-template #actions>
|
||||||
|
<p-button (click)="showQrCode()" icon="pi pi-qrcode" outlined size="small" />
|
||||||
<p-button (click)="printInvoice()" icon="pi pi-print" outlined size="small" label="چاپ" />
|
<p-button (click)="printInvoice()" icon="pi pi-print" outlined size="small" label="چاپ" />
|
||||||
|
@if (!isApplication) {
|
||||||
|
<p-button (click)="menu.toggle($event)" icon="pi pi-ellipsis-v" label="عملیات بیشتر" outlined size="small">
|
||||||
|
</p-button>
|
||||||
|
<p-menu #menu [model]="moreActionMenuItems()" [popup]="true"></p-menu>
|
||||||
|
}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</app-inner-pages-header>
|
</app-inner-pages-header>
|
||||||
<div class="p-4">
|
<div class="py-4 max-md:p-4">
|
||||||
<p-card>
|
<shared-sale-invoice-single-info-card [loading]="loading" [invoice]="invoice" [variant]="variant" />
|
||||||
<div class="flex flex-col gap-4">
|
|
||||||
<div class="listKeyValue">
|
|
||||||
<app-key-value label="شماره منحصر به فرد مالیاتی" [value]="invoice.tax_id" />
|
|
||||||
<app-key-value label="تاریخ صورتحساب" [value]="invoice.invoice_date" type="date" />
|
|
||||||
<app-key-value label="تاریخ ایجاد صورتحساب" [value]="invoice.created_at" type="dateTime" />
|
|
||||||
<app-key-value label="نوع صورتحساب">
|
|
||||||
<catalog-invoice-type-tag [status]="invoice.type.value" />
|
|
||||||
</app-key-value>
|
|
||||||
<app-key-value label="وضعیت صدور به سامانهی مودیان">
|
|
||||||
<catalog-tax-provider-status-tag [status]="invoice.status.value" [translate]="invoice.status.translate" />
|
|
||||||
</app-key-value>
|
|
||||||
<div class="col-span-full">
|
|
||||||
<app-key-value label="توضیحات" [value]="invoice.notes || '----'" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p-divider align="center"> اطلاعات مالی</p-divider>
|
|
||||||
<div class="grid items-center gap-3 sm:grid-cols-2 sm:gap-4 md:grid-cols-3">
|
|
||||||
<app-key-value label="مبلغ تخفیف" [value]="invoice.discount_amount" type="price" />
|
|
||||||
<app-key-value label="مبلغ مالیات" [value]="invoice.tax_amount" type="price" />
|
|
||||||
<app-key-value label="مجموع قابل پرداخت" [value]="invoice.total_amount" type="price" />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p-divider align="center"> اطلاعات پرداخت</p-divider>
|
@if (isApplication && moreActionMenuItems().length) {
|
||||||
<div class="grid items-center gap-3 sm:grid-cols-2 sm:gap-4 md:grid-cols-3">
|
|
||||||
<app-key-value label="نحوهی تسویهحساب">
|
|
||||||
<catalog-invoice-settlement-type-tag [type]="invoice.settlement_type.value" />
|
|
||||||
</app-key-value>
|
|
||||||
|
|
||||||
@for (payment of invoice.payments; track $index) {
|
|
||||||
<app-key-value
|
|
||||||
[label]="`${payment.payment_method === 'SET_OFF' ? 'تهاتر' : payment.payment_method === 'TERMINAL' ? 'پوز' : 'نقدی/ کارتخوان دیگر/ کارت به کارت'}`"
|
|
||||||
[value]="payment.amount"
|
|
||||||
type="price" />
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p-divider align="center"> اطلاعات صادر کننده </p-divider>
|
|
||||||
<div class="listKeyValue">
|
|
||||||
<app-key-value label="کسب و کار" [value]="invoice.pos!.complex.business_activity.name" />
|
|
||||||
<app-key-value label="مجموعه" [value]="invoice.pos!.complex.name" />
|
|
||||||
<app-key-value label="پایانه فروش" [value]="invoice.pos!.name" />
|
|
||||||
@if (invoice.consumer_account?.account?.username) {
|
|
||||||
<app-key-value label="ایجاد کننده" [value]="invoice.consumer_account.account.username" />
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if (variant !== 'customer') {
|
|
||||||
<p-divider align="center"> اطلاعات مشتری </p-divider>
|
|
||||||
@if (invoice.customer) {
|
|
||||||
<div class="listKeyValue">
|
|
||||||
@if (invoice.customer.type === 'INDIVIDUAL') {
|
|
||||||
<app-key-value label="نوع مشتری" value="حقیقی" />
|
|
||||||
<app-key-value label="نام" [value]="invoice.customer.individual?.first_name" />
|
|
||||||
<app-key-value label="نام خانوادگی" [value]="invoice.customer.individual?.last_name" />
|
|
||||||
<app-key-value label="کد اقتصادی" [value]="invoice.customer.individual?.economic_code" />
|
|
||||||
<app-key-value label="کد ملی" [value]="invoice.customer.individual?.national_id" />
|
|
||||||
<app-key-value label="کد پستی" [value]="invoice.customer.individual?.postal_code" />
|
|
||||||
} @else {
|
|
||||||
<app-key-value label="نوع مشتری" value="حقوقی" />
|
|
||||||
<app-key-value label="نام شرکت" [value]="invoice.customer.legal?.company_name" />
|
|
||||||
<app-key-value label="کد اقتصادی" [value]="invoice.customer.legal?.economic_code" />
|
|
||||||
<app-key-value label="کد ثبتی" [value]="invoice.customer.legal?.registration_number" />
|
|
||||||
<app-key-value label="کد پستی" [value]="invoice.customer.legal?.postal_code" />
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
} @else if (invoice.unknown_customer) {
|
|
||||||
<div class="listKeyValue">
|
|
||||||
<app-key-value label="نوع مشتری" value="نوع دوم" />
|
|
||||||
<app-key-value label="عنوان" [value]="invoice.unknown_customer.name" />
|
|
||||||
<app-key-value label="کد ثبتی" [value]="invoice.unknown_customer.national_code" />
|
|
||||||
</div>
|
|
||||||
} @else {
|
|
||||||
<p class="text-text-color pt-3 pb-5 text-center">اطلاعات مشتری ثبت نشده است.</p>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<p-divider align="center"> کالاهای خریداری شده </p-divider>
|
|
||||||
<app-page-data-list
|
|
||||||
[columns]="columns"
|
|
||||||
[items]="invoice.items"
|
|
||||||
[loading]="loading"
|
|
||||||
pageTitle=""
|
|
||||||
[showRefresh]="false">
|
|
||||||
<ng-template #totalAmount let-item>
|
|
||||||
@if (!item.discount_amount) {
|
|
||||||
<span [appPriceMask]="item.total_amount"></span>
|
|
||||||
}
|
|
||||||
</ng-template>
|
|
||||||
</app-page-data-list>
|
|
||||||
</div>
|
|
||||||
</p-card>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if (moreActionMenuItems().length) {
|
|
||||||
<div class="border-surface-border bg-surface-card sticky bottom-0 z-10 mt-4 w-full rounded-t-2xl border-t p-3">
|
<div class="border-surface-border bg-surface-card sticky bottom-0 z-10 mt-4 w-full rounded-t-2xl border-t p-3">
|
||||||
<div class="flex flex-wrap justify-center gap-2">
|
<div class="flex flex-wrap justify-center gap-2">
|
||||||
@for (action of moreActionMenuItems(); track action.label || $index) {
|
@for (action of moreActionMenuItems(); track action.label || $index) {
|
||||||
@@ -130,6 +46,40 @@
|
|||||||
[visible]="showCorrectionForm()"
|
[visible]="showCorrectionForm()"
|
||||||
[initialValues]="invoice.items"
|
[initialValues]="invoice.items"
|
||||||
[invoiceDate]="invoice.invoice_date"
|
[invoiceDate]="invoice.invoice_date"
|
||||||
|
[beforeSubmit]="beforeCorrectionSubmitHandler.bind(this)"
|
||||||
(onSubmit)="correctionSubmit($event)" />
|
(onSubmit)="correctionSubmit($event)" />
|
||||||
</shared-light-bottomsheet>
|
</shared-light-bottomsheet>
|
||||||
|
<shared-light-bottomsheet [(visible)]="showQrCodeDialog" header="کد QR">
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<span class="text-center text-lg font-bold">
|
||||||
|
برای امکان دسترسی به صورتحساب به صورت آنلاین، کد QR را اسکن کنید.
|
||||||
|
</span>
|
||||||
|
<p-card class="mx-auto">
|
||||||
|
<qrcode [qrdata]="publicInvoiceRoute()" [width]="220" [errorCorrectionLevel]="'M'"></qrcode>
|
||||||
|
</p-card>
|
||||||
|
</div>
|
||||||
|
</shared-light-bottomsheet>
|
||||||
|
|
||||||
|
<shared-light-bottomsheet [(visible)]="showCorrectionPaymentDialog" header="پرداخت اصلاحی">
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div class="text-sm">مبلغ اصلاحی افزایش یافته است. لطفاً مبلغ پرداختی را ثبت کنید.</div>
|
||||||
|
<div class="border-surface-border rounded-lg border p-3">
|
||||||
|
<div class="text-muted-color text-xs">حداقل مبلغ موردنیاز</div>
|
||||||
|
<div class="text-lg font-bold" [appPriceMask]="correctionRequiredPayment()"></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<label class="text-sm font-medium">مبلغ پرداختی</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
class="border-surface-border w-full rounded-md border px-3 py-2"
|
||||||
|
[value]="correctionPaymentAmount()"
|
||||||
|
(input)="onCorrectionPaymentAmountChange($event)" />
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end gap-2">
|
||||||
|
<button pButton type="button" severity="secondary" label="انصراف" (click)="cancelCorrectionPayment()"></button>
|
||||||
|
<button pButton type="button" label="تایید پرداخت" (click)="confirmCorrectionPayment()"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</shared-light-bottomsheet>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,17 @@
|
|||||||
import { Maybe } from '@/core';
|
import { Maybe } from '@/core';
|
||||||
import { NativeBridgeService } from '@/core/services';
|
import { NativeBridgeService } from '@/core/services';
|
||||||
|
import { NavigationService } from '@/core/services/navigation.service';
|
||||||
import { ToastService } from '@/core/services/toast.service';
|
import { ToastService } from '@/core/services/toast.service';
|
||||||
import { PosConfigPrintService } from '@/domains/pos/modules/configs/components/print/services/main.service';
|
import { PosConfigPrintService } from '@/domains/pos/modules/configs/components/print/services/main.service';
|
||||||
import { IPosReturnFromSaleRequest } from '@/domains/pos/modules/saleInvoices/models/returnFromSale';
|
import { IPosReturnFromSaleRequest } from '@/domains/pos/modules/saleInvoices/models/returnFromSale';
|
||||||
import { IPosOrderItem } from '@/domains/pos/modules/shop/models';
|
import { IPosOrderItem } from '@/domains/pos/modules/shop/models';
|
||||||
import { PosInfoStore } from '@/domains/pos/store';
|
import { PosInfoStore } from '@/domains/pos/store';
|
||||||
import {
|
import { TspProviderResponseStatus } from '@/shared/catalog';
|
||||||
CatalogInvoiceTypeTagComponent,
|
import { SharedLightBottomsheetComponent } from '@/shared/components';
|
||||||
CatalogTaxProviderStatusTagComponent,
|
|
||||||
TspProviderResponseStatus,
|
|
||||||
} from '@/shared/catalog';
|
|
||||||
import { CatalogInvoiceSettlementTypeTagComponent } from '@/shared/catalog/invoiceSettlementType';
|
|
||||||
import { KeyValueComponent, SharedLightBottomsheetComponent } from '@/shared/components';
|
|
||||||
import { ISaleInvoiceFullResponse } from '@/shared/components/invoices/sale-invoice-full-response.model';
|
import { ISaleInvoiceFullResponse } from '@/shared/components/invoices/sale-invoice-full-response.model';
|
||||||
import { PageLoadingComponent } from '@/shared/components/page-loading.component';
|
import { PageLoadingComponent } from '@/shared/components/page-loading.component';
|
||||||
import {
|
|
||||||
IColumn,
|
|
||||||
PageDataListComponent,
|
|
||||||
} from '@/shared/components/pageDataList/page-data-list.component';
|
|
||||||
import { PriceMaskDirective } from '@/shared/directives';
|
import { PriceMaskDirective } from '@/shared/directives';
|
||||||
import { UikitEmptyStateComponent } from '@/uikit';
|
import { UikitEmptyStateComponent } from '@/uikit';
|
||||||
import { formatWithCurrency } from '@/utils';
|
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
computed,
|
computed,
|
||||||
@@ -33,21 +24,25 @@ import {
|
|||||||
TemplateRef,
|
TemplateRef,
|
||||||
ViewChild,
|
ViewChild,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { UrlTree } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
import { QRCodeComponent } from 'angularx-qrcode';
|
||||||
import { Button, ButtonDirective } from 'primeng/button';
|
import { Button, ButtonDirective } from 'primeng/button';
|
||||||
import { Card } from 'primeng/card';
|
import { Card } from 'primeng/card';
|
||||||
import { Dialog } from 'primeng/dialog';
|
import { Menu } from 'primeng/menu';
|
||||||
import { Divider } from 'primeng/divider';
|
|
||||||
import { ProgressSpinner } from 'primeng/progressspinner';
|
|
||||||
import { TableModule } from 'primeng/table';
|
import { TableModule } from 'primeng/table';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
import config from 'src/config';
|
||||||
import { AppConfirmationService } from '../confirmationDialog/confirmation-dialog.service';
|
import { AppConfirmationService } from '../confirmationDialog/confirmation-dialog.service';
|
||||||
import { InnerPagesHeaderComponent } from '../innerPagesHeader/inner-pages-header.component';
|
import { InnerPagesHeaderComponent } from '../innerPagesHeader/inner-pages-header.component';
|
||||||
import { SharedCorrectionFormComponent } from './correctionForm';
|
import { SharedCorrectionFormComponent } from './correctionForm';
|
||||||
import { CorrectionInvoiceFormValue, ICorrectionRequest, ReturnFromSaleFormValue } from './models';
|
import { CorrectionInvoiceFormValue, ICorrectionRequest, ReturnFromSaleFormValue } from './models';
|
||||||
|
import { prepareInvoicePrintPayload } from './prepare-print.util';
|
||||||
import { SharedReturnFormComponent } from './returnForm/form.component';
|
import { SharedReturnFormComponent } from './returnForm/form.component';
|
||||||
|
import {
|
||||||
|
SaleInvoiceSingleInfoCardComponent,
|
||||||
|
TSaleInvoiceSingleViewVariant,
|
||||||
|
} from './sale-invoice-single-info-card.component';
|
||||||
|
|
||||||
export type TSaleInvoiceSingleViewVariant = 'full' | 'customer' | 'pos';
|
|
||||||
type TActionMenuItem = {
|
type TActionMenuItem = {
|
||||||
label: string;
|
label: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
@@ -60,25 +55,20 @@ type TActionMenuItem = {
|
|||||||
selector: 'shared-sale-invoice-single-view',
|
selector: 'shared-sale-invoice-single-view',
|
||||||
templateUrl: './sale-invoice-single-view.component.html',
|
templateUrl: './sale-invoice-single-view.component.html',
|
||||||
imports: [
|
imports: [
|
||||||
KeyValueComponent,
|
|
||||||
Divider,
|
|
||||||
PageDataListComponent,
|
|
||||||
TableModule,
|
TableModule,
|
||||||
PageLoadingComponent,
|
PageLoadingComponent,
|
||||||
UikitEmptyStateComponent,
|
UikitEmptyStateComponent,
|
||||||
PriceMaskDirective,
|
|
||||||
CatalogTaxProviderStatusTagComponent,
|
|
||||||
CatalogInvoiceTypeTagComponent,
|
|
||||||
Button,
|
Button,
|
||||||
CatalogInvoiceSettlementTypeTagComponent,
|
|
||||||
SharedLightBottomsheetComponent,
|
SharedLightBottomsheetComponent,
|
||||||
ProgressSpinner,
|
|
||||||
SharedReturnFormComponent,
|
SharedReturnFormComponent,
|
||||||
SharedCorrectionFormComponent,
|
SharedCorrectionFormComponent,
|
||||||
Dialog,
|
|
||||||
ButtonDirective,
|
ButtonDirective,
|
||||||
InnerPagesHeaderComponent,
|
InnerPagesHeaderComponent,
|
||||||
|
SaleInvoiceSingleInfoCardComponent,
|
||||||
|
QRCodeComponent,
|
||||||
Card,
|
Card,
|
||||||
|
PriceMaskDirective,
|
||||||
|
Menu,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class SharedSaleInvoiceSingleViewComponent {
|
export class SharedSaleInvoiceSingleViewComponent {
|
||||||
@@ -88,14 +78,17 @@ export class SharedSaleInvoiceSingleViewComponent {
|
|||||||
//TODO: below service Must be transform from pos to shared.
|
//TODO: below service Must be transform from pos to shared.
|
||||||
private readonly service = inject(PosConfigPrintService);
|
private readonly service = inject(PosConfigPrintService);
|
||||||
private readonly confirmationService = inject(AppConfirmationService);
|
private readonly confirmationService = inject(AppConfirmationService);
|
||||||
|
private readonly router = inject(Router);
|
||||||
|
private readonly navigationService = inject(NavigationService);
|
||||||
|
|
||||||
@Input({ required: true }) loading!: boolean;
|
@Input({ required: true }) loading!: boolean;
|
||||||
@Input() invoice!: Maybe<ISaleInvoiceFullResponse>;
|
@Input() invoice!: Maybe<ISaleInvoiceFullResponse>;
|
||||||
@Input() variant: TSaleInvoiceSingleViewVariant = 'full';
|
@Input() variant: TSaleInvoiceSingleViewVariant = 'full';
|
||||||
@Input() backRoute?: UrlTree | string | any[];
|
@Input() backRoute?: string;
|
||||||
@Input() sendToTspLoading: boolean = false;
|
@Input() sendToTspLoading: boolean = false;
|
||||||
@Input() resendToTspLoading: boolean = false;
|
@Input() resendToTspLoading: boolean = false;
|
||||||
@Input() inquiryLoading: boolean = false;
|
@Input() inquiryLoading: boolean = false;
|
||||||
|
@Input() beforeCorrectionSubmit?: (data: ICorrectionRequest) => Promise<boolean> | boolean;
|
||||||
|
|
||||||
@Output() onRefresh = new EventEmitter<void>();
|
@Output() onRefresh = new EventEmitter<void>();
|
||||||
@Output() onSendToTsp = new EventEmitter<Observable<any>>();
|
@Output() onSendToTsp = new EventEmitter<Observable<any>>();
|
||||||
@@ -109,6 +102,19 @@ export class SharedSaleInvoiceSingleViewComponent {
|
|||||||
moreActionMenuItems = signal<TActionMenuItem[]>([]);
|
moreActionMenuItems = signal<TActionMenuItem[]>([]);
|
||||||
showCorrectionForm = signal(false);
|
showCorrectionForm = signal(false);
|
||||||
showReturnFromSaleForm = signal(false);
|
showReturnFromSaleForm = signal(false);
|
||||||
|
showQrCodeDialog = signal(false);
|
||||||
|
showCorrectionPaymentDialog = signal(false);
|
||||||
|
correctionRequiredPayment = signal(0);
|
||||||
|
correctionPaymentAmount = signal(0);
|
||||||
|
readonly isApplication = config.isPosApplication;
|
||||||
|
private pendingCorrectionSubmitResolver: Maybe<(allowed: boolean) => void> = null;
|
||||||
|
|
||||||
|
publicInvoiceRoute = computed(() => {
|
||||||
|
if (this.invoice) {
|
||||||
|
return `${window.location.origin}/sale-invoices/${this.invoice.id}`;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
|
||||||
showErrors = () => {};
|
showErrors = () => {};
|
||||||
inquiry = () => {
|
inquiry = () => {
|
||||||
@@ -231,157 +237,8 @@ export class SharedSaleInvoiceSingleViewComponent {
|
|||||||
|
|
||||||
preparePrint = async () => {
|
preparePrint = async () => {
|
||||||
if (this.invoice) {
|
if (this.invoice) {
|
||||||
const mustPrintConfig = await this.service.get();
|
const mustPrintConfig = await this.service.getVisibleItems();
|
||||||
|
return prepareInvoicePrintPayload(this.invoice, mustPrintConfig, this.posName());
|
||||||
const defaultPrintItems = [
|
|
||||||
{
|
|
||||||
title: 'اطلاعات صورتحساب',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
label: 'شماره منحصر به فرد مالیاتی',
|
|
||||||
value: 'this.invoice',
|
|
||||||
show: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'شماره صورتحساب',
|
|
||||||
value: this.invoice.code,
|
|
||||||
show: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'موضوع صورتحساب',
|
|
||||||
value: 'this.invoice',
|
|
||||||
show: mustPrintConfig.invoice_template ?? true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'نوع صورتحساب',
|
|
||||||
value: 'this.invoice',
|
|
||||||
show: mustPrintConfig.invoice_template,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'تاریخ و ساعت',
|
|
||||||
value: this.invoice.invoice_date,
|
|
||||||
show: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'وضعیت صورتحساب مالیاتی',
|
|
||||||
value: this.invoice.status.translate,
|
|
||||||
show: mustPrintConfig.show_payment_info ?? true,
|
|
||||||
},
|
|
||||||
].filter((item) => item.show),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: `اطلاعات فروشنده`,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
label: 'عنوان فروشگاه',
|
|
||||||
value: this.invoice.pos.complex.business_activity.name,
|
|
||||||
show: mustPrintConfig.business_name,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'عنوان شعبه',
|
|
||||||
value: this.invoice.pos.complex.name,
|
|
||||||
show: mustPrintConfig.complex_name,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'عنوان پایانه فروش',
|
|
||||||
value: this.invoice.pos.name,
|
|
||||||
show: mustPrintConfig.pos_name,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'شماره اقتصادی',
|
|
||||||
value: 'this.invoice.pos.complex.business_activity.economic_code',
|
|
||||||
show: mustPrintConfig.economic_code,
|
|
||||||
},
|
|
||||||
].filter((item) => item.show),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: `اطلاعات خریدار`,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
label: 'نام خریدار',
|
|
||||||
value:
|
|
||||||
(this.invoice.customer
|
|
||||||
? this.invoice.customer.type === 'LEGAL'
|
|
||||||
? this.invoice.customer.legal?.company_name
|
|
||||||
: `${this.invoice.customer.individual?.first_name} ${this.invoice.customer.individual?.last_name}`
|
|
||||||
: this.invoice.unknown_customer?.name) || '-',
|
|
||||||
show: mustPrintConfig.customer_name,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'شماره اقتصادی',
|
|
||||||
value:
|
|
||||||
(this.invoice.customer
|
|
||||||
? this.invoice.customer.type === 'LEGAL'
|
|
||||||
? this.invoice.customer.legal?.economic_code
|
|
||||||
: this.invoice.customer.individual?.economic_code || '-'
|
|
||||||
: '-') || '-',
|
|
||||||
show: mustPrintConfig.customer_economic_code,
|
|
||||||
},
|
|
||||||
].filter((item) => item.show),
|
|
||||||
},
|
|
||||||
].filter((item) => item.items.length);
|
|
||||||
|
|
||||||
if (mustPrintConfig.show_items) {
|
|
||||||
for (let item of this.invoice.items) {
|
|
||||||
defaultPrintItems.push({
|
|
||||||
title: 'جزییات صورتحساب',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
label: 'شرح',
|
|
||||||
value: item.good.name,
|
|
||||||
show: mustPrintConfig.items?.name,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'شناسه کالا / خدمت',
|
|
||||||
value: item.sku_code,
|
|
||||||
show: mustPrintConfig.items?.sku,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'تعداد / مقدار',
|
|
||||||
value: `${item.quantity} ${item.measure_unit_text}`,
|
|
||||||
show: mustPrintConfig.items?.quantity,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'قیمت واحد',
|
|
||||||
value: formatWithCurrency(item.unit_price),
|
|
||||||
show: mustPrintConfig.items?.base_amount,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'اجرت',
|
|
||||||
value: formatWithCurrency(item.payload.wages),
|
|
||||||
show: mustPrintConfig.items?.wage && item.good_snapshot.pricing_model === 'GOLD',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'سود',
|
|
||||||
value: formatWithCurrency(item.payload.wages),
|
|
||||||
show: mustPrintConfig.items?.profit && item.good_snapshot.pricing_model === 'GOLD',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'حقالعمل',
|
|
||||||
value: formatWithCurrency(item.payload.commission),
|
|
||||||
show:
|
|
||||||
mustPrintConfig.items?.commission && item.good_snapshot.pricing_model === 'GOLD',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'مالیات بر ارزش افزوده',
|
|
||||||
value: 'item.good.tax',
|
|
||||||
show: mustPrintConfig.items?.tax,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'تخفیف',
|
|
||||||
value: formatWithCurrency(item.discount),
|
|
||||||
show: mustPrintConfig.items?.discount,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'مبلغ کل',
|
|
||||||
value: formatWithCurrency(item.total_amount),
|
|
||||||
show: mustPrintConfig.items?.total_amount,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return defaultPrintItems;
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
@@ -389,6 +246,7 @@ export class SharedSaleInvoiceSingleViewComponent {
|
|||||||
printInvoice = async () => {
|
printInvoice = async () => {
|
||||||
try {
|
try {
|
||||||
const printItems = await this.preparePrint();
|
const printItems = await this.preparePrint();
|
||||||
|
|
||||||
if (printItems) {
|
if (printItems) {
|
||||||
this.nativeBridge.print(printItems);
|
this.nativeBridge.print(printItems);
|
||||||
}
|
}
|
||||||
@@ -399,75 +257,6 @@ export class SharedSaleInvoiceSingleViewComponent {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
columns: IColumn[] = [
|
|
||||||
{
|
|
||||||
field: 'name',
|
|
||||||
header: 'عنوان',
|
|
||||||
type: 'nested',
|
|
||||||
nestedOption: {
|
|
||||||
path: 'good_snapshot.name',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'sku_code',
|
|
||||||
header: 'شناسه کالا',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'unit_price',
|
|
||||||
header: 'قیمت واحد',
|
|
||||||
type: 'price',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'quantity',
|
|
||||||
header: 'مقدار',
|
|
||||||
customDataModel(item) {
|
|
||||||
return `${item.quantity} ${item.measure_unit_text}`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'commission',
|
|
||||||
header: 'کارمزد',
|
|
||||||
type: 'nested',
|
|
||||||
nestedOption: {
|
|
||||||
path: 'payload.commission',
|
|
||||||
type: 'price',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'wages',
|
|
||||||
header: 'اجرت',
|
|
||||||
type: 'nested',
|
|
||||||
nestedOption: {
|
|
||||||
path: 'payload.wages',
|
|
||||||
type: 'price',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'profit',
|
|
||||||
header: 'سود',
|
|
||||||
type: 'nested',
|
|
||||||
nestedOption: {
|
|
||||||
path: 'payload.profit',
|
|
||||||
type: 'price',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'discount_amount',
|
|
||||||
header: 'مبلغ تخفیف',
|
|
||||||
type: 'price',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'tax_amount',
|
|
||||||
header: 'مبلغ مالیات',
|
|
||||||
type: 'price',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'total_amount',
|
|
||||||
header: 'مبلغ قابل پرداخت',
|
|
||||||
type: 'price',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
refresh() {
|
refresh() {
|
||||||
this.onRefresh.emit();
|
this.onRefresh.emit();
|
||||||
}
|
}
|
||||||
@@ -492,6 +281,53 @@ export class SharedSaleInvoiceSingleViewComponent {
|
|||||||
this.sendCorrection(this.mapCorrectionRequest(event));
|
this.sendCorrection(this.mapCorrectionRequest(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async beforeCorrectionSubmitHandler(event: CorrectionInvoiceFormValue): Promise<boolean> {
|
||||||
|
const mapped = this.mapCorrectionRequest(event);
|
||||||
|
const oldTotalAmount = Number(this.invoice?.total_amount || 0);
|
||||||
|
const newTotalAmount = Number(mapped.total_amount || 0);
|
||||||
|
|
||||||
|
if (newTotalAmount <= oldTotalAmount) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const requiredAmount = newTotalAmount - oldTotalAmount;
|
||||||
|
this.correctionRequiredPayment.set(requiredAmount);
|
||||||
|
this.correctionPaymentAmount.set(requiredAmount);
|
||||||
|
this.showCorrectionPaymentDialog.set(true);
|
||||||
|
|
||||||
|
const allowByDialog = await new Promise<boolean>((resolve) => {
|
||||||
|
this.pendingCorrectionSubmitResolver = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!allowByDialog) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (await this.beforeCorrectionSubmit?.(mapped)) ?? true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onCorrectionPaymentAmountChange(event: Event) {
|
||||||
|
const value = Number((event.target as HTMLInputElement)?.value || 0);
|
||||||
|
this.correctionPaymentAmount.set(Number.isFinite(value) ? value : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmCorrectionPayment() {
|
||||||
|
if (this.correctionPaymentAmount() < this.correctionRequiredPayment()) {
|
||||||
|
this.toastService.warn({ text: 'مبلغ پرداختی باید حداقل برابر با افزایش مبلغ باشد.' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showCorrectionPaymentDialog.set(false);
|
||||||
|
this.pendingCorrectionSubmitResolver?.(true);
|
||||||
|
this.pendingCorrectionSubmitResolver = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelCorrectionPayment() {
|
||||||
|
this.showCorrectionPaymentDialog.set(false);
|
||||||
|
this.pendingCorrectionSubmitResolver?.(false);
|
||||||
|
this.pendingCorrectionSubmitResolver = null;
|
||||||
|
}
|
||||||
|
|
||||||
private mapReturnFromSaleRequest(event: ReturnFromSaleFormValue): IPosReturnFromSaleRequest {
|
private mapReturnFromSaleRequest(event: ReturnFromSaleFormValue): IPosReturnFromSaleRequest {
|
||||||
const invoiceItems = this.invoice?.items || [];
|
const invoiceItems = this.invoice?.items || [];
|
||||||
const itemMap = new Map(invoiceItems.map((item) => [item.id, item]));
|
const itemMap = new Map(invoiceItems.map((item) => [item.id, item]));
|
||||||
@@ -503,10 +339,10 @@ export class SharedSaleInvoiceSingleViewComponent {
|
|||||||
|
|
||||||
const quantity = Number(item.quantity || 0);
|
const quantity = Number(item.quantity || 0);
|
||||||
const unit_price = Number(source.unit_price || 0);
|
const unit_price = Number(source.unit_price || 0);
|
||||||
const discount_amount = Number(source.discount || 0);
|
const discount_amount = Number(source.discount_amount || 0);
|
||||||
const base_total_amount = unit_price * quantity;
|
const base_total_amount = unit_price * quantity;
|
||||||
const total_amount = Number(source.total_amount || 0);
|
const total_amount = Number(source.total_amount || 0);
|
||||||
const tax_amount = Number(source.payload?.wages || 0);
|
const tax_amount = Number(source.tax_amount || 0);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
good_id: source.good_id,
|
good_id: source.good_id,
|
||||||
@@ -537,4 +373,11 @@ export class SharedSaleInvoiceSingleViewComponent {
|
|||||||
returnSubmit(event: ReturnFromSaleFormValue) {
|
returnSubmit(event: ReturnFromSaleFormValue) {
|
||||||
this.sendReturnFromSale(this.mapReturnFromSaleRequest(event));
|
this.sendReturnFromSale(this.mapReturnFromSaleRequest(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
backToPrevPage() {
|
||||||
|
this.navigationService.back(this.backRoute);
|
||||||
|
}
|
||||||
|
showQrCode() {
|
||||||
|
this.showQrCodeDialog.set(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
<div [ngClass]="{ 'h-full overflow-auto': true, 'border border-surface-border cardShadow': hasCaption }">
|
<div [ngClass]="{ 'h-full overflow-auto': true, 'border-surface-border cardShadow border': hasCaption }">
|
||||||
<div
|
<div
|
||||||
[ngClass]="{
|
[ngClass]="{
|
||||||
'px-4': hasCaption,
|
'px-4': hasCaption,
|
||||||
'pb-4': true,
|
'pb-4': true,
|
||||||
}"
|
}">
|
||||||
>
|
|
||||||
@if (hasCaption && captionBox) {
|
@if (hasCaption && captionBox) {
|
||||||
<div class="pt-4">
|
<div class="pt-4">
|
||||||
<ng-container [ngTemplateOutlet]="captionBox"></ng-container>
|
<ng-container [ngTemplateOutlet]="captionBox"></ng-container>
|
||||||
@@ -13,10 +12,10 @@
|
|||||||
}
|
}
|
||||||
<div class="grid grid-cols-1 gap-3" [ngClass]="{ 'pt-4': hasCaption }">
|
<div class="grid grid-cols-1 gap-3" [ngClass]="{ 'pt-4': hasCaption }">
|
||||||
@for (item of items; track `gridView_${$index}`) {
|
@for (item of items; track `gridView_${$index}`) {
|
||||||
<div class="card border border-surface-border bg-surface-0! mb-0! rounded-2xl p-4!">
|
<div class="card border-surface-border bg-surface-card! mb-0! rounded-2xl border p-4!">
|
||||||
<div [ngClass]="{ listKeyValue: true, 'mb-2': expandable }">
|
<div [ngClass]="{ listKeyValue: true, 'mb-2': expandable }">
|
||||||
@for (col of columns; track `gridView_${col.field.toString()}_${$index}`) {
|
@for (col of columns; track `gridView_${col.field.toString()}_${$index}`) {
|
||||||
@if (col.type !== "index") {
|
@if (col.type !== 'index') {
|
||||||
<app-key-value [label]="col.header" [variant]="col.variant">
|
<app-key-value [label]="col.header" [variant]="col.variant">
|
||||||
<app-page-data-value [item]="item" [column]="col" (thumbnailClick)="openThumbnailModal($event)" />
|
<app-page-data-value [item]="item" [column]="col" (thumbnailClick)="openThumbnailModal($event)" />
|
||||||
</app-key-value>
|
</app-key-value>
|
||||||
@@ -25,10 +24,10 @@
|
|||||||
</div>
|
</div>
|
||||||
@if (expandable) {
|
@if (expandable) {
|
||||||
<p-accordion [unstyled]="true" [value]="['0']">
|
<p-accordion [unstyled]="true" [value]="['0']">
|
||||||
<p-accordion-panel value="0" class="border! rounded-lg! overflow-hidden">
|
<p-accordion-panel value="0" class="overflow-hidden rounded-lg! border!">
|
||||||
<p-accordion-header class="bg-surface-200! text-text-color! py-2!">
|
<p-accordion-header class="bg-surface-200! text-text-color! py-2!">
|
||||||
<ng-template #toggleicon let-active="active">
|
<ng-template #toggleicon let-active="active">
|
||||||
<div class="flex items-center gap-4 w-full">
|
<div class="flex w-full items-center gap-4">
|
||||||
<i [ngClass]="{ 'pi pi-chevron-left text-xs! transition': true, '-rotate-90': active }"></i>
|
<i [ngClass]="{ 'pi pi-chevron-left text-xs! transition': true, '-rotate-90': active }"></i>
|
||||||
جزییات بیشتر
|
جزییات بیشتر
|
||||||
</div>
|
</div>
|
||||||
@@ -37,13 +36,12 @@
|
|||||||
<p-accordion-content>
|
<p-accordion-content>
|
||||||
<div class="listKeyValue pt-4">
|
<div class="listKeyValue pt-4">
|
||||||
@for (col of expandColumns; track `gridView_expand_${col.field.toString()}_${$index}`) {
|
@for (col of expandColumns; track `gridView_expand_${col.field.toString()}_${$index}`) {
|
||||||
@if (col.type !== "index") {
|
@if (col.type !== 'index') {
|
||||||
<app-key-value [label]="col.header" [variant]="col.variant">
|
<app-key-value [label]="col.header" [variant]="col.variant">
|
||||||
<app-page-data-value
|
<app-page-data-value
|
||||||
[item]="item[expandableItemKey!]"
|
[item]="item[expandableItemKey!]"
|
||||||
[column]="col"
|
[column]="col"
|
||||||
(thumbnailClick)="openThumbnailModal($event)"
|
(thumbnailClick)="openThumbnailModal($event)" />
|
||||||
/>
|
|
||||||
</app-key-value>
|
</app-key-value>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,7 +52,7 @@
|
|||||||
}
|
}
|
||||||
@if (showEdit || showDelete || showDetails) {
|
@if (showEdit || showDelete || showDetails) {
|
||||||
<hr class="my-2" />
|
<hr class="my-2" />
|
||||||
<div class="flex justify-center gap-2 mt-4">
|
<div class="mt-4 flex justify-center gap-2">
|
||||||
@if (showEdit) {
|
@if (showEdit) {
|
||||||
<p-button
|
<p-button
|
||||||
icon="pi pi-pencil"
|
icon="pi pi-pencil"
|
||||||
@@ -62,8 +60,7 @@
|
|||||||
size="small"
|
size="small"
|
||||||
outlined
|
outlined
|
||||||
severity="secondary"
|
severity="secondary"
|
||||||
(click)="edit(item)"
|
(click)="edit(item)">
|
||||||
>
|
|
||||||
</p-button>
|
</p-button>
|
||||||
}
|
}
|
||||||
@if (showDelete) {
|
@if (showDelete) {
|
||||||
@@ -77,8 +74,7 @@
|
|||||||
size="small"
|
size="small"
|
||||||
outlined
|
outlined
|
||||||
severity="primary"
|
severity="primary"
|
||||||
(click)="details(item)"
|
(click)="details(item)">
|
||||||
>
|
|
||||||
</p-button>
|
</p-button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -87,7 +83,7 @@
|
|||||||
}
|
}
|
||||||
@if (loading) {
|
@if (loading) {
|
||||||
@for (i of [1, 2, 3, 4]; track `grid_view_loading${$index}`) {
|
@for (i of [1, 2, 3, 4]; track `grid_view_loading${$index}`) {
|
||||||
<div class="w-full h-40">
|
<div class="h-40 w-full">
|
||||||
<p-skeleton height="100%"></p-skeleton>
|
<p-skeleton height="100%"></p-skeleton>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="h-full flex flex-col gap-4 cardShadow">
|
<div class="cardShadow flex h-full flex-col gap-4">
|
||||||
<p-table
|
<p-table
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
[scrollable]="true"
|
[scrollable]="true"
|
||||||
@@ -9,9 +9,8 @@
|
|||||||
[showFirstLastIcon]="false"
|
[showFirstLastIcon]="false"
|
||||||
[expandedRowKeys]="expandedRows"
|
[expandedRowKeys]="expandedRows"
|
||||||
[dataKey]="dataKey"
|
[dataKey]="dataKey"
|
||||||
class="max-sm:hidden! grow flex! flex-col overflow-hidden"
|
class="flex! grow flex-col overflow-hidden max-sm:hidden!"
|
||||||
[tableStyleClass]="!items.length && !loading ? 'h-full' : ''"
|
[tableStyleClass]="!items.length && !loading ? 'h-full' : ''">
|
||||||
>
|
|
||||||
@if (captionBox) {
|
@if (captionBox) {
|
||||||
<ng-template #caption>
|
<ng-template #caption>
|
||||||
<ng-container [ngTemplateOutlet]="captionBox"> </ng-container>
|
<ng-container [ngTemplateOutlet]="captionBox"> </ng-container>
|
||||||
@@ -24,14 +23,13 @@
|
|||||||
<th style="width: 3rem"></th>
|
<th style="width: 3rem"></th>
|
||||||
}
|
}
|
||||||
@if (showIndex) {
|
@if (showIndex) {
|
||||||
<th [style]="{ width: '3rem', minWidth: '3rem' }"></th>
|
<th [style]="{ width: '3rem', minWidth: '3rem' }">#</th>
|
||||||
}
|
}
|
||||||
@for (col of columns; track col.header) {
|
@for (col of columns; track col.header) {
|
||||||
<th
|
<th
|
||||||
[style]="
|
[style]="
|
||||||
col.type === 'index' ? { width: '3rem', minWidth: '3rem' } : { width: col.width, minWidth: col.minWidth }
|
col.type === 'index' ? { width: '3rem', minWidth: '3rem' } : { width: col.width, minWidth: col.minWidth }
|
||||||
"
|
">
|
||||||
>
|
|
||||||
{{ col.header }}
|
{{ col.header }}
|
||||||
</th>
|
</th>
|
||||||
}
|
}
|
||||||
@@ -52,8 +50,7 @@
|
|||||||
[text]="true"
|
[text]="true"
|
||||||
[rounded]="true"
|
[rounded]="true"
|
||||||
[plain]="true"
|
[plain]="true"
|
||||||
[icon]="expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-left'"
|
[icon]="expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-left'" />
|
||||||
/>
|
|
||||||
</td>
|
</td>
|
||||||
}
|
}
|
||||||
@if (showIndex) {
|
@if (showIndex) {
|
||||||
@@ -75,8 +72,7 @@
|
|||||||
[showEdit]="showEdit"
|
[showEdit]="showEdit"
|
||||||
(edit)="edit(item)"
|
(edit)="edit(item)"
|
||||||
(delete)="remove(item)"
|
(delete)="remove(item)"
|
||||||
(details)="details(item)"
|
(details)="details(item)"></td>
|
||||||
></td>
|
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@@ -96,9 +92,8 @@
|
|||||||
stripedRows
|
stripedRows
|
||||||
[showFirstLastIcon]="false"
|
[showFirstLastIcon]="false"
|
||||||
[expandedRowKeys]="expandedRows"
|
[expandedRowKeys]="expandedRows"
|
||||||
class="grow flex! flex-col overflow-hidden"
|
class="flex! grow flex-col overflow-hidden"
|
||||||
[tableStyleClass]="!item.items?.length && !loading ? 'h-full' : ''"
|
[tableStyleClass]="!item.items?.length && !loading ? 'h-full' : ''">
|
||||||
>
|
|
||||||
<ng-template #header let-columns>
|
<ng-template #header let-columns>
|
||||||
<tr>
|
<tr>
|
||||||
@for (col of expandColumns; track col.header) {
|
@for (col of expandColumns; track col.header) {
|
||||||
@@ -107,8 +102,7 @@
|
|||||||
col.type === 'index'
|
col.type === 'index'
|
||||||
? { width: '3rem', minWidth: '3rem' }
|
? { width: '3rem', minWidth: '3rem' }
|
||||||
: { width: col.width, minWidth: col.minWidth }
|
: { width: col.width, minWidth: col.minWidth }
|
||||||
"
|
">
|
||||||
>
|
|
||||||
{{ col.header }}
|
{{ col.header }}
|
||||||
</th>
|
</th>
|
||||||
}
|
}
|
||||||
@@ -120,14 +114,13 @@
|
|||||||
@for (col of expandColumns; track col.field) {
|
@for (col of expandColumns; track col.field) {
|
||||||
<td>
|
<td>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
@if (col.type === "index") {
|
@if (col.type === 'index') {
|
||||||
{{ i * (currentPage || 1) + 1 }}
|
{{ i * (currentPage || 1) + 1 }}
|
||||||
} @else {
|
} @else {
|
||||||
<app-page-data-value
|
<app-page-data-value
|
||||||
[item]="item"
|
[item]="item"
|
||||||
[column]="col"
|
[column]="col"
|
||||||
(thumbnailClick)="openThumbnailModal($event)"
|
(thumbnailClick)="openThumbnailModal($event)" />
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
}
|
}
|
||||||
@@ -142,8 +135,7 @@
|
|||||||
[description]="emptyPlaceholderDescription"
|
[description]="emptyPlaceholderDescription"
|
||||||
[ctaLabel]="emptyPlaceholderCtaLabel || addNewCtaLabel"
|
[ctaLabel]="emptyPlaceholderCtaLabel || addNewCtaLabel"
|
||||||
[showCTA]="showAdd"
|
[showCTA]="showAdd"
|
||||||
(ctaClick)="openAddForm()"
|
(ctaClick)="openAddForm()"></uikit-empty-state>
|
||||||
></uikit-empty-state>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@@ -155,8 +147,7 @@
|
|||||||
[label]="col.header"
|
[label]="col.header"
|
||||||
[value]="item[expandableItemKey][col.field]"
|
[value]="item[expandableItemKey][col.field]"
|
||||||
[type]="col.type || 'simple'"
|
[type]="col.type || 'simple'"
|
||||||
[variant]="col.variant"
|
[variant]="col.variant" />
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ export class PageDataListComponent<I = any> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
get showPaginator() {
|
get showPaginator() {
|
||||||
return !!(this.totalPages && this.perPage && this.totalPages > this.perPage);
|
return !!(this.totalPages && this.totalPages > 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
getPreviewClasses(item: Record<string, any>, column: IColumn): any {
|
getPreviewClasses(item: Record<string, any>, column: IColumn): any {
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ import { IColumn } from './page-data-list.component';
|
|||||||
template: `
|
template: `
|
||||||
@if (column.type === 'thumbnail') {
|
@if (column.type === 'thumbnail') {
|
||||||
<div
|
<div
|
||||||
class="w-20 h-20 rounded-2xl overflow-hidden bg-surface-100 cursor-pointer"
|
class="bg-surface-100 h-20 w-20 cursor-pointer overflow-hidden rounded-2xl"
|
||||||
(click)="thumbnailClick.emit(item)"
|
(click)="thumbnailClick.emit(item)"
|
||||||
>
|
>
|
||||||
@if (readFieldValue(item, column.field)) {
|
@if (readFieldValue(item, column.field)) {
|
||||||
<img [src]="readFieldValue(item, column.field)" class="w-full h-full object-cover" />
|
<img [src]="readFieldValue(item, column.field)" class="h-full w-full object-cover" />
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
} @else if (column.variant === 'tag') {
|
} @else if (column.variant === 'tag') {
|
||||||
@@ -68,12 +68,19 @@ export class PageDataValueComponent {
|
|||||||
|
|
||||||
let data = item[String(field)];
|
let data = item[String(field)];
|
||||||
if (column.type === 'nested') {
|
if (column.type === 'nested') {
|
||||||
|
try {
|
||||||
const path = column.nestedOption?.path;
|
const path = column.nestedOption?.path;
|
||||||
if (!path) return '-';
|
if (!path) return '-';
|
||||||
data = path
|
data = path
|
||||||
.split('.')
|
.split('.')
|
||||||
.reduce((obj: any, key: string) => (obj && obj[key] !== undefined ? obj[key] : null), item);
|
.reduce(
|
||||||
|
(obj: any, key: string) => (obj && obj[key] !== undefined ? obj[key] : null),
|
||||||
|
item
|
||||||
|
);
|
||||||
type = column.nestedOption?.type || 'simple';
|
type = column.nestedOption?.type || 'simple';
|
||||||
|
} catch (e) {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<uikit-field label="رمز عبور" [pSize]="size" [control]="passwordControl">
|
<uikit-field [label]="passwordFieldLabel()" [pSize]="size" [control]="passwordControl">
|
||||||
<p-password
|
<p-password
|
||||||
id="password1"
|
id="password1"
|
||||||
name="password"
|
name="password"
|
||||||
@@ -8,14 +8,13 @@
|
|||||||
[fluid]="fluid"
|
[fluid]="fluid"
|
||||||
[feedback]="false"
|
[feedback]="false"
|
||||||
[size]="size"
|
[size]="size"
|
||||||
[invalid]="passwordControl.touched && passwordControl.invalid"
|
[invalid]="passwordControl.touched && passwordControl.invalid" />
|
||||||
/>
|
<span class="text-muted-color mt-1 text-xs">
|
||||||
<span class="text-xs mt-1 text-muted-color">
|
|
||||||
{{ hint }}
|
{{ hint }}
|
||||||
</span>
|
</span>
|
||||||
</uikit-field>
|
</uikit-field>
|
||||||
|
|
||||||
<uikit-field label="تکرار رمز عبور" [pSize]="size" [control]="confirmPasswordControl">
|
<uikit-field [label]="confirmPasswordFieldLabel()" [pSize]="size" [control]="confirmPasswordControl">
|
||||||
<p-password
|
<p-password
|
||||||
id="confirmPassword"
|
id="confirmPassword"
|
||||||
name="confirmPassword"
|
name="confirmPassword"
|
||||||
@@ -25,6 +24,5 @@
|
|||||||
[fluid]="fluid"
|
[fluid]="fluid"
|
||||||
[feedback]="false"
|
[feedback]="false"
|
||||||
[size]="size"
|
[size]="size"
|
||||||
[invalid]="confirmPasswordControl.touched && confirmPasswordControl.invalid"
|
[invalid]="confirmPasswordControl.touched && confirmPasswordControl.invalid" />
|
||||||
/>
|
|
||||||
</uikit-field>
|
</uikit-field>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { UikitFieldComponent } from '@/uikit';
|
import { UikitFieldComponent } from '@/uikit';
|
||||||
import { Component, Input } from '@angular/core';
|
import { Component, computed, Input } from '@angular/core';
|
||||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { Password } from 'primeng/password';
|
import { Password } from 'primeng/password';
|
||||||
|
|
||||||
@@ -14,4 +14,10 @@ export class SharedPasswordInputComponent {
|
|||||||
@Input() hint: string = 'رمز باید حداقل ۶ کاراکتر باشد.';
|
@Input() hint: string = 'رمز باید حداقل ۶ کاراکتر باشد.';
|
||||||
@Input() fluid: boolean = true;
|
@Input() fluid: boolean = true;
|
||||||
@Input() size: 'small' | 'large' = 'large';
|
@Input() size: 'small' | 'large' = 'large';
|
||||||
|
@Input() isRenewal = false;
|
||||||
|
|
||||||
|
passwordFieldLabel = computed(() => (this.isRenewal ? 'رمز عبور جدید' : 'رمز عبور'));
|
||||||
|
confirmPasswordFieldLabel = computed(() =>
|
||||||
|
this.isRenewal ? 'تکرار رمز عبور جدید' : 'تکرار رمز عبور'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
[discountAmount]="form.controls.discount_amount.value || 0"
|
[discountAmount]="form.controls.discount_amount.value || 0"
|
||||||
[taxAmount]="taxAmount()" />
|
[taxAmount]="taxAmount()" />
|
||||||
@if (!isCorrection) {
|
@if (!isCorrection) {
|
||||||
<button pButton class="w-full sm:w-auto" (click)="submit()">{{ preparedCTAText() }}</button>
|
<button pButton class="w-full sm:w-auto" size="large" (click)="submit()">{{ preparedCTAText() }}</button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
[discountAmount]="discountAmount()"
|
[discountAmount]="discountAmount()"
|
||||||
[taxAmount]="taxAmount()" />
|
[taxAmount]="taxAmount()" />
|
||||||
@if (!isCorrection) {
|
@if (!isCorrection) {
|
||||||
<button pButton class="w-full sm:w-auto" (onClick)="submit()">{{ preparedCTAText() }}</button>
|
<button pButton class="w-full sm:w-auto" size="large" (onClick)="submit()">{{ preparedCTAText() }}</button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -2,13 +2,14 @@
|
|||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<uikit-label name="rapidInvoice"> انتخاب سال</uikit-label>
|
<uikit-label name="rapidInvoice"> انتخاب سال</uikit-label>
|
||||||
<select
|
<p-select
|
||||||
[(ngModel)]="selectedYearDraft"
|
[(ngModel)]="selectedYearDraft"
|
||||||
class="w-full rounded-xl border border-slate-200 bg-white px-3 py-2 text-slate-700 outline-none">
|
appendTo="body"
|
||||||
@for (yearItem of years; track yearItem.value) {
|
class="w-full"
|
||||||
<option [value]="yearItem.value">{{ yearItem.year }}</option>
|
[options]="years"
|
||||||
}
|
optionLabel="year"
|
||||||
</select>
|
optionValue="value">
|
||||||
|
</p-select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { Component, computed, EventEmitter, Input, Output, signal } from '@angular/core';
|
import { Component, computed, EventEmitter, Input, Output, signal } from '@angular/core';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { ButtonDirective, ButtonSeverity } from 'primeng/button';
|
import { ButtonDirective, ButtonSeverity } from 'primeng/button';
|
||||||
|
import { Select } from 'primeng/select';
|
||||||
import { SharedLightBottomsheetComponent } from '../dialog/light-bottomsheet.component';
|
import { SharedLightBottomsheetComponent } from '../dialog/light-bottomsheet.component';
|
||||||
|
|
||||||
type SeasonKey = 0 | 1 | 2 | 3;
|
type SeasonKey = 0 | 1 | 2 | 3;
|
||||||
@@ -23,6 +24,7 @@ interface SeasonItem {
|
|||||||
SharedLightBottomsheetComponent,
|
SharedLightBottomsheetComponent,
|
||||||
ButtonDirective,
|
ButtonDirective,
|
||||||
UikitLabelComponent,
|
UikitLabelComponent,
|
||||||
|
Select,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class SeasonPickerDialogComponent extends AbstractDialog {
|
export class SeasonPickerDialogComponent extends AbstractDialog {
|
||||||
|
|||||||
@@ -1,9 +1,21 @@
|
|||||||
<div class="border-surface-border bg-surface-card flex items-center gap-2 overflow-hidden rounded-lg border p-2">
|
<div class="border-surface-border bg-surface-card flex h-11 items-center gap-2 overflow-hidden rounded-lg border p-2">
|
||||||
<p-button icon="pi pi-chevron-right" size="small" text class="shrink-0" (onClick)="prevSeason()" />
|
<p-button
|
||||||
|
icon="pi pi-chevron-right"
|
||||||
|
size="small"
|
||||||
|
text
|
||||||
|
class="shrink-0"
|
||||||
|
[disabled]="!canGoPrev()"
|
||||||
|
(onClick)="prevSeason()" />
|
||||||
<div class="flex flex-1 cursor-pointer justify-center" (click)="openPicker()">
|
<div class="flex flex-1 cursor-pointer justify-center" (click)="openPicker()">
|
||||||
<span class="text-base font-semibold">{{ currentSeason() }}</span>
|
<span class="text-base font-semibold">{{ currentSeason() }}</span>
|
||||||
</div>
|
</div>
|
||||||
<p-button icon="pi pi-chevron-left" size="small" text class="shrink-0" (onClick)="nextSeason()" />
|
<p-button
|
||||||
|
icon="pi pi-chevron-left"
|
||||||
|
size="small"
|
||||||
|
text
|
||||||
|
class="shrink-0"
|
||||||
|
[disabled]="!canGoNext()"
|
||||||
|
(onClick)="nextSeason()" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if (isOpen()) {
|
@if (isOpen()) {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ interface SeasonItem {
|
|||||||
imports: [CommonModule, Button, SeasonPickerDialogComponent],
|
imports: [CommonModule, Button, SeasonPickerDialogComponent],
|
||||||
})
|
})
|
||||||
export class SeasonPickerComponent implements OnInit {
|
export class SeasonPickerComponent implements OnInit {
|
||||||
@Input() minYear = 1390;
|
@Input() minYear = 1404;
|
||||||
@Input() maxYear = Number(nowJalali(JALALI_DATE_FORMATS.YEAR));
|
@Input() maxYear = Number(nowJalali(JALALI_DATE_FORMATS.YEAR));
|
||||||
@Input() value!: Date;
|
@Input() value!: Date;
|
||||||
|
|
||||||
@@ -66,13 +66,29 @@ export class SeasonPickerComponent implements OnInit {
|
|||||||
this.isOpen.set(false);
|
this.isOpen.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canGoPrev(): boolean {
|
||||||
|
const index = this.selectedSeason();
|
||||||
|
const currentYear = this.selectedYear();
|
||||||
|
const nextSeason = index === 0 ? 3 : ((index - 1) as SeasonKey);
|
||||||
|
const nextYear = index === 0 ? currentYear - 1 : currentYear;
|
||||||
|
return this.isWithinBounds(nextYear, nextSeason);
|
||||||
|
}
|
||||||
|
|
||||||
|
canGoNext(): boolean {
|
||||||
|
const index = this.selectedSeason();
|
||||||
|
const currentYear = this.selectedYear();
|
||||||
|
const nextSeason = index === 3 ? 0 : ((index + 1) as SeasonKey);
|
||||||
|
const nextYear = index === 3 ? currentYear + 1 : currentYear;
|
||||||
|
return this.isWithinBounds(nextYear, nextSeason);
|
||||||
|
}
|
||||||
|
|
||||||
prevSeason(): void {
|
prevSeason(): void {
|
||||||
const index = this.selectedSeason();
|
const index = this.selectedSeason();
|
||||||
const currentYear = this.selectedYear();
|
const currentYear = this.selectedYear();
|
||||||
const nextSeason = index === 0 ? 3 : ((index - 1) as SeasonKey);
|
const nextSeason = index === 0 ? 3 : ((index - 1) as SeasonKey);
|
||||||
const nextYear = index === 0 ? currentYear - 1 : currentYear;
|
const nextYear = index === 0 ? currentYear - 1 : currentYear;
|
||||||
|
|
||||||
// if (!this.isWithinBounds(nextYear, nextSeason)) return;
|
if (!this.isWithinBounds(nextYear, nextSeason)) return;
|
||||||
|
|
||||||
this.selectedYear.set(nextYear);
|
this.selectedYear.set(nextYear);
|
||||||
this.selectedSeason.set(nextSeason);
|
this.selectedSeason.set(nextSeason);
|
||||||
@@ -85,14 +101,19 @@ export class SeasonPickerComponent implements OnInit {
|
|||||||
const nextSeason = index === 3 ? 0 : ((index + 1) as SeasonKey);
|
const nextSeason = index === 3 ? 0 : ((index + 1) as SeasonKey);
|
||||||
const nextYear = index === 3 ? currentYear + 1 : currentYear;
|
const nextYear = index === 3 ? currentYear + 1 : currentYear;
|
||||||
|
|
||||||
|
if (!this.isWithinBounds(nextYear, nextSeason)) return;
|
||||||
|
|
||||||
this.selectedYear.set(nextYear);
|
this.selectedYear.set(nextYear);
|
||||||
this.selectedSeason.set(nextSeason);
|
this.selectedSeason.set(nextSeason);
|
||||||
this.emitValue();
|
this.emitValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
submitPicker(value: { year: number; season: number }): void {
|
submitPicker(value: { year: number; season: number }): void {
|
||||||
|
const season = value.season as SeasonKey;
|
||||||
|
if (!this.isWithinBounds(value.year, season)) return;
|
||||||
|
|
||||||
this.selectedYear.set(value.year);
|
this.selectedYear.set(value.year);
|
||||||
this.selectedSeason.set(value.season as SeasonKey);
|
this.selectedSeason.set(season);
|
||||||
this.emitValue();
|
this.emitValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,11 @@ import { IListConfig } from './list-config.model';
|
|||||||
export const saleInvoiceListConfig: IListConfig = {
|
export const saleInvoiceListConfig: IListConfig = {
|
||||||
pageTitle: 'مدیریت صورتحسابهای فروش',
|
pageTitle: 'مدیریت صورتحسابهای فروش',
|
||||||
addNewCtaLabel: 'افزودن صورتحساب',
|
addNewCtaLabel: 'افزودن صورتحساب',
|
||||||
emptyPlaceholderTitle: 'صورتحسابی یافت نشد',
|
emptyPlaceholderTitle: 'صورتحسابی یافت نشد',
|
||||||
emptyPlaceholderDescription: 'برای افزودن صورتحساب، روی دکمهٔ بالا کلیک کنید.',
|
emptyPlaceholderDescription: 'برای افزودن صورتحساب، روی دکمهٔ بالا کلیک کنید.',
|
||||||
columns: [
|
columns: [
|
||||||
{ field: 'code', header: 'کد رهگیری' },
|
{ field: 'invoice_number', header: 'شماره' },
|
||||||
{
|
|
||||||
field: 'total_amount',
|
|
||||||
header: 'قیمت نهایی',
|
|
||||||
type: 'price',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
field: 'pos',
|
field: 'pos',
|
||||||
header: 'پایانه',
|
header: 'پایانه',
|
||||||
@@ -19,15 +15,24 @@ export const saleInvoiceListConfig: IListConfig = {
|
|||||||
return `${item.pos.name} (${item.pos.complex.name} - ${item.pos.complex.business_activity.name})`;
|
return `${item.pos.name} (${item.pos.complex.name} - ${item.pos.complex.business_activity.name})`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// field: 'consumer_account',
|
||||||
|
// header: 'ایجاد شده توسط',
|
||||||
|
// type: 'nested',
|
||||||
|
// nestedOption: { path: 'consumer_account.account.username' },
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
field: 'consumer_account',
|
field: 'total_amount',
|
||||||
header: 'ایجاد شده توسط',
|
header: 'مبلغ کل',
|
||||||
type: 'nested',
|
type: 'price',
|
||||||
nestedOption: { path: 'consumer_account.account.username' },
|
},
|
||||||
|
{
|
||||||
|
field: 'status',
|
||||||
|
header: 'وضعیت',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'invoice_date',
|
field: 'invoice_date',
|
||||||
header: 'تاریخ صورتحساب',
|
header: 'تاریخ',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
@if (totalPages > 1) {
|
@if (totalPages > 1) {
|
||||||
<div class="flex items-center justify-center gap-3 p-4">
|
<div class="flex items-center justify-center gap-3 p-4">
|
||||||
|
@if (totalPages > 5) {
|
||||||
|
<button
|
||||||
|
pButton
|
||||||
|
icon="pi pi-angle-double-right"
|
||||||
|
size="small"
|
||||||
|
severity="secondary"
|
||||||
|
outlined
|
||||||
|
[disabled]="loading || currentPage === 1"
|
||||||
|
(click)="goToFirstPage()"></button>
|
||||||
|
}
|
||||||
<button
|
<button
|
||||||
pButton
|
pButton
|
||||||
icon="pi pi-angle-right"
|
icon="pi pi-angle-right"
|
||||||
@@ -25,5 +35,15 @@
|
|||||||
outlined
|
outlined
|
||||||
[disabled]="loading || currentPage >= totalPages"
|
[disabled]="loading || currentPage >= totalPages"
|
||||||
(click)="nextPage()"></button>
|
(click)="nextPage()"></button>
|
||||||
|
@if (totalPages > 5) {
|
||||||
|
<button
|
||||||
|
pButton
|
||||||
|
icon="pi pi-angle-double-left"
|
||||||
|
size="small"
|
||||||
|
severity="secondary"
|
||||||
|
outlined
|
||||||
|
[disabled]="loading || currentPage === totalPages"
|
||||||
|
(click)="goToLastPage()"></button>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user