Compare commits
4 Commits
cd09b09e3b
...
88f45eee38
| Author | SHA1 | Date | |
|---|---|---|---|
| 88f45eee38 | |||
| 5fa07c7ee8 | |||
| 788f4023f3 | |||
| 2f67801700 |
@@ -100,6 +100,10 @@
|
|||||||
"input": "public-tis"
|
"input": "public-tis"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/assets/styles.scss",
|
||||||
|
"src/assets/psp.scss"
|
||||||
|
],
|
||||||
"budgets": [
|
"budgets": [
|
||||||
{
|
{
|
||||||
"maximumError": "3MB",
|
"maximumError": "3MB",
|
||||||
@@ -144,6 +148,10 @@
|
|||||||
"input": "public-tis"
|
"input": "public-tis"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/assets/styles.scss",
|
||||||
|
"src/assets/psp.scss"
|
||||||
|
],
|
||||||
"budgets": [
|
"budgets": [
|
||||||
{
|
{
|
||||||
"maximumError": "2.5MB",
|
"maximumError": "2.5MB",
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
<shared-dialog
|
<shared-dialog
|
||||||
header="ویرایش گذرواژه"
|
header="تغییر رمز عبور"
|
||||||
[(visible)]="visible"
|
[(visible)]="visible"
|
||||||
[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">
|
||||||
<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()" />
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<app-page-data-list
|
<app-page-data-list
|
||||||
pageTitle="لیست صورتحسابها"
|
pageTitle="صورتحسابها"
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
emptyPlaceholderTitle="تا به حال صورتحسابی توسط این پایانه ایجاد نشده است."
|
emptyPlaceholderTitle="تا به حال صورتحسابی توسط این پایانه ایجاد نشده است."
|
||||||
[items]="items()"
|
[items]="items()"
|
||||||
|
|||||||
+5
-6
@@ -1,11 +1,10 @@
|
|||||||
<app-card-data cardTitle="تغییر گذرواژه" [editable]="false">
|
<app-card-data cardTitle="تغییر رمز عبور" [editable]="false">
|
||||||
<form [formGroup]="form" (submit)="submit()" class="max-w-lg mx-auto">
|
<form [formGroup]="form" (submit)="submit()" class="mx-auto max-w-lg">
|
||||||
<shared-password-input
|
<shared-password-input
|
||||||
[passwordControl]="form.controls.password"
|
[passwordControl]="form.controls.password"
|
||||||
[confirmPasswordControl]="form.controls.confirmPassword"
|
[confirmPasswordControl]="form.controls.confirmPassword" />
|
||||||
/>
|
<button type="submit" pButton [disabled]="form.invalid || loading()" class="mx-auto w-full max-w-xs">
|
||||||
<button type="submit" pButton [disabled]="form.invalid || loading()" class="w-full max-w-xs mx-auto">
|
تغییر رمز عبور
|
||||||
تغییر گذرواژه
|
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</app-card-data>
|
</app-card-data>
|
||||||
|
|||||||
+2
-2
@@ -25,7 +25,7 @@ export class ConsumerResetPasswordCardComponent {
|
|||||||
password: fieldControl.password(),
|
password: fieldControl.password(),
|
||||||
confirmPassword: fieldControl.confirmPassword(),
|
confirmPassword: fieldControl.confirmPassword(),
|
||||||
},
|
},
|
||||||
{ validators: [MustMatch('password', 'confirmPassword')] },
|
{ validators: [MustMatch('password', 'confirmPassword')] }
|
||||||
);
|
);
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
@@ -40,7 +40,7 @@ export class ConsumerResetPasswordCardComponent {
|
|||||||
.pipe(finalize(() => this.loading.set(false)))
|
.pipe(finalize(() => this.loading.set(false)))
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.form.reset();
|
this.form.reset();
|
||||||
this.toastService.success({ text: 'گذرواژه با موفقیت بهروز شد.' });
|
this.toastService.success({ text: 'رمز عبور با موفقیت بهروز شد.' });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<app-page-data-list
|
<app-page-data-list
|
||||||
[pageTitle]="'لیست صورتحسابها'"
|
[pageTitle]="'صورتحسابها'"
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
emptyPlaceholderTitle="صورتحسابی یافت نشد"
|
emptyPlaceholderTitle="صورتحسابی یافت نشد"
|
||||||
[items]="items()"
|
[items]="items()"
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
<shared-dialog
|
<shared-dialog
|
||||||
header="ویرایش گذرواژه"
|
header="تغییر رمز عبور"
|
||||||
[(visible)]="visible"
|
[(visible)]="visible"
|
||||||
[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">
|
||||||
<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()" />
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+5
-6
@@ -1,11 +1,10 @@
|
|||||||
<app-card-data cardTitle="تغییر گذرواژه" [editable]="false">
|
<app-card-data cardTitle="تغییر رمز عبور" [editable]="false">
|
||||||
<form [formGroup]="form" (submit)="submit()" class="max-w-lg mx-auto">
|
<form [formGroup]="form" (submit)="submit()" class="mx-auto max-w-lg">
|
||||||
<shared-password-input
|
<shared-password-input
|
||||||
[passwordControl]="form.controls.password"
|
[passwordControl]="form.controls.password"
|
||||||
[confirmPasswordControl]="form.controls.confirmPassword"
|
[confirmPasswordControl]="form.controls.confirmPassword" />
|
||||||
/>
|
<button type="submit" pButton [disabled]="form.invalid || loading()" class="mx-auto w-full max-w-xs">
|
||||||
<button type="submit" pButton [disabled]="form.invalid || loading()" class="w-full max-w-xs mx-auto">
|
تغییر رمز عبور
|
||||||
تغییر گذرواژه
|
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</app-card-data>
|
</app-card-data>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export class PartnerResetPasswordCardComponent {
|
|||||||
password: fieldControl.password(),
|
password: fieldControl.password(),
|
||||||
confirmPassword: fieldControl.confirmPassword(),
|
confirmPassword: fieldControl.confirmPassword(),
|
||||||
},
|
},
|
||||||
{ validators: [MustMatch('password', 'confirmPassword')] },
|
{ validators: [MustMatch('password', 'confirmPassword')] }
|
||||||
);
|
);
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
@@ -40,7 +40,7 @@ export class PartnerResetPasswordCardComponent {
|
|||||||
.pipe(finalize(() => this.loading.set(false)))
|
.pipe(finalize(() => this.loading.set(false)))
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.form.reset();
|
this.form.reset();
|
||||||
this.toastService.success({ text: 'گذرواژه با موفقیت بهروز شد.' });
|
this.toastService.success({ text: 'رمز عبور با موفقیت بهروز شد.' });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<shared-change-password-form-dialog [(visible)]="visible" [loading]="submitLoading()" (onSubmit)="submit($event)" />
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { ToastService } from '@/core/services/toast.service';
|
||||||
|
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
|
||||||
|
import {
|
||||||
|
ChangePasswordFormDialogComponent,
|
||||||
|
IChangePasswordSubmitPayload,
|
||||||
|
} from '@/shared/components';
|
||||||
|
import { Component, inject, signal } from '@angular/core';
|
||||||
|
import { finalize } from 'rxjs';
|
||||||
|
import { PosChangePasswordService } from '../services/password';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'pos-change-password',
|
||||||
|
templateUrl: 'change-password.component.html',
|
||||||
|
imports: [ChangePasswordFormDialogComponent],
|
||||||
|
})
|
||||||
|
export class PosChangePasswordComponent extends AbstractDialog {
|
||||||
|
private readonly service = inject(PosChangePasswordService);
|
||||||
|
private readonly toastService = inject(ToastService);
|
||||||
|
|
||||||
|
submitLoading = signal(false);
|
||||||
|
|
||||||
|
submit(payload: IChangePasswordSubmitPayload) {
|
||||||
|
this.submitLoading.set(true);
|
||||||
|
|
||||||
|
this.service
|
||||||
|
.changePassword(payload.password)
|
||||||
|
.pipe(finalize(() => this.submitLoading.set(false)))
|
||||||
|
.subscribe(() => {
|
||||||
|
this.toastService.success({
|
||||||
|
text: 'تغییر رمز عبور با موفقیت انجام شد.',
|
||||||
|
});
|
||||||
|
this.submitLoading.set(false);
|
||||||
|
this.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,52 +25,27 @@
|
|||||||
|
|
||||||
@if (loading()) {
|
@if (loading()) {
|
||||||
<shared-page-loading />
|
<shared-page-loading />
|
||||||
} @else {
|
} @else if (error()) {
|
||||||
<!-- <div class="w-svw h-svh bg-surface-ground flex flex-col gap-4 p-4"> -->
|
@switch (error()?.status) {
|
||||||
<!-- <div class="w-full flex items-center gap-4 shrink-0 justify-between">
|
@case (412) {
|
||||||
<div class="flex gap-2 items-center">
|
<pos-choose-cards class="h-full" (onChoose)="onChoosePos()" />
|
||||||
@if (posInfo()) {
|
}
|
||||||
<div class="w-10 h-10">
|
@default {
|
||||||
<img [src]="placeholderLogo" alt="Logo" class="w-full h-full object-cover rounded-md bg-surface-card" />
|
<div class="flex h-full w-full items-center justify-center">
|
||||||
</div>
|
<p-card class="border-surface-border border">
|
||||||
<span class="text-lg font-bold">
|
<div class="flex shrink-0 flex-col items-center justify-between gap-2">
|
||||||
{{ posInfo()?.name }} ({{ posInfo()?.complex!.name }} - {{ posInfo()?.businessActivity!.name }})
|
<i class="pi pi-exclamation-triangle text-error mb-3 text-6xl!" aria-hidden="true"></i>
|
||||||
</span>
|
<span class="text-error mb-2 block text-xl font-semibold"> عدم دسترسی </span>
|
||||||
}
|
<p class="inline-block text-base">متاسفانه امکان دسترسی برای کاربر شما فراهم نیست</p>
|
||||||
</div>
|
<button pButton outlined severity="danger" class="mt-5 w-32" (click)="logout()">خروج</button>
|
||||||
<div class="flex gap-2 items-center">
|
</div>
|
||||||
<div class="bg-surface-card px-3 rounded-md shadow-sm h-9 flex items-center">
|
</p-card>
|
||||||
<span [jalaliDate]="now" jalaliFormat="dddd YYYY/MM/DD" class="text-base"></span>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="">
|
|
||||||
<p-menu #menu [model]="profileMenuItems" [popup]="true" />
|
|
||||||
<button pButton (click)="menu.toggle($event)" icon="pi pi-user" severity="contrast">
|
|
||||||
{{ posProfile()?.account?.username }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
@if (error()) {
|
|
||||||
@switch (error()?.status) {
|
|
||||||
@case (412) {
|
|
||||||
<pos-choose-cards class="h-full" (onChoose)="onChoosePos()" />
|
|
||||||
}
|
|
||||||
@default {
|
|
||||||
<div class="flex h-full w-full items-center justify-center">
|
|
||||||
<p-card class="border-surface-border border">
|
|
||||||
<div class="flex shrink-0 flex-col items-center justify-between gap-2">
|
|
||||||
<i class="pi pi-exclamation-triangle text-error mb-3 text-6xl!" aria-hidden="true"></i>
|
|
||||||
<span class="text-error mb-2 block text-xl font-semibold"> عدم دسترسی </span>
|
|
||||||
<p class="inline-block text-base">متاسفانه امکان دسترسی برای کاربر شما فراهم نیست</p>
|
|
||||||
<button pButton outlined severity="danger" class="mt-5 w-32" (click)="logout()">خروج</button>
|
|
||||||
</div>
|
|
||||||
</p-card>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} @else {
|
|
||||||
<pos-main-menu-sidebar [(visible)]="mainMenuVisible" />
|
|
||||||
<router-outlet></router-outlet>
|
|
||||||
}
|
}
|
||||||
<!-- </div> -->
|
} @else {
|
||||||
|
<pos-main-menu-sidebar [(visible)]="mainMenuVisible" />
|
||||||
|
<pos-change-password [(visible)]="changePasswordVisible" />
|
||||||
|
<router-outlet></router-outlet>
|
||||||
}
|
}
|
||||||
|
<!-- </div> -->
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Menu } from 'primeng/menu';
|
|||||||
import { finalize } from 'rxjs';
|
import { finalize } from 'rxjs';
|
||||||
import images from 'src/assets/images';
|
import images from 'src/assets/images';
|
||||||
import config from 'src/config';
|
import config from 'src/config';
|
||||||
|
import { PosChangePasswordComponent } from '../../components/change-password.component';
|
||||||
import { PosInfoStore, PosProfileStore } from '../../store';
|
import { PosInfoStore, PosProfileStore } from '../../store';
|
||||||
import { DeviceInfoStore } from '../../store/device.store';
|
import { DeviceInfoStore } from '../../store/device.store';
|
||||||
import { PosMainMenuSidebarComponent } from '../mainMenuSidebar/main-menu-sidebar.component';
|
import { PosMainMenuSidebarComponent } from '../mainMenuSidebar/main-menu-sidebar.component';
|
||||||
@@ -30,6 +31,7 @@ import { PosChooseCardsComponent } from './choose-pos.component';
|
|||||||
CommonModule,
|
CommonModule,
|
||||||
RouterLinkWithHref,
|
RouterLinkWithHref,
|
||||||
RouterOutlet,
|
RouterOutlet,
|
||||||
|
PosChangePasswordComponent,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class PosPagesLayoutComponent {
|
export class PosPagesLayoutComponent {
|
||||||
@@ -49,6 +51,7 @@ export class PosPagesLayoutComponent {
|
|||||||
private readonly layoutService = inject(LayoutService);
|
private readonly layoutService = inject(LayoutService);
|
||||||
|
|
||||||
mainMenuVisible = signal(false);
|
mainMenuVisible = signal(false);
|
||||||
|
changePasswordVisible = signal(false);
|
||||||
|
|
||||||
readonly posProfileLoading = computed(() => this.posProfileStore.loading());
|
readonly posProfileLoading = computed(() => this.posProfileStore.loading());
|
||||||
readonly posProfile = computed(() => this.posProfileStore.entity());
|
readonly posProfile = computed(() => this.posProfileStore.entity());
|
||||||
@@ -67,12 +70,21 @@ export class PosPagesLayoutComponent {
|
|||||||
this.authService.logout();
|
this.authService.logout();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
showChangePasswordDialog = () => {
|
||||||
|
this.changePasswordVisible.set(true);
|
||||||
|
};
|
||||||
|
|
||||||
profileMenuItems: MenuItem[] = [
|
profileMenuItems: MenuItem[] = [
|
||||||
{
|
{
|
||||||
label: 'راهنمای سامانه',
|
label: 'راهنمای سامانه',
|
||||||
icon: 'pi pi-question-circle',
|
icon: 'pi pi-question-circle',
|
||||||
disabled: true,
|
disabled: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'تغییر رمز عبور',
|
||||||
|
icon: 'pi pi-key',
|
||||||
|
command: this.showChangePasswordDialog,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'خروج',
|
label: 'خروج',
|
||||||
icon: 'pi pi-sign-out',
|
icon: 'pi pi-sign-out',
|
||||||
@@ -97,7 +109,7 @@ export class PosPagesLayoutComponent {
|
|||||||
.pipe(
|
.pipe(
|
||||||
finalize(() => {
|
finalize(() => {
|
||||||
this.layoutService.changeFullPageLoading(false);
|
this.layoutService.changeFullPageLoading(false);
|
||||||
}),
|
})
|
||||||
)
|
)
|
||||||
.subscribe();
|
.subscribe();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
<app-card-data cardTitle="تغییر گذرواژه" class="w-full">
|
|
||||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
|
||||||
<shared-password-input
|
|
||||||
[passwordControl]="form.controls.password"
|
|
||||||
[confirmPasswordControl]="form.controls.confirmPassword" />
|
|
||||||
|
|
||||||
<div class="flex w-full justify-end">
|
|
||||||
<button pButton label="ذخیره گذرواژه" [loading]="submitLoading()" class="w-full max-w-40"></button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</app-card-data>
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import { MustMatch } from '@/core/validators';
|
|
||||||
import { AbstractForm } from '@/shared/abstractClasses';
|
|
||||||
import { AppCardComponent } from '@/shared/components';
|
|
||||||
import { SharedPasswordInputComponent } from '@/shared/components/passwordInput/password-input.component';
|
|
||||||
import { fieldControl } from '@/shared/constants';
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { Component, inject } from '@angular/core';
|
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
|
||||||
import { ButtonDirective } from 'primeng/button';
|
|
||||||
import { tap } from 'rxjs';
|
|
||||||
import { IChangePasswordSubmitPayload } from './model';
|
|
||||||
import { PosChangePasswordService } from './services/main.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'pos-change-password-form',
|
|
||||||
templateUrl: './form.component.html',
|
|
||||||
imports: [
|
|
||||||
ReactiveFormsModule,
|
|
||||||
SharedPasswordInputComponent,
|
|
||||||
CommonModule,
|
|
||||||
ButtonDirective,
|
|
||||||
AppCardComponent,
|
|
||||||
],
|
|
||||||
})
|
|
||||||
export class PosChangePasswordFormDialogComponent extends AbstractForm<
|
|
||||||
IChangePasswordSubmitPayload,
|
|
||||||
any
|
|
||||||
> {
|
|
||||||
private readonly changePasswordService = inject(PosChangePasswordService);
|
|
||||||
|
|
||||||
form = this.fb.group(
|
|
||||||
{
|
|
||||||
password: fieldControl.password(),
|
|
||||||
confirmPassword: fieldControl.confirmPassword(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
validators: [MustMatch('password', 'confirmPassword')],
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
override submitForm() {
|
|
||||||
const payload = this.form.getRawValue().password!;
|
|
||||||
return this.changePasswordService.changePassword({ password: payload }).pipe(
|
|
||||||
tap({
|
|
||||||
next: (res) => {
|
|
||||||
this.form.reset();
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export interface IChangePasswordSubmitPayload {
|
|
||||||
password: string;
|
|
||||||
}
|
|
||||||
@@ -1,20 +1,28 @@
|
|||||||
<div class="flex h-full w-full flex-col items-center justify-center gap-6 p-4">
|
<div class="bg-surface-card flex h-full w-full flex-col gap-4 rounded-b-2xl p-4">
|
||||||
<app-card-data cardTitle="تنظیمات صدور صورتحساب" class="w-full">
|
<p-tabs value="0">
|
||||||
<div class="flex w-full flex-col gap-4">
|
<p-tablist>
|
||||||
@if (info()?.guild!.code.toLocaleLowerCase() === 'gold') {
|
<p-tab value="0">تنظیمات صدور صورتحساب</p-tab>
|
||||||
<pos-config-gold-price-form class="w-full" />
|
<p-tab value="1">تنظیمات پرینت</p-tab>
|
||||||
<hr />
|
</p-tablist>
|
||||||
}
|
<p-tabpanels class="mt-4">
|
||||||
<pos-config-rapid-invoice-form class="w-full" />
|
<p-tabpanel value="0">
|
||||||
<hr />
|
<div class="flex w-full flex-col gap-4">
|
||||||
<pos-config-send-to-fiscal-activation-form class="w-full" />
|
@if (info()?.guild!.code.toLocaleLowerCase() === 'gold') {
|
||||||
</div>
|
<pos-config-gold-price-form class="w-full" />
|
||||||
</app-card-data>
|
<hr />
|
||||||
<pos-change-password-form class="w-full" />
|
}
|
||||||
<app-card-data cardTitle="تنظیمات پرینت صورتحساب" class="w-full">
|
<pos-config-rapid-invoice-form class="w-full" />
|
||||||
<p-message variant="text" severity="info" icon="pi pi-info-circle">
|
<hr />
|
||||||
هریک از موارد زیر را که میخواهید در چاپ صورتحساب نمایش داده شوند را انتخاب کنید
|
<pos-config-send-to-fiscal-activation-form class="w-full" />
|
||||||
</p-message>
|
</div>
|
||||||
<pos-config-print-form class="mt-6 block w-full" (onClose)="returnToMainPage()" />
|
</p-tabpanel>
|
||||||
</app-card-data>
|
|
||||||
|
<p-tabpanel value="1">
|
||||||
|
<p-message variant="text" severity="info" icon="pi pi-info-circle">
|
||||||
|
هریک از موارد زیر را که میخواهید در چاپ صورتحساب نمایش داده شوند را انتخاب کنید
|
||||||
|
</p-message>
|
||||||
|
<pos-config-print-form class="mt-6 block w-full" (onClose)="returnToMainPage()" />
|
||||||
|
</p-tabpanel>
|
||||||
|
</p-tabpanels>
|
||||||
|
</p-tabs>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { PosInfoStore } from '@/domains/pos/store';
|
import { PosInfoStore } from '@/domains/pos/store';
|
||||||
import { AppCardComponent } from '@/shared/components';
|
|
||||||
import { Component, computed, inject } from '@angular/core';
|
import { Component, computed, inject } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { Message } from 'primeng/message';
|
import { Message } from 'primeng/message';
|
||||||
import { PosChangePasswordFormDialogComponent } from '../components/changePassword/form.component';
|
import { TabsModule } from 'primeng/tabs';
|
||||||
import { PosConfigGoldPriceFormComponent } from '../components/goldPrice/form.component';
|
import { PosConfigGoldPriceFormComponent } from '../components/goldPrice/form.component';
|
||||||
import { PosConfigPrintFormComponent } from '../components/print/form.component';
|
import { PosConfigPrintFormComponent } from '../components/print/form.component';
|
||||||
import { PosConfigRapidInvoiceFormComponent } from '../components/rapidInvoice/form.component';
|
import { PosConfigRapidInvoiceFormComponent } from '../components/rapidInvoice/form.component';
|
||||||
@@ -14,12 +13,11 @@ import { PosConfigSendToFiscalActivationFormComponent } from '../components/send
|
|||||||
templateUrl: './root.component.html',
|
templateUrl: './root.component.html',
|
||||||
imports: [
|
imports: [
|
||||||
PosConfigPrintFormComponent,
|
PosConfigPrintFormComponent,
|
||||||
AppCardComponent,
|
|
||||||
Message,
|
Message,
|
||||||
|
TabsModule,
|
||||||
PosConfigGoldPriceFormComponent,
|
PosConfigGoldPriceFormComponent,
|
||||||
PosConfigRapidInvoiceFormComponent,
|
PosConfigRapidInvoiceFormComponent,
|
||||||
PosConfigSendToFiscalActivationFormComponent,
|
PosConfigSendToFiscalActivationFormComponent,
|
||||||
PosChangePasswordFormDialogComponent,
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class PosConfigPageComponent {
|
export class PosConfigPageComponent {
|
||||||
@@ -27,6 +25,7 @@ export class PosConfigPageComponent {
|
|||||||
private readonly posInfoStore = inject(PosInfoStore);
|
private readonly posInfoStore = inject(PosInfoStore);
|
||||||
|
|
||||||
readonly info = computed(() => this.posInfoStore.entity());
|
readonly info = computed(() => this.posInfoStore.entity());
|
||||||
|
activeTabIndex = 0;
|
||||||
|
|
||||||
returnToMainPage() {
|
returnToMainPage() {
|
||||||
this.router.navigateByUrl('/');
|
this.router.navigateByUrl('/');
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
}
|
}
|
||||||
} @else {
|
} @else {
|
||||||
@for (good of items(); track good.id) {
|
@for (good of items(); track good.id) {
|
||||||
<div class="bg-surface-card flex items-center gap-2 rounded-lg px-3 py-1 shadow-xs">
|
<div class="bg-surface-card flex items-center gap-2 rounded-lg px-3 py-1">
|
||||||
<div class="flex grow items-center gap-2">
|
<div class="flex grow items-center gap-2">
|
||||||
<img
|
<img
|
||||||
[src]="good.image_url || goodPlaceholder"
|
[src]="good.image_url || goodPlaceholder"
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -16,11 +16,9 @@
|
|||||||
<div class="flex flex-wrap gap-2 px-4 pb-2">
|
<div class="flex flex-wrap gap-2 px-4 pb-2">
|
||||||
@for (filter of activeFilters(); track filter.key) {
|
@for (filter of activeFilters(); track filter.key) {
|
||||||
@if (filter.key !== 'page') {
|
@if (filter.key !== 'page') {
|
||||||
<p-chip
|
<p-chip removable class="border-surface-border border" (onRemove)="removeFilter(filter.key)">
|
||||||
removable
|
<span class="text-sm"> {{ filter.label }}: {{ filter.value }} </span>
|
||||||
[label]="filter.label + ': ' + filter.value"
|
</p-chip>
|
||||||
class="border-surface-border border"
|
|
||||||
(onRemove)="removeFilter(filter.key)" />
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+6
-6
@@ -1,18 +1,18 @@
|
|||||||
<p-card class="border-surface-border relative overflow-visible border p-0!">
|
<p-card class="border-surface-border relative overflow-visible border p-0!">
|
||||||
<div class="flex w-full items-center justify-between gap-4">
|
<div class="flex w-full items-center justify-between gap-4">
|
||||||
<span> {{ saleInvoice.invoice_number }} - {{ saleInvoice.code }} </span>
|
<span class="text-lg font-bold"> {{ saleInvoice.invoice_number }}</span>
|
||||||
<catalog-tax-provider-status-tag [status]="saleInvoice.status.value" [translate]="saleInvoice.status.translate" />
|
<catalog-tax-provider-status-tag [status]="saleInvoice.status.value" [translate]="saleInvoice.status.translate" />
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<div class="grid grid-cols-1 gap-4">
|
<div class="grid grid-cols-1 gap-3">
|
||||||
<app-key-value alignment="end" label="نوع صورتحساب">
|
<app-key-value alignment="end" label="تاریخ" [value]="saleInvoice.created_at" type="date" />
|
||||||
{{ preparedInvoiceType() }}
|
|
||||||
</app-key-value>
|
|
||||||
<app-key-value alignment="end" label="مبلغ کل" [value]="saleInvoice.total_amount" type="price" />
|
<app-key-value alignment="end" label="مبلغ کل" [value]="saleInvoice.total_amount" type="price" />
|
||||||
<app-key-value alignment="end" label="نوع صورتحساب">
|
<app-key-value alignment="end" label="نوع صورتحساب">
|
||||||
<catalog-invoice-type-tag [status]="saleInvoice.type.value" />
|
<catalog-invoice-type-tag [status]="saleInvoice.type.value" />
|
||||||
</app-key-value>
|
</app-key-value>
|
||||||
<app-key-value alignment="end" label="تاریخ صورتحساب" [value]="saleInvoice.created_at" type="date" />
|
<app-key-value alignment="end" label="مشتری">
|
||||||
|
{{ preparedInvoiceType() }}
|
||||||
|
</app-key-value>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<div class="flex items-center justify-center gap-4">
|
<div class="flex items-center justify-center gap-4">
|
||||||
|
|||||||
+12
-12
@@ -50,20 +50,20 @@ export class SaleInvoiceCardComponent {
|
|||||||
);
|
);
|
||||||
preparedInvoiceType = computed(() => {
|
preparedInvoiceType = computed(() => {
|
||||||
if (!this.saleInvoice) return '';
|
if (!this.saleInvoice) return '';
|
||||||
const { customer } = this.saleInvoice;
|
const { customer, unknown_customer } = this.saleInvoice;
|
||||||
|
|
||||||
if (customer) {
|
if (unknown_customer?.name || unknown_customer?.national_code) {
|
||||||
const { legal, individual } = customer;
|
return `${unknown_customer.name || unknown_customer?.national_code || 'رهگذر'} (نوع دوم)`;
|
||||||
let text = 'نوع اول - ';
|
} else if (customer) {
|
||||||
if (legal) {
|
const { legal, individual, type } = customer;
|
||||||
text += `حقوقی (${legal.company_name})`;
|
switch (type) {
|
||||||
|
case 'INDIVIDUAL':
|
||||||
|
return `${individual ? individual.first_name + ' ' + individual.last_name : '-----'} (نوع اول)`;
|
||||||
|
case 'LEGAL':
|
||||||
|
return `${legal?.name || '-----'} (نوع اول)`;
|
||||||
}
|
}
|
||||||
if (individual) {
|
|
||||||
text += `حقیقی (${individual.first_name} ${individual.last_name})`;
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
}
|
||||||
return 'نوع دوم (بدون اطلاعات خریدار)';
|
return 'رهگذر (نوع دوم)';
|
||||||
});
|
});
|
||||||
|
|
||||||
sendInvoice() {
|
sendInvoice() {
|
||||||
@@ -103,7 +103,7 @@ export class SaleInvoiceCardComponent {
|
|||||||
.retrySendToTsp(this.saleInvoice.id)
|
.retrySendToTsp(this.saleInvoice.id)
|
||||||
.pipe(finalize(() => this.resendingLoading.set(false)))
|
.pipe(finalize(() => this.resendingLoading.set(false)))
|
||||||
.subscribe((res) => {
|
.subscribe((res) => {
|
||||||
if (res.status === 'FAILURE') {
|
if (res.status === 'SEND_FAILURE') {
|
||||||
this.toastService.error({
|
this.toastService.error({
|
||||||
text: res.message || 'خطا در ارسال مجدد صورتحساب رخ داده است.',
|
text: res.message || 'خطا در ارسال مجدد صورتحساب رخ داده است.',
|
||||||
});
|
});
|
||||||
|
|||||||
+8
-15
@@ -2,6 +2,7 @@ import { Maybe } from '@/core';
|
|||||||
import ISummary from '@/core/models/summary';
|
import ISummary from '@/core/models/summary';
|
||||||
import { InvoiceTypes, TspProviderResponseStatus } from '@/shared/catalog';
|
import { InvoiceTypes, TspProviderResponseStatus } from '@/shared/catalog';
|
||||||
import { IEnumTranslate } from '@/shared/models/enum_translate.type';
|
import { IEnumTranslate } from '@/shared/models/enum_translate.type';
|
||||||
|
import { IIndividualCustomer, ILegalCustomer } from '../../shop/models';
|
||||||
|
|
||||||
export interface IPosSaleInvoicesSummaryRawResponse {
|
export interface IPosSaleInvoicesSummaryRawResponse {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -10,6 +11,7 @@ export interface IPosSaleInvoicesSummaryRawResponse {
|
|||||||
invoice_date: string;
|
invoice_date: string;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
total_amount: string;
|
total_amount: string;
|
||||||
|
unknown_customer: Partial<UnknownCoustomer>;
|
||||||
customer: Maybe<Customer>;
|
customer: Maybe<Customer>;
|
||||||
status: IEnumTranslate<TspProviderResponseStatus>;
|
status: IEnumTranslate<TspProviderResponseStatus>;
|
||||||
type: IEnumTranslate<InvoiceTypes>;
|
type: IEnumTranslate<InvoiceTypes>;
|
||||||
@@ -30,6 +32,10 @@ export interface IPosSaleInvoicesRawResponse extends IPosSaleInvoicesSummaryRawR
|
|||||||
|
|
||||||
export interface IPosSaleInvoicesResponse extends IPosSaleInvoicesRawResponse {}
|
export interface IPosSaleInvoicesResponse extends IPosSaleInvoicesRawResponse {}
|
||||||
|
|
||||||
|
interface UnknownCoustomer {
|
||||||
|
name?: string;
|
||||||
|
national_code?: string;
|
||||||
|
}
|
||||||
interface ConsumerAccount {
|
interface ConsumerAccount {
|
||||||
role: string;
|
role: string;
|
||||||
account: Account;
|
account: Account;
|
||||||
@@ -55,19 +61,6 @@ interface Payments {
|
|||||||
|
|
||||||
interface Customer {
|
interface Customer {
|
||||||
type: string;
|
type: string;
|
||||||
individual: Individual;
|
individual: IIndividualCustomer;
|
||||||
legal: Legal;
|
legal: ILegalCustomer;
|
||||||
}
|
|
||||||
|
|
||||||
interface Individual {
|
|
||||||
first_name: string;
|
|
||||||
last_name: string;
|
|
||||||
national_code: string;
|
|
||||||
mobile_number: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Legal {
|
|
||||||
company_name: string;
|
|
||||||
economic_code: string;
|
|
||||||
registration_number: string;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<div class="p-4">
|
<shared-sale-invoice-single-view
|
||||||
<shared-sale-invoice-single-view
|
[loading]="loading()"
|
||||||
[loading]="loading()"
|
[invoice]="invoice()"
|
||||||
[invoice]="invoice()"
|
[backRoute]="backRoute()"
|
||||||
[backRoute]="backRoute()"
|
[sendToTspLoading]="sendToTspLoading()"
|
||||||
[sendToTspLoading]="sendToTspLoading()"
|
[inquiryLoading]="inquiryLoading()"
|
||||||
[inquiryLoading]="inquiryLoading()"
|
[resendToTspLoading]="resendToTspLoading()"
|
||||||
(onSendToTsp)="sendToTsp()"
|
(onSendToTsp)="sendToTsp()"
|
||||||
(onInquiry)="inquiry()"
|
(onResendToTsp)="resendToTsp()"
|
||||||
(onCorrection)="correction($event)"
|
(onInquiry)="inquiry()"
|
||||||
(onReturnFromSale)="returnFromSale($event)"
|
(onCorrection)="correction($event)"
|
||||||
variant="pos" />
|
(onReturnFromSale)="returnFromSale($event)"
|
||||||
</div>
|
variant="pos" />
|
||||||
|
|||||||
@@ -78,7 +78,12 @@ export class PosSaleInvoiceComponent {
|
|||||||
this.resendToTspLoading.set(false);
|
this.resendToTspLoading.set(false);
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.subscribe();
|
.subscribe((res) => {
|
||||||
|
this.toastService.success({
|
||||||
|
text: res.message || 'ارسال مجدد صورتحساب با موفقیت انجام شد.',
|
||||||
|
});
|
||||||
|
this.store.updateStatus(res.status);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
correction(data: IPosCorrectionRequest) {
|
correction(data: IPosCorrectionRequest) {
|
||||||
this.correctionLoading.set(true);
|
this.correctionLoading.set(true);
|
||||||
|
|||||||
+14
-18
@@ -1,21 +1,20 @@
|
|||||||
<div class="border border-surface-border rounded-xl p-2 shadow-sm">
|
<div class="border-surface-border rounded-xl border p-2">
|
||||||
<div class="flex gap-3 items-center">
|
<div class="flex items-center gap-3">
|
||||||
<img
|
<img
|
||||||
[src]="inOrderGood.good.image_url || placeholderImage"
|
[src]="inOrderGood.good.image_url || placeholderImage"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
class="w-24 h-24 rounded-md bg-surface-100 object-cover shrink-0 border border-surface-border"
|
class="bg-surface-100 border-surface-border h-24 w-24 shrink-0 rounded-md border object-cover" />
|
||||||
/>
|
<div class="flex grow flex-col justify-between overflow-hidden">
|
||||||
<div class="flex flex-col grow justify-between overflow-hidden">
|
<div class="flex grow items-stretch gap-4">
|
||||||
<div class="flex items-stretch grow gap-4">
|
<div class="flex grow flex-col justify-between gap-2 overflow-hidden py-1">
|
||||||
<div class="flex flex-col justify-between gap-2 grow overflow-hidden py-1">
|
<div class="flex w-full shrink-0 flex-col overflow-hidden">
|
||||||
<div class="shrink-0 flex flex-col w-full overflow-hidden">
|
<div class="flex w-full items-center gap-1 overflow-hidden">
|
||||||
<div class="flex w-full overflow-hidden gap-1 items-center">
|
<span class="overflow-hidden text-lg font-bold text-nowrap text-ellipsis">
|
||||||
<span class="font-bold text-lg text-ellipsis text-nowrap overflow-hidden">
|
|
||||||
{{ inOrderGood.good.name }}
|
{{ inOrderGood.good.name }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-sm text-ellipsis text-nowrap overflow-hidden">
|
<span class="overflow-hidden text-sm text-nowrap text-ellipsis">
|
||||||
{{ inOrderGood.quantity }} {{ inOrderGood.good.measure_unit.name }}
|
{{ inOrderGood.quantity }} {{ inOrderGood.good.measure_unit.name }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -23,7 +22,7 @@
|
|||||||
<span [appPriceMask]="inOrderGood.total_amount"></span>
|
<span [appPriceMask]="inOrderGood.total_amount"></span>
|
||||||
} @else {
|
} @else {
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<span class="line-through text-muted-color text-xs" [appPriceMask]="inOrderGood.base_total_amount"></span>
|
<span class="text-muted-color text-xs line-through" [appPriceMask]="inOrderGood.base_total_amount"></span>
|
||||||
<span [appPriceMask]="inOrderGood.base_total_amount - inOrderGood.discount_amount"></span>
|
<span [appPriceMask]="inOrderGood.base_total_amount - inOrderGood.discount_amount"></span>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -36,8 +35,7 @@
|
|||||||
size="small"
|
size="small"
|
||||||
severity="secondary"
|
severity="secondary"
|
||||||
class="ms-auto"
|
class="ms-auto"
|
||||||
(click)="editOrderItem()"
|
(click)="editOrderItem()"></button>
|
||||||
></button>
|
|
||||||
<button
|
<button
|
||||||
pButton
|
pButton
|
||||||
type="button"
|
type="button"
|
||||||
@@ -45,8 +43,7 @@
|
|||||||
size="small"
|
size="small"
|
||||||
severity="danger"
|
severity="danger"
|
||||||
class="ms-auto"
|
class="ms-auto"
|
||||||
(click)="removeGoodFromOrder()"
|
(click)="removeGoodFromOrder()"></button>
|
||||||
></button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -58,6 +55,5 @@
|
|||||||
[(visible)]="visible"
|
[(visible)]="visible"
|
||||||
[good]="inOrderGood.good"
|
[good]="inOrderGood.good"
|
||||||
[initialValues]="inOrderGood"
|
[initialValues]="inOrderGood"
|
||||||
[orderItemId]="inOrderGood.id"
|
[orderItemId]="inOrderGood.id" />
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
import { PriceMaskDirective } from '@/shared/directives';
|
import { PriceMaskDirective } from '@/shared/directives';
|
||||||
import { Component, computed, inject } from '@angular/core';
|
import { Component, Input, inject } from '@angular/core';
|
||||||
import { Card } from 'primeng/card';
|
import { Card } from 'primeng/card';
|
||||||
import { PosLandingStore } from '../../store/main.store';
|
import { PosLandingStore } from '../../store/main.store';
|
||||||
|
|
||||||
|
type TOrderPriceInfo = {
|
||||||
|
totalBaseAmount: number;
|
||||||
|
discountAmount: number;
|
||||||
|
taxAmount: number;
|
||||||
|
totalAmount: number;
|
||||||
|
};
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'pos-order-price-info-card',
|
selector: 'pos-order-price-info-card',
|
||||||
templateUrl: './price-info-card.component.html',
|
templateUrl: './price-info-card.component.html',
|
||||||
@@ -10,6 +17,12 @@ import { PosLandingStore } from '../../store/main.store';
|
|||||||
})
|
})
|
||||||
export class POSOrderPriceInfoCardComponent {
|
export class POSOrderPriceInfoCardComponent {
|
||||||
private readonly store = inject(PosLandingStore);
|
private readonly store = inject(PosLandingStore);
|
||||||
|
@Input() info?: TOrderPriceInfo;
|
||||||
|
|
||||||
priceInfo = computed(() => this.store.orderPricingInfo());
|
priceInfo(): TOrderPriceInfo {
|
||||||
|
if (this.info) {
|
||||||
|
return this.info;
|
||||||
|
}
|
||||||
|
return this.store.orderPricingInfo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,32 @@
|
|||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<div class="w-full overflow-visible flex gap-3 px-4">
|
<div class="flex w-full gap-3 overflow-visible px-4">
|
||||||
@if (loading()) {
|
@if (loading()) {
|
||||||
@for (i of [1, 2, 3, 4, 5]; track i) {
|
@for (i of [1, 2, 3, 4, 5]; track i) {
|
||||||
<p-skeleton width="6rem" height="2.5rem" />
|
<div class="h-10 w-24 shrink-0">
|
||||||
|
<p-skeleton width="100%" height="100%" />
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
} @else {
|
} @else {
|
||||||
@for (category of categories(); track category.id) {
|
@for (category of categories(); track category.id) {
|
||||||
<div
|
<div
|
||||||
[class]="
|
[class]="
|
||||||
'h-10 rounded-lg px-3 flex items-center gap-3 border border-surface-border cursor-pointer bg-surface-100 hover:bg-surface-200 transition-all shrink-0' +
|
'border-surface-border bg-surface-100 hover:bg-surface-200 flex h-10 shrink-0 cursor-pointer items-center gap-3 rounded-lg border px-3 transition-all' +
|
||||||
(selectedCategory() === category.id ? ' bg-surface-card' : '')
|
(selectedCategory() === category.id ? ' bg-surface-card' : '')
|
||||||
"
|
"
|
||||||
(click)="changeSelectedCategory(category)"
|
(click)="changeSelectedCategory(category)">
|
||||||
>
|
<span class="text-muted-color text-sm font-bold"> {{ category.name }}</span>
|
||||||
<span class="text-sm text-muted-color font-bold"> {{ category.name }}</span>
|
|
||||||
<div
|
<div
|
||||||
[class]="
|
[class]="
|
||||||
'flex items-center justify-center py-0.5 px-2 rounded-sm bg-surface-300 text-xs text-muted-color' +
|
'bg-surface-300 text-muted-color flex items-center justify-center rounded-sm px-2 py-0.5 text-xs' +
|
||||||
(selectedCategory() === category.id ? ' bg-amber-400! text-white' : '')
|
(selectedCategory() === category.id ? ' bg-amber-400! text-white' : '')
|
||||||
"
|
">
|
||||||
>
|
|
||||||
<span>
|
<span>
|
||||||
{{ category.goods_count }}
|
{{ category.goods_count }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
<div class="invisible w-1 shrink-0 opacity-0"></div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
}
|
}
|
||||||
} @else {
|
} @else {
|
||||||
@for (good of visibleGoods(); track good.id) {
|
@for (good of visibleGoods(); track good.id) {
|
||||||
<div class="bg-surface-card flex items-center gap-2 rounded-lg px-3 py-1 shadow-xs">
|
<div class="bg-surface-card flex items-center gap-2 rounded-lg px-3 py-1">
|
||||||
<div class="flex grow items-center gap-2">
|
<div class="flex grow items-center gap-2">
|
||||||
<img
|
<img
|
||||||
[src]="good.image_url || goodPlaceholder"
|
[src]="good.image_url || goodPlaceholder"
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
pButton
|
pButton
|
||||||
class="border-surface-border bg-surface-0 sticky! inset-x-0 right-0 bottom-0 z-1200 w-full rounded-b-none! border-t px-4 py-3 shadow-[0_-4px_16px_rgba(0,0,0,0.08)] md:hidden!"
|
class="border-surface-border bg-surface-0 sticky! inset-x-0 right-0 bottom-0 z-120 w-full rounded-b-none! border-t px-4 py-3 md:hidden!"
|
||||||
(click)="openInvoiceBottomSheet()">
|
(click)="openInvoiceBottomSheet()">
|
||||||
<!-- [style.paddingBottom]="'calc(0.75rem + {{env(safe-area-inset-bottom)}})'" -->
|
<!-- [style.paddingBottom]="'calc(0.75rem + {{env(safe-area-inset-bottom)}})'" -->
|
||||||
<div class="mx-auto flex w-full max-w-3xl items-center justify-between">
|
<div class="mx-auto flex w-full max-w-3xl items-center justify-between">
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { PosLandingStore } from '../store/main.store';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'pos-shop',
|
selector: 'pos-shop',
|
||||||
templateUrl: './root.component.html',
|
templateUrl: './root.component.html',
|
||||||
host: { class: 'grow overflow-hidden' },
|
host: { class: 'grow' },
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
|
||||||
imports: [
|
imports: [
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<div
|
<div
|
||||||
class="text-surface-700 relative flex flex-col gap-4 overflow-hidden rounded-lg border px-4 py-4 pe-2"
|
class="text-surface-700 relative flex h-full flex-col gap-4 overflow-hidden rounded-lg border py-4 ps-3 pe-2"
|
||||||
[style.backgroundColor]="preparedInfo().bgColor"
|
[style.backgroundColor]="preparedInfo().bgColor"
|
||||||
[style.borderColor]="preparedInfo().borderColor"
|
[style.borderColor]="preparedInfo().borderColor"
|
||||||
(click)="showDetails()">
|
(click)="showDetails()">
|
||||||
|
|||||||
@@ -1,57 +1,59 @@
|
|||||||
<div class="flex flex-col gap-6 p-4">
|
<div class="flex min-h-[calc(100svh-5.5rem)] flex-col p-4 pt-0!">
|
||||||
<season-picker (onChange)="onDateChanged($event)" />
|
<div class="bg-surface-ground sticky top-[5.5rem] z-10 w-full pt-4!">
|
||||||
<div class="grid grid-cols-2 gap-4">
|
|
||||||
@if (loading()) {
|
|
||||||
@for (_ of [0, 1, 2, 3, 4, 5]; track $index) {
|
|
||||||
<div class="h-32 w-full">
|
|
||||||
<p-skeleton width="100%" height="100%"></p-skeleton>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
} @else {
|
|
||||||
<pos-statistics-invoice-type-card
|
|
||||||
type="all"
|
|
||||||
[loading]="loading()"
|
|
||||||
[totalAmount]="item()?.all?.total_amount"
|
|
||||||
[totalTaxAmount]="item()?.all?.total_tax"
|
|
||||||
[count]="item()?.all?.count"
|
|
||||||
(onClick)="toInvoicesPage('all')" />
|
|
||||||
<pos-statistics-invoice-type-card
|
|
||||||
type="success"
|
|
||||||
[loading]="loading()"
|
|
||||||
[totalAmount]="item()?.success?.total_amount"
|
|
||||||
[totalTaxAmount]="item()?.success?.total_tax"
|
|
||||||
[count]="item()?.success?.count"
|
|
||||||
(onClick)="toInvoicesPage('success')" />
|
|
||||||
<pos-statistics-invoice-type-card
|
|
||||||
type="failure"
|
|
||||||
[loading]="loading()"
|
|
||||||
[totalAmount]="item()?.failure?.total_amount"
|
|
||||||
[totalTaxAmount]="item()?.failure?.total_tax"
|
|
||||||
[count]="item()?.failure?.count"
|
|
||||||
(onClick)="toInvoicesPage('failure')" />
|
|
||||||
<pos-statistics-invoice-type-card
|
|
||||||
type="not_send"
|
|
||||||
[loading]="loading()"
|
|
||||||
[totalAmount]="item()?.not_send?.total_amount"
|
|
||||||
[totalTaxAmount]="item()?.not_send?.total_tax"
|
|
||||||
[count]="item()?.not_send?.count"
|
|
||||||
(onClick)="toInvoicesPage('not_send')" />
|
|
||||||
<pos-statistics-invoice-type-card
|
|
||||||
type="pending"
|
|
||||||
[loading]="loading()"
|
|
||||||
[totalAmount]="item()?.pending?.total_amount"
|
|
||||||
[totalTaxAmount]="item()?.pending?.total_tax"
|
|
||||||
[count]="item()?.pending?.count"
|
|
||||||
(onClick)="toInvoicesPage('pending')" />
|
|
||||||
<pos-statistics-invoice-type-card
|
|
||||||
type="not_original"
|
|
||||||
[loading]="loading()"
|
|
||||||
[totalAmount]="item()?.not_original?.total_amount"
|
|
||||||
[totalTaxAmount]="item()?.not_original?.total_tax"
|
|
||||||
[count]="item()?.not_original?.count" />
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div class="fixed inset-x-0 bottom-0 p-4">
|
|
||||||
<button pButton [routerLink]="shopRoute" size="large" class="w-full">ایجاد صورتحساب جدید</button>
|
<button pButton [routerLink]="shopRoute" size="large" class="w-full">ایجاد صورتحساب جدید</button>
|
||||||
</div>
|
</div>
|
||||||
|
<season-picker class="mt-6 mb-4 block w-full" (onChange)="onDateChanged($event)" />
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="grid grid-cols-2 items-stretch gap-2">
|
||||||
|
@if (loading()) {
|
||||||
|
@for (_ of [0, 1, 2, 3, 4, 5]; track $index) {
|
||||||
|
<div class="h-32 w-full">
|
||||||
|
<p-skeleton width="100%" height="100%"></p-skeleton>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
} @else {
|
||||||
|
<pos-statistics-invoice-type-card
|
||||||
|
type="all"
|
||||||
|
[loading]="loading()"
|
||||||
|
[totalAmount]="item()?.all?.total_amount"
|
||||||
|
[totalTaxAmount]="item()?.all?.total_tax"
|
||||||
|
[count]="item()?.all?.count"
|
||||||
|
(onClick)="toInvoicesPage('all')" />
|
||||||
|
<pos-statistics-invoice-type-card
|
||||||
|
type="success"
|
||||||
|
[loading]="loading()"
|
||||||
|
[totalAmount]="item()?.success?.total_amount"
|
||||||
|
[totalTaxAmount]="item()?.success?.total_tax"
|
||||||
|
[count]="item()?.success?.count"
|
||||||
|
(onClick)="toInvoicesPage('success')" />
|
||||||
|
<pos-statistics-invoice-type-card
|
||||||
|
type="failure"
|
||||||
|
[loading]="loading()"
|
||||||
|
[totalAmount]="item()?.failure?.total_amount"
|
||||||
|
[totalTaxAmount]="item()?.failure?.total_tax"
|
||||||
|
[count]="item()?.failure?.count"
|
||||||
|
(onClick)="toInvoicesPage('failure')" />
|
||||||
|
<pos-statistics-invoice-type-card
|
||||||
|
type="not_send"
|
||||||
|
[loading]="loading()"
|
||||||
|
[totalAmount]="item()?.not_send?.total_amount"
|
||||||
|
[totalTaxAmount]="item()?.not_send?.total_tax"
|
||||||
|
[count]="item()?.not_send?.count"
|
||||||
|
(onClick)="toInvoicesPage('not_send')" />
|
||||||
|
<pos-statistics-invoice-type-card
|
||||||
|
type="pending"
|
||||||
|
[loading]="loading()"
|
||||||
|
[totalAmount]="item()?.pending?.total_amount"
|
||||||
|
[totalTaxAmount]="item()?.pending?.total_tax"
|
||||||
|
[count]="item()?.pending?.count"
|
||||||
|
(onClick)="toInvoicesPage('pending')" />
|
||||||
|
<pos-statistics-invoice-type-card
|
||||||
|
type="not_original"
|
||||||
|
[loading]="loading()"
|
||||||
|
[totalAmount]="item()?.not_original?.total_amount"
|
||||||
|
[totalTaxAmount]="item()?.not_original?.total_tax"
|
||||||
|
[count]="item()?.not_original?.count" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+2
-3
@@ -1,7 +1,6 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { IChangePasswordSubmitPayload } from '../model';
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
@@ -9,7 +8,7 @@ import { IChangePasswordSubmitPayload } from '../model';
|
|||||||
export class PosChangePasswordService {
|
export class PosChangePasswordService {
|
||||||
constructor(private readonly http: HttpClient) {}
|
constructor(private readonly http: HttpClient) {}
|
||||||
|
|
||||||
changePassword(payload: IChangePasswordSubmitPayload): Observable<unknown> {
|
changePassword(password: string): Observable<unknown> {
|
||||||
return this.http.put('/api/v1/pos/update-password', payload);
|
return this.http.put('/api/v1/pos/update-password', { password });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,29 +1,27 @@
|
|||||||
<div class="layout-wrapper" [ngClass]="containerClass">
|
<div class="layout-wrapper flex min-h-svh flex-col" [ngClass]="containerClass">
|
||||||
@if (!fullPageLoading()) {
|
@if (!fullPageLoading()) {
|
||||||
<app-topbar
|
<app-topbar
|
||||||
[showMenu]="showMenu()"
|
[showMenu]="showMenu()"
|
||||||
[startTemplate]="topBarStartAction"
|
[startTemplate]="topBarStartAction"
|
||||||
[centerTemplate]="topBarCenterAction"
|
[centerTemplate]="topBarCenterAction"
|
||||||
[endTemplate]="topBarEndAction || topBarMoreAction"
|
[endTemplate]="topBarEndAction || topBarMoreAction" />
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
@if (showMenu()) {
|
@if (showMenu()) {
|
||||||
<app-sidebar></app-sidebar>
|
<app-sidebar></app-sidebar>
|
||||||
}
|
}
|
||||||
<div [class]="`layout-main-container ${!showMenu() ? 'hideMenu' : ''} grow ${isFullPage ? 'isFullPage' : ''}`">
|
<div
|
||||||
<div class="layout-main flex flex-col gap-4">
|
[class]="`flex flex-col justify-between ${!showMenu() ? 'hideMenu m0 ps-0' : ''} grow ${isFullPage ? 'isFullPage p-0 ps-0' : ''}`">
|
||||||
|
<div class="flex flex-1 flex-col gap-4">
|
||||||
@if (showBreadcrumb) {
|
@if (showBreadcrumb) {
|
||||||
<app-breadcrumb class="rounded-md overflow-hidden shrink-0" />
|
<app-breadcrumb class="shrink-0 overflow-hidden rounded-md" />
|
||||||
}
|
}
|
||||||
<div [class]="`rounded-md flex flex-col grow`">
|
<div [class]="`flex min-h-0 flex-1 flex-col rounded-md`">
|
||||||
<!-- style="container-type: size" -->
|
<!-- style="container-type: size" -->
|
||||||
<div class="h-full">
|
@if (content) {
|
||||||
@if (content) {
|
<ng-container [ngTemplateOutlet]="content"></ng-container>
|
||||||
<ng-container [ngTemplateOutlet]="content"></ng-container>
|
} @else {
|
||||||
} @else {
|
<router-outlet></router-outlet>
|
||||||
<router-outlet></router-outlet>
|
}
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<app-footer></app-footer>
|
<app-footer></app-footer>
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<div class="p-4">
|
<div class="min-h-dvh p-4">
|
||||||
<shared-sale-invoice-single-view [loading]="loading()" [invoice]="invoice()" />
|
<shared-sale-invoice-single-view [loading]="loading()" [invoice]="invoice()" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+9
-4
@@ -1,10 +1,10 @@
|
|||||||
import { MustMatch, password } from '@/core/validators';
|
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 { 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 { Component, EventEmitter, Output, input } from '@angular/core';
|
||||||
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
|
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
import { SharedPasswordInputComponent } from '../passwordInput/password-input.component';
|
import { SharedPasswordInputComponent } from '../passwordInput/password-input.component';
|
||||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
|
||||||
|
|
||||||
export interface IChangePasswordSubmitPayload {
|
export interface IChangePasswordSubmitPayload {
|
||||||
password: string;
|
password: string;
|
||||||
@@ -14,7 +14,12 @@ export interface IChangePasswordSubmitPayload {
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'shared-change-password-form-dialog',
|
selector: 'shared-change-password-form-dialog',
|
||||||
templateUrl: './change-password-form-dialog.component.html',
|
templateUrl: './change-password-form-dialog.component.html',
|
||||||
imports: [ReactiveFormsModule, SharedDialogComponent, FormFooterActionsComponent, SharedPasswordInputComponent],
|
imports: [
|
||||||
|
ReactiveFormsModule,
|
||||||
|
SharedDialogComponent,
|
||||||
|
FormFooterActionsComponent,
|
||||||
|
SharedPasswordInputComponent,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class ChangePasswordFormDialogComponent extends AbstractDialog {
|
export class ChangePasswordFormDialogComponent extends AbstractDialog {
|
||||||
title = input<string>('');
|
title = input<string>('');
|
||||||
@@ -31,11 +36,11 @@ export class ChangePasswordFormDialogComponent extends AbstractDialog {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
validators: [MustMatch('password', 'confirmPassword')],
|
validators: [MustMatch('password', 'confirmPassword')],
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
get dialogHeader() {
|
get dialogHeader() {
|
||||||
return this.title() ? `تغییر گذرواژه ${this.title()}` : 'تغییر گذرواژه';
|
return this.title() ? `تغییر رمز عبور ${this.title()}` : 'تغییر رمز عبور';
|
||||||
}
|
}
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="bg-surface-card flex flex-col items-center rounded p-8">
|
<div class="bg-surface-card flex flex-col items-center rounded p-8">
|
||||||
<div
|
<div
|
||||||
class="bg-primary text-primary-contrast -mt-20 inline-flex h-24 w-24 items-center justify-center rounded-full">
|
class="bg-primary text-primary-contrast -mt-20 inline-flex h-24 w-24 items-center justify-center rounded-full">
|
||||||
<i class="pi pi-question text-5xl!"></i>
|
<i class="pi pi-question rotate-y-180 text-5xl!"></i>
|
||||||
</div>
|
</div>
|
||||||
<span class="mt-6 mb-2 block text-2xl font-bold">{{ message.header }}</span>
|
<span class="mt-6 mb-2 block text-2xl font-bold">{{ message.header }}</span>
|
||||||
<p class="mb-0">{{ message.message }}</p>
|
<p class="mb-0">{{ message.message }}</p>
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
<div class="light-bottomsheet-mask" (click)="onMaskClick()"></div>
|
@if (rendered) {
|
||||||
|
<div class="light-bottomsheet-mask" (click)="onMaskClick()"></div>
|
||||||
|
|
||||||
<section class="light-bottomsheet-panel" [ngStyle]="style || { 'max-height': mobileDrawerHeight, height: 'auto' }">
|
<section class="light-bottomsheet-panel" [ngStyle]="style || { 'max-height': mobileDrawerHeight, height: 'auto' }">
|
||||||
<div class="light-bottomsheet-content">
|
<div class="light-bottomsheet-content">
|
||||||
@if (header || closable) {
|
@if (header || closable) {
|
||||||
<header class="light-bottomsheet-header border-surface-border border-b">
|
<header class="light-bottomsheet-header border-surface-border border-b">
|
||||||
<span class="text-xl font-bold">{{ header }}</span>
|
<span class="text-xl font-bold">{{ header }}</span>
|
||||||
@if (closable) {
|
@if (closable) {
|
||||||
<p-button
|
<p-button
|
||||||
type="button"
|
type="button"
|
||||||
icon="pi pi-times"
|
icon="pi pi-times"
|
||||||
text
|
text
|
||||||
size="small"
|
size="small"
|
||||||
class="light-bottomsheet-close"
|
class="light-bottomsheet-close"
|
||||||
(click)="onVisibilityChange(false)"
|
(click)="onVisibilityChange(false)"
|
||||||
aria-label="Close">
|
aria-label="Close">
|
||||||
</p-button>
|
</p-button>
|
||||||
}
|
}
|
||||||
</header>
|
</header>
|
||||||
}
|
}
|
||||||
<div class="light-bottomsheet-body p-4">
|
<div class="light-bottomsheet-body p-4">
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
</section>
|
}
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ import { Button } from 'primeng/button';
|
|||||||
'[attr.pfocustrap]': 'true',
|
'[attr.pfocustrap]': 'true',
|
||||||
'[attr.data-pc-name]': "'drawer'",
|
'[attr.data-pc-name]': "'drawer'",
|
||||||
'[attr.data-pc-section]': "'root'",
|
'[attr.data-pc-section]': "'root'",
|
||||||
'[attr.aria-hidden]': '!visible',
|
'[attr.aria-hidden]': '!rendered',
|
||||||
'[style.display]': 'visible ? "block" : "none"',
|
'[style.display]': 'rendered ? "block" : "none"',
|
||||||
'[style.--sheet-transition]': 'transitionOptions',
|
'[style.--sheet-transition]': 'transitionOptions',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -105,8 +105,11 @@ 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;
|
||||||
|
|
||||||
@Output() onHide = new EventEmitter<any>();
|
@Output() onHide = new EventEmitter<any>();
|
||||||
|
rendered = false;
|
||||||
|
private closeTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
private originalParent: Node | null = null;
|
private originalParent: Node | null = null;
|
||||||
private readonly defaultDrawerZIndex = 1102;
|
private readonly defaultDrawerZIndex = 1102;
|
||||||
@@ -123,21 +126,27 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy, OnCha
|
|||||||
const host = this.elementRef.nativeElement;
|
const host = this.elementRef.nativeElement;
|
||||||
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.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.clearCloseTimer();
|
||||||
|
this.rendered = true;
|
||||||
this.syncZIndex();
|
this.syncZIndex();
|
||||||
}
|
}
|
||||||
if (changes['visible']) {
|
if (changes['visible']) {
|
||||||
|
|
||||||
this.toggleBodyScrollLock(this.visible);
|
this.toggleBodyScrollLock(this.visible);
|
||||||
|
if (!this.visible) {
|
||||||
|
this.scheduleUnmount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
this.clearCloseTimer();
|
||||||
this.toggleBodyScrollLock(false);
|
this.toggleBodyScrollLock(false);
|
||||||
this.removeDrawer();
|
this.removeDrawer();
|
||||||
}
|
}
|
||||||
@@ -154,9 +163,12 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy, OnCha
|
|||||||
this.visibleChange.emit(nextValue);
|
this.visibleChange.emit(nextValue);
|
||||||
this.toggleBodyScrollLock(nextValue);
|
this.toggleBodyScrollLock(nextValue);
|
||||||
if (nextValue) {
|
if (nextValue) {
|
||||||
|
this.clearCloseTimer();
|
||||||
|
this.rendered = true;
|
||||||
this.syncZIndex();
|
this.syncZIndex();
|
||||||
}
|
}
|
||||||
if (!nextValue) {
|
if (!nextValue) {
|
||||||
|
this.scheduleUnmount();
|
||||||
this.onHide.emit();
|
this.onHide.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,4 +215,19 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy, OnCha
|
|||||||
: this.defaultDrawerZIndex;
|
: this.defaultDrawerZIndex;
|
||||||
this.renderer.setStyle(host, 'z-index', `${maxDrawerZIndex + 1}`);
|
this.renderer.setStyle(host, 'z-index', `${maxDrawerZIndex + 1}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private scheduleUnmount() {
|
||||||
|
this.clearCloseTimer();
|
||||||
|
this.closeTimer = setTimeout(() => {
|
||||||
|
if (!this.visible) {
|
||||||
|
this.rendered = false;
|
||||||
|
}
|
||||||
|
}, this.closeUnmountDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
private clearCloseTimer() {
|
||||||
|
if (!this.closeTimer) return;
|
||||||
|
clearTimeout(this.closeTimer);
|
||||||
|
this.closeTimer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<button
|
<button
|
||||||
pButton
|
pButton
|
||||||
[label]="submitLabel"
|
[label]="submitLabel"
|
||||||
type="submit"
|
[type]="submitBtnType"
|
||||||
class="min-w-28"
|
class="min-w-28"
|
||||||
[disabled]="disabled"
|
[disabled]="disabled"
|
||||||
[loading]="loading"
|
[loading]="loading"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export class FormFooterActionsComponent {
|
|||||||
@Input() cancelLabel = 'انصراف';
|
@Input() cancelLabel = 'انصراف';
|
||||||
@Input() loading = false;
|
@Input() loading = false;
|
||||||
@Input() disabled = false;
|
@Input() disabled = false;
|
||||||
|
@Input() submitBtnType: 'button' | 'submit' = 'submit';
|
||||||
@Output() onSubmit = new EventEmitter<void>();
|
@Output() onSubmit = new EventEmitter<void>();
|
||||||
@Output() onCancel = new EventEmitter<void>();
|
@Output() onCancel = new EventEmitter<void>();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex items-center p-4">
|
<div class="bg-surface-card flex items-center p-4">
|
||||||
<div class="grow">
|
<div class="grow">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
@if (backRoute) {
|
@if (backRoute) {
|
||||||
|
|||||||
@@ -1,28 +1,78 @@
|
|||||||
<form [formGroup]="form" (ngSubmit)="submit()">
|
<form [formGroup]="form" (ngSubmit)="submit()">
|
||||||
<field-invoice-date [control]="form.controls.invoice_date" />
|
<field-invoice-date [control]="form.controls.invoice_date" />
|
||||||
|
|
||||||
@for (item of initialValues || []; track item.id) {
|
<div class="mt-4 flex flex-col gap-3">
|
||||||
<div class="py-3">
|
@for (item of initialValues || []; track item.id) {
|
||||||
@if ($index) {
|
<div class="border-surface-border rounded-xl border p-2">
|
||||||
<hr class="h-1 w-full" />
|
<div class="flex items-center gap-3">
|
||||||
}
|
<img
|
||||||
<p-divider align="right">
|
[src]="item.good_snapshot.image_url || ''"
|
||||||
{{ $index + 1 }}- <b>{{ item.good_snapshot.name }}</b>
|
loading="lazy"
|
||||||
</p-divider>
|
decoding="async"
|
||||||
@if (isGold(item)) {
|
class="bg-surface-100 border-surface-border h-20 w-20 shrink-0 rounded-md border object-cover" />
|
||||||
<shared-gold-payload-form
|
<div class="flex grow flex-col gap-2 overflow-hidden py-1">
|
||||||
[initialValues]="$any(mappedInitialItems[$index])"
|
<div class="flex items-center justify-between gap-2">
|
||||||
[vatPercentage]="vatFromItem(item)"
|
<span class="overflow-hidden text-base font-bold text-nowrap text-ellipsis">
|
||||||
[isCorrection]="true" />
|
{{ item.good_snapshot.name }}
|
||||||
} @else {
|
</span>
|
||||||
<shared-standard-payload-form
|
<button
|
||||||
[initialValues]="$any(mappedInitialItems[$index])"
|
pButton
|
||||||
[measureUnit]="item.good_snapshot.measure_unit"
|
type="button"
|
||||||
[vatPercentage]="vatFromItem(item)"
|
icon="pi pi-pencil"
|
||||||
[isCorrection]="true" />
|
size="small"
|
||||||
}
|
outlined
|
||||||
</div>
|
(click)="openItemEditor($index)"></button>
|
||||||
}
|
</div>
|
||||||
|
@let preview = getItemPreview($index);
|
||||||
|
<span class="text-sm">{{ item.quantity }} {{ item.measure_unit_text }}</span>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
@if (!preview.discount_amount) {
|
||||||
|
<span [appPriceMask]="preview.base_total_amount"></span>
|
||||||
|
} @else {
|
||||||
|
<div class="flex flex-col items-end">
|
||||||
|
<span class="text-muted-color text-xs line-through" [appPriceMask]="preview.base_total_amount"></span>
|
||||||
|
<span [appPriceMask]="preview.base_total_amount - preview.discount_amount"></span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<pos-order-price-info-card [info]="getTotalPriceInfo()" />
|
||||||
|
|
||||||
<app-form-footer-actions />
|
<app-form-footer-actions />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<shared-light-bottomsheet
|
||||||
|
[(visible)]="showItemEditSheet"
|
||||||
|
[header]="`ویرایش ${activeItem()?.good_snapshot?.name || ''}`">
|
||||||
|
@if (activeItem()) {
|
||||||
|
<div class="pt-4">
|
||||||
|
@if (isGold(activeItem()!)) {
|
||||||
|
<shared-gold-payload-form
|
||||||
|
#goldEditor
|
||||||
|
[initialValues]="$any(activeInitialValue())"
|
||||||
|
[vatPercentage]="vatFromItem(activeItem()!)"
|
||||||
|
[isCorrection]="true" />
|
||||||
|
<div class="mt-6 flex justify-end gap-2">
|
||||||
|
<button pButton type="button" severity="secondary" (click)="backToList()">انصراف</button>
|
||||||
|
<button pButton type="button" (click)="saveActiveItemDraft(goldEditor)">ذخیره تغییرات</button>
|
||||||
|
</div>
|
||||||
|
} @else {
|
||||||
|
<shared-standard-payload-form
|
||||||
|
#standardEditor
|
||||||
|
[initialValues]="$any(activeInitialValue())"
|
||||||
|
[measureUnit]="activeItem()!.good_snapshot.measure_unit"
|
||||||
|
[vatPercentage]="vatFromItem(activeItem()!)"
|
||||||
|
[isCorrection]="true" />
|
||||||
|
<div class="mt-6 flex justify-end gap-2">
|
||||||
|
<button pButton type="button" severity="secondary" (click)="backToList()">انصراف</button>
|
||||||
|
<button pButton type="button" (click)="saveActiveItemDraft(undefined, standardEditor)">ذخیره تغییرات</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</shared-light-bottomsheet>
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import ISummary from '@/core/models/summary';
|
import ISummary from '@/core/models/summary';
|
||||||
|
import { POSOrderPriceInfoCardComponent } from '@/domains/pos/modules/shop/components/order/price-info-card.component';
|
||||||
import { IPosOrderItem } from '@/domains/pos/modules/shop/models';
|
import { IPosOrderItem } from '@/domains/pos/modules/shop/models';
|
||||||
import { AbstractForm } from '@/shared/abstractClasses';
|
import { AbstractForm } from '@/shared/abstractClasses';
|
||||||
import {
|
import {
|
||||||
SharedGoldPayloadFormComponent,
|
SharedGoldPayloadFormComponent,
|
||||||
SharedStandardPayloadFormComponent,
|
SharedStandardPayloadFormComponent,
|
||||||
} from '@/shared/components';
|
} from '@/shared/components';
|
||||||
|
import { PriceMaskDirective } from '@/shared/directives';
|
||||||
import { goldDiscountType } from '@/shared/localEnum/constants/goldDiscountType';
|
import { goldDiscountType } from '@/shared/localEnum/constants/goldDiscountType';
|
||||||
import { IGoldPayload, IStandardPayload } from '@/shared/models';
|
import { IGoldPayload, IStandardPayload } from '@/shared/models';
|
||||||
import { formatDate, GREGORIAN_DATE_FORMATS } from '@/utils';
|
import { formatDate, GREGORIAN_DATE_FORMATS } from '@/utils';
|
||||||
import { Component, Input, QueryList, SimpleChanges, ViewChildren } from '@angular/core';
|
import { Component, Input, signal, SimpleChanges } from '@angular/core';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
import { Divider } from 'primeng/divider';
|
import { ButtonDirective } from 'primeng/button';
|
||||||
|
import { SharedLightBottomsheetComponent } from '../../dialog';
|
||||||
import { FieldInvoiceDateComponent } from '../../fields/invoice_date.component';
|
import { FieldInvoiceDateComponent } from '../../fields/invoice_date.component';
|
||||||
import { FormFooterActionsComponent } from '../../formFooterActions/form-footer-actions.component';
|
import { FormFooterActionsComponent } from '../../formFooterActions/form-footer-actions.component';
|
||||||
import { CorrectionInvoiceFormValue, TCorrectionItemPayload } from '../models';
|
import { CorrectionInvoiceFormValue, TCorrectionItemPayload } from '../models';
|
||||||
@@ -25,7 +28,10 @@ import { IInvoiceItem } from '../sale-invoice-full-response.model';
|
|||||||
FormFooterActionsComponent,
|
FormFooterActionsComponent,
|
||||||
SharedGoldPayloadFormComponent,
|
SharedGoldPayloadFormComponent,
|
||||||
SharedStandardPayloadFormComponent,
|
SharedStandardPayloadFormComponent,
|
||||||
Divider,
|
ButtonDirective,
|
||||||
|
SharedLightBottomsheetComponent,
|
||||||
|
POSOrderPriceInfoCardComponent,
|
||||||
|
PriceMaskDirective,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class SharedCorrectionFormComponent extends AbstractForm<
|
export class SharedCorrectionFormComponent extends AbstractForm<
|
||||||
@@ -34,11 +40,7 @@ export class SharedCorrectionFormComponent extends AbstractForm<
|
|||||||
IInvoiceItem[]
|
IInvoiceItem[]
|
||||||
> {
|
> {
|
||||||
@Input({ required: true }) invoiceDate!: string;
|
@Input({ required: true }) invoiceDate!: string;
|
||||||
|
@Input() visible = false;
|
||||||
@ViewChildren(SharedGoldPayloadFormComponent)
|
|
||||||
goldForms!: QueryList<SharedGoldPayloadFormComponent>;
|
|
||||||
@ViewChildren(SharedStandardPayloadFormComponent)
|
|
||||||
standardForms!: QueryList<SharedStandardPayloadFormComponent>;
|
|
||||||
|
|
||||||
form = this.fb.group({
|
form = this.fb.group({
|
||||||
invoice_date: [this.invoiceDate],
|
invoice_date: [this.invoiceDate],
|
||||||
@@ -46,6 +48,8 @@ export class SharedCorrectionFormComponent extends AbstractForm<
|
|||||||
|
|
||||||
itemDrafts: Record<string, TCorrectionItemPayload> = {};
|
itemDrafts: Record<string, TCorrectionItemPayload> = {};
|
||||||
mappedInitialItems: TCorrectionItemPayload[] = [];
|
mappedInitialItems: TCorrectionItemPayload[] = [];
|
||||||
|
showItemEditSheet = signal(false);
|
||||||
|
activeItemIndex = signal<number | null>(null);
|
||||||
|
|
||||||
initForm() {
|
initForm() {
|
||||||
this.form.controls.invoice_date.setValue(
|
this.form.controls.invoice_date.setValue(
|
||||||
@@ -53,6 +57,8 @@ 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.showItemEditSheet.set(false);
|
||||||
|
this.activeItemIndex.set(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
override ngOnInit(): void {
|
override ngOnInit(): void {
|
||||||
@@ -60,6 +66,11 @@ export class SharedCorrectionFormComponent extends AbstractForm<
|
|||||||
}
|
}
|
||||||
|
|
||||||
override ngOnChanges(changes: SimpleChanges) {
|
override ngOnChanges(changes: SimpleChanges) {
|
||||||
|
if (changes['visible'] && !this.visible) {
|
||||||
|
this.initForm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (changes['initialValues'] || changes['invoiceDate']) {
|
if (changes['initialValues'] || changes['invoiceDate']) {
|
||||||
this.initForm();
|
this.initForm();
|
||||||
}
|
}
|
||||||
@@ -115,23 +126,88 @@ export class SharedCorrectionFormComponent extends AbstractForm<
|
|||||||
return this.mapToStandardInitialItem(item) as TCorrectionItemPayload;
|
return this.mapToStandardInitialItem(item) as TCorrectionItemPayload;
|
||||||
}
|
}
|
||||||
|
|
||||||
override submitForm() {
|
openItemEditor(index: number) {
|
||||||
const goldQueue = [...(this.goldForms?.toArray() || [])];
|
this.activeItemIndex.set(index);
|
||||||
const standardQueue = [...(this.standardForms?.toArray() || [])];
|
this.showItemEditSheet.set(true);
|
||||||
const items =
|
}
|
||||||
this.initialValues?.map((item, index) => {
|
|
||||||
const current = this.isGold(item)
|
|
||||||
? goldQueue.shift()?.getCorrectionValue()
|
|
||||||
: standardQueue.shift()?.getCorrectionValue();
|
|
||||||
const merged = (current || this.mappedInitialItems[index]) as TCorrectionItemPayload;
|
|
||||||
return {
|
|
||||||
...merged,
|
|
||||||
id: item.id,
|
|
||||||
pricing_model: item.good_snapshot?.pricing_model || '',
|
|
||||||
} as TCorrectionItemPayload;
|
|
||||||
}) || [];
|
|
||||||
|
|
||||||
console.log('items', items);
|
backToList() {
|
||||||
|
this.showItemEditSheet.set(false);
|
||||||
|
this.activeItemIndex.set(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
activeItem() {
|
||||||
|
const index = this.activeItemIndex();
|
||||||
|
if (index === null) return null;
|
||||||
|
return this.initialValues?.[index] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
activeInitialValue() {
|
||||||
|
const item = this.activeItem();
|
||||||
|
const index = this.activeItemIndex();
|
||||||
|
if (!item || index === null) return null;
|
||||||
|
return this.itemDrafts[item.id] || this.mappedInitialItems[index] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getItemPreview(index: number) {
|
||||||
|
const item = this.initialValues?.[index];
|
||||||
|
return this.itemDrafts[item!.id] || this.mappedInitialItems[index] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTotalPriceInfo() {
|
||||||
|
const previews = (this.initialValues || [])
|
||||||
|
.map((_, index) => this.getItemPreview(index))
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
console.log('previews', previews);
|
||||||
|
|
||||||
|
return previews.reduce(
|
||||||
|
(acc, item: any) => {
|
||||||
|
acc.totalBaseAmount += Number(item.base_total_amount || 0);
|
||||||
|
acc.discountAmount += Number(item.discount_amount || 0);
|
||||||
|
acc.taxAmount += Number(item.tax_amount || 0);
|
||||||
|
acc.totalAmount += Number(item.total_amount || 0);
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
totalBaseAmount: 0,
|
||||||
|
discountAmount: 0,
|
||||||
|
taxAmount: 0,
|
||||||
|
totalAmount: 0,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveActiveItemDraft(
|
||||||
|
goldForm?: SharedGoldPayloadFormComponent,
|
||||||
|
standardForm?: SharedStandardPayloadFormComponent
|
||||||
|
) {
|
||||||
|
const item = this.activeItem();
|
||||||
|
const index = this.activeItemIndex();
|
||||||
|
if (!item || index === null) return;
|
||||||
|
|
||||||
|
const current = this.isGold(item)
|
||||||
|
? goldForm?.getCorrectionValue()
|
||||||
|
: standardForm?.getCorrectionValue();
|
||||||
|
|
||||||
|
if (!current) {
|
||||||
|
this.toastService.warn({ text: 'اطلاعات آیتم برای ذخیره در دسترس نیست.' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.itemDrafts[item.id] = {
|
||||||
|
...(current as TCorrectionItemPayload),
|
||||||
|
id: item.id,
|
||||||
|
pricing_model: item.good_snapshot?.pricing_model || '',
|
||||||
|
};
|
||||||
|
this.backToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
override submitForm() {
|
||||||
|
const items =
|
||||||
|
this.initialValues?.map(
|
||||||
|
(item, index) => this.itemDrafts[item.id] || this.mappedInitialItems[index]
|
||||||
|
) || [];
|
||||||
|
|
||||||
const hasChanges = (this.initialValues || []).some((item, index) => {
|
const hasChanges = (this.initialValues || []).some((item, index) => {
|
||||||
const source = this.mappedInitialItems[index];
|
const source = this.mappedInitialItems[index];
|
||||||
|
|||||||
@@ -3,23 +3,15 @@
|
|||||||
} @else if (!invoice) {
|
} @else if (!invoice) {
|
||||||
<uikit-empty-state> </uikit-empty-state>
|
<uikit-empty-state> </uikit-empty-state>
|
||||||
} @else {
|
} @else {
|
||||||
<shared-light-bottomsheet [visible]="actionLoading" [closable]="false" header="لطفا صبر کنید">
|
<app-inner-pages-header [pageTitle]="`صورتحساب ${invoice.invoice_number}`" [backRoute]="backRoute">
|
||||||
<div class="flex h-[30svh] flex-col items-center justify-center gap-6">
|
<ng-template #actions>
|
||||||
<p-progressSpinner />
|
<p-button (click)="printInvoice()" icon="pi pi-print" outlined size="small" label="چاپ" />
|
||||||
<span class="text-lg font-bold">در حال ارسال درخواست شما...</span>
|
</ng-template>
|
||||||
</div>
|
</app-inner-pages-header>
|
||||||
</shared-light-bottomsheet>
|
<div class="p-4">
|
||||||
<div class="flex flex-col gap-6">
|
<p-card>
|
||||||
<app-card-data cardTitle="اطلاعات صورتحساب" [editable]="false" [backRoute]="backRoute">
|
|
||||||
<ng-template #moreActions>
|
|
||||||
<div class="">
|
|
||||||
<p-menu #menu [model]="moreActionMenuItems()" [popup]="true" appendTo="body" />
|
|
||||||
<p-button (click)="menu.toggle($event)" icon="pi pi-ellipsis-v" outlined size="small" />
|
|
||||||
</div>
|
|
||||||
</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]="invoice.invoice_number" />
|
|
||||||
<app-key-value label="شماره منحصر به فرد مالیاتی" [value]="invoice.tax_id" />
|
<app-key-value label="شماره منحصر به فرد مالیاتی" [value]="invoice.tax_id" />
|
||||||
<app-key-value label="تاریخ صورتحساب" [value]="invoice.invoice_date" type="date" />
|
<app-key-value label="تاریخ صورتحساب" [value]="invoice.invoice_date" type="date" />
|
||||||
<app-key-value label="تاریخ ایجاد صورتحساب" [value]="invoice.created_at" type="dateTime" />
|
<app-key-value label="تاریخ ایجاد صورتحساب" [value]="invoice.created_at" type="dateTime" />
|
||||||
@@ -93,24 +85,40 @@
|
|||||||
<p class="text-text-color pt-3 pb-5 text-center">اطلاعات مشتری ثبت نشده است.</p>
|
<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>
|
</div>
|
||||||
</app-card-data>
|
</p-card>
|
||||||
<app-card-data cardTitle="کالاهای خریداری شده" [editable]="false">
|
|
||||||
<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>
|
|
||||||
</app-card-data>
|
|
||||||
</div>
|
</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="flex flex-wrap justify-center gap-2">
|
||||||
|
@for (action of moreActionMenuItems(); track action.label || $index) {
|
||||||
|
<button
|
||||||
|
pButton
|
||||||
|
[label]="action.label || ''"
|
||||||
|
[icon]="action.icon || ''"
|
||||||
|
[severity]="$any(action).severity || 'secondary'"
|
||||||
|
[outlined]="$any(action).severity === 'secondary'"
|
||||||
|
[loading]="actionLoading"
|
||||||
|
(click)="action.command()"></button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<shared-light-bottomsheet [(visible)]="showReturnFromSaleForm" header=" برگشت از فروش">
|
<shared-light-bottomsheet [(visible)]="showReturnFromSaleForm" header=" برگشت از فروش">
|
||||||
<shared-return-form
|
<shared-return-form
|
||||||
[initialValues]="invoice.items"
|
[initialValues]="invoice.items"
|
||||||
@@ -119,6 +127,7 @@
|
|||||||
</shared-light-bottomsheet>
|
</shared-light-bottomsheet>
|
||||||
<shared-light-bottomsheet [(visible)]="showCorrectionForm" header="اصلاحی">
|
<shared-light-bottomsheet [(visible)]="showCorrectionForm" header="اصلاحی">
|
||||||
<shared-correction-form
|
<shared-correction-form
|
||||||
|
[visible]="showCorrectionForm()"
|
||||||
[initialValues]="invoice.items"
|
[initialValues]="invoice.items"
|
||||||
[invoiceDate]="invoice.invoice_date"
|
[invoiceDate]="invoice.invoice_date"
|
||||||
(onSubmit)="correctionSubmit($event)" />
|
(onSubmit)="correctionSubmit($event)" />
|
||||||
|
|||||||
@@ -11,11 +11,7 @@ import {
|
|||||||
TspProviderResponseStatus,
|
TspProviderResponseStatus,
|
||||||
} from '@/shared/catalog';
|
} from '@/shared/catalog';
|
||||||
import { CatalogInvoiceSettlementTypeTagComponent } from '@/shared/catalog/invoiceSettlementType';
|
import { CatalogInvoiceSettlementTypeTagComponent } from '@/shared/catalog/invoiceSettlementType';
|
||||||
import {
|
import { KeyValueComponent, SharedLightBottomsheetComponent } from '@/shared/components';
|
||||||
AppCardComponent,
|
|
||||||
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 {
|
import {
|
||||||
@@ -38,25 +34,32 @@ import {
|
|||||||
ViewChild,
|
ViewChild,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { UrlTree } from '@angular/router';
|
import { UrlTree } from '@angular/router';
|
||||||
import { MenuItem } from 'primeng/api';
|
import { Button, ButtonDirective } from 'primeng/button';
|
||||||
import { Button } from 'primeng/button';
|
import { Card } from 'primeng/card';
|
||||||
|
import { Dialog } from 'primeng/dialog';
|
||||||
import { Divider } from 'primeng/divider';
|
import { Divider } from 'primeng/divider';
|
||||||
import { Menu } from 'primeng/menu';
|
|
||||||
import { ProgressSpinner } from 'primeng/progressspinner';
|
import { ProgressSpinner } from 'primeng/progressspinner';
|
||||||
import { TableModule } from 'primeng/table';
|
import { TableModule } from 'primeng/table';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { AppConfirmationService } from '../confirmationDialog/confirmation-dialog.service';
|
import { AppConfirmationService } from '../confirmationDialog/confirmation-dialog.service';
|
||||||
|
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 { SharedReturnFormComponent } from './returnForm/form.component';
|
import { SharedReturnFormComponent } from './returnForm/form.component';
|
||||||
|
|
||||||
export type TSaleInvoiceSingleViewVariant = 'full' | 'customer' | 'pos';
|
export type TSaleInvoiceSingleViewVariant = 'full' | 'customer' | 'pos';
|
||||||
|
type TActionMenuItem = {
|
||||||
|
label: string;
|
||||||
|
icon: string;
|
||||||
|
command: () => void;
|
||||||
|
neededStatus?: TspProviderResponseStatus;
|
||||||
|
severity?: 'secondary' | 'info' | 'warn' | 'danger' | 'contrast';
|
||||||
|
};
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
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: [
|
||||||
AppCardComponent,
|
|
||||||
KeyValueComponent,
|
KeyValueComponent,
|
||||||
Divider,
|
Divider,
|
||||||
PageDataListComponent,
|
PageDataListComponent,
|
||||||
@@ -66,13 +69,16 @@ export type TSaleInvoiceSingleViewVariant = 'full' | 'customer' | 'pos';
|
|||||||
PriceMaskDirective,
|
PriceMaskDirective,
|
||||||
CatalogTaxProviderStatusTagComponent,
|
CatalogTaxProviderStatusTagComponent,
|
||||||
CatalogInvoiceTypeTagComponent,
|
CatalogInvoiceTypeTagComponent,
|
||||||
Menu,
|
|
||||||
Button,
|
Button,
|
||||||
CatalogInvoiceSettlementTypeTagComponent,
|
CatalogInvoiceSettlementTypeTagComponent,
|
||||||
SharedLightBottomsheetComponent,
|
SharedLightBottomsheetComponent,
|
||||||
ProgressSpinner,
|
ProgressSpinner,
|
||||||
SharedReturnFormComponent,
|
SharedReturnFormComponent,
|
||||||
SharedCorrectionFormComponent,
|
SharedCorrectionFormComponent,
|
||||||
|
Dialog,
|
||||||
|
ButtonDirective,
|
||||||
|
InnerPagesHeaderComponent,
|
||||||
|
Card,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class SharedSaleInvoiceSingleViewComponent {
|
export class SharedSaleInvoiceSingleViewComponent {
|
||||||
@@ -100,41 +106,89 @@ export class SharedSaleInvoiceSingleViewComponent {
|
|||||||
|
|
||||||
@ViewChild('totalAmount', { static: false }) totalAmount!: TemplateRef<any>;
|
@ViewChild('totalAmount', { static: false }) totalAmount!: TemplateRef<any>;
|
||||||
|
|
||||||
moreActionMenuItems = signal<MenuItem[]>([]);
|
moreActionMenuItems = signal<TActionMenuItem[]>([]);
|
||||||
showCorrectionForm = signal(false);
|
showCorrectionForm = signal(false);
|
||||||
showReturnFromSaleForm = signal(false);
|
showReturnFromSaleForm = signal(false);
|
||||||
|
|
||||||
constructor() {
|
showErrors = () => {};
|
||||||
this.showErrors = this.showErrors.bind(this);
|
inquiry = () => {
|
||||||
this.showRevokeConfirmation = this.showRevokeConfirmation.bind(this);
|
this.onInquiry.emit();
|
||||||
this.showCorrection = this.showCorrection.bind(this);
|
};
|
||||||
this.showReturnFromSale = this.showReturnFromSale.bind(this);
|
send = () => {
|
||||||
this.printInvoice = this.printInvoice.bind(this);
|
this.onSendToTsp.emit();
|
||||||
this.send = this.send.bind(this);
|
};
|
||||||
this.resend = this.resend.bind(this);
|
sendCorrection = (event: ICorrectionRequest) => {
|
||||||
this.inquiry = this.inquiry.bind(this);
|
this.onCorrection.emit(event);
|
||||||
}
|
};
|
||||||
|
resend = () => {
|
||||||
|
this.onResendToTsp.emit();
|
||||||
|
};
|
||||||
|
sendReturnFromSale = (event: IPosReturnFromSaleRequest) => {
|
||||||
|
this.onReturnFromSale.emit(event);
|
||||||
|
};
|
||||||
|
showCorrection = () => {
|
||||||
|
this.showCorrectionForm.set(true);
|
||||||
|
};
|
||||||
|
showReturnFromSale = () => {
|
||||||
|
this.showReturnFromSaleForm.set(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly actions: TActionMenuItem[] = [
|
||||||
|
{
|
||||||
|
label: 'ارسال مجدد صورتحساب',
|
||||||
|
icon: 'pi pi-send',
|
||||||
|
neededStatus: TspProviderResponseStatus.SEND_FAILURE,
|
||||||
|
severity: 'info',
|
||||||
|
command: () => this.resend(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'ارسال صورتحساب',
|
||||||
|
icon: 'pi pi-send',
|
||||||
|
neededStatus: TspProviderResponseStatus.NOT_SEND,
|
||||||
|
severity: 'info',
|
||||||
|
command: () => this.send(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'استعلام وضعیت',
|
||||||
|
icon: 'pi pi-info',
|
||||||
|
neededStatus: TspProviderResponseStatus.FISCAL_QUEUED,
|
||||||
|
severity: 'info',
|
||||||
|
command: () => this.inquiry(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'دلایل خطا',
|
||||||
|
icon: 'pi pi-question',
|
||||||
|
neededStatus: TspProviderResponseStatus.FAILURE,
|
||||||
|
severity: 'danger',
|
||||||
|
command: () => this.showErrors(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'ابطال',
|
||||||
|
icon: 'pi pi-eraser',
|
||||||
|
neededStatus: TspProviderResponseStatus.SUCCESS,
|
||||||
|
severity: 'danger',
|
||||||
|
command: () => this.showRevokeConfirmation(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'اصلاح',
|
||||||
|
icon: 'pi pi-file-edit',
|
||||||
|
neededStatus: TspProviderResponseStatus.SUCCESS,
|
||||||
|
severity: 'warn',
|
||||||
|
command: () => this.showCorrection(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'برگشت از فروش',
|
||||||
|
icon: 'pi pi-cart-minus',
|
||||||
|
neededStatus: TspProviderResponseStatus.SUCCESS,
|
||||||
|
severity: 'warn',
|
||||||
|
command: () => this.showReturnFromSale(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
get actionLoading() {
|
get actionLoading() {
|
||||||
return this.sendToTspLoading || this.inquiryLoading || this.resendToTspLoading;
|
return this.sendToTspLoading || this.inquiryLoading || this.resendToTspLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
showErrors() {}
|
|
||||||
inquiry() {
|
|
||||||
this.onInquiry.emit();
|
|
||||||
}
|
|
||||||
send() {
|
|
||||||
this.onSendToTsp.emit();
|
|
||||||
}
|
|
||||||
sendCorrection(event: ICorrectionRequest) {
|
|
||||||
this.onCorrection.emit(event);
|
|
||||||
}
|
|
||||||
resend() {
|
|
||||||
this.onResendToTsp.emit();
|
|
||||||
}
|
|
||||||
sendReturnFromSale(event: IPosReturnFromSaleRequest) {
|
|
||||||
this.onReturnFromSale.emit(event);
|
|
||||||
}
|
|
||||||
async showRevokeConfirmation() {
|
async showRevokeConfirmation() {
|
||||||
await this.confirmationService.ask({
|
await this.confirmationService.ask({
|
||||||
header: `ابطال صورتحساب شماره ${this.invoice!.invoice_number}`,
|
header: `ابطال صورتحساب شماره ${this.invoice!.invoice_number}`,
|
||||||
@@ -156,72 +210,13 @@ export class SharedSaleInvoiceSingleViewComponent {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
showCorrection() {
|
|
||||||
this.showCorrectionForm.set(true);
|
|
||||||
}
|
|
||||||
showReturnFromSale() {
|
|
||||||
this.showReturnFromSaleForm.set(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (changes['invoice'] && this.invoice) {
|
if (changes['invoice'] && this.invoice) {
|
||||||
const invoiceStatus = this.invoice.status.value;
|
const invoiceStatus = this.invoice.status.value;
|
||||||
const actions: MenuItem[] = [
|
|
||||||
{
|
|
||||||
label: 'ارسال مجدد صورتحساب',
|
|
||||||
icon: 'pi pi-send',
|
|
||||||
neededStatus: TspProviderResponseStatus.SEND_FAILURE,
|
|
||||||
command: this.resend,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'ارسال صورتحساب',
|
|
||||||
icon: 'pi pi-send',
|
|
||||||
neededStatus: TspProviderResponseStatus.NOT_SEND,
|
|
||||||
command: this.send,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'استعلام وضعیت',
|
|
||||||
icon: 'pi pi-info',
|
|
||||||
neededStatus: TspProviderResponseStatus.FISCAL_QUEUED,
|
|
||||||
command: this.inquiry,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'دلایل خطا',
|
|
||||||
icon: 'pi pi-question',
|
|
||||||
neededStatus: TspProviderResponseStatus.FAILURE,
|
|
||||||
command: this.showErrors,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'ابطال',
|
|
||||||
icon: 'pi pi-eraser',
|
|
||||||
neededStatus: TspProviderResponseStatus.SUCCESS,
|
|
||||||
command: this.showRevokeConfirmation,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'اصلاح',
|
|
||||||
icon: 'pi pi-file-edit',
|
|
||||||
neededStatus: TspProviderResponseStatus.SUCCESS,
|
|
||||||
command: this.showCorrection,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'برگشت از فروش',
|
|
||||||
icon: 'pi pi-cart-minus',
|
|
||||||
neededStatus: TspProviderResponseStatus.SUCCESS,
|
|
||||||
command: this.showReturnFromSale,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'چاپ',
|
|
||||||
icon: 'pi pi-print',
|
|
||||||
neededStatus: '',
|
|
||||||
command: this.printInvoice,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
this.moreActionMenuItems.set(
|
this.moreActionMenuItems.set(
|
||||||
actions.filter(
|
this.actions.filter((action) => action.neededStatus === invoiceStatus)
|
||||||
// @ts-ignore
|
|
||||||
(action) => !action.neededStatus || action.neededStatus === invoiceStatus
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
<div class="inline-flex flex-col gap-1 w-full">
|
<div class="inline-flex w-full flex-col gap-1">
|
||||||
<div class="inline-flex gap-2 items-center w-full">
|
<div class="inline-flex w-full items-center gap-2">
|
||||||
<span class="text-muted-color text-base font-normal flex-auto grow-0">{{ label }}:</span>
|
<span class="text-muted-color flex-auto grow-0 text-base font-normal">{{ label }}:</span>
|
||||||
<div
|
<div
|
||||||
class="shrink-0 grow max-sm:text-left"
|
class="text-text-color shrink-0 grow text-base font-bold max-sm:text-left"
|
||||||
[ngClass]="{
|
[ngClass]="{
|
||||||
'text-right': alignment === 'start',
|
'text-right': alignment === 'start',
|
||||||
'text-center': alignment === 'center',
|
'text-center': alignment === 'center',
|
||||||
'text-left': alignment === 'end',
|
'text-left': alignment === 'end',
|
||||||
}"
|
}">
|
||||||
>
|
|
||||||
<ng-content>
|
<ng-content>
|
||||||
@if (type === "thumbnail") {
|
@if (type === 'thumbnail') {
|
||||||
<div class="w-20 h-20 rounded-2xl overflow-hidden bg-surface-100 cursor-pointer">
|
<div class="bg-surface-100 h-20 w-20 cursor-pointer overflow-hidden rounded-2xl">
|
||||||
@if (valueToShow()) {
|
@if (valueToShow()) {
|
||||||
<img [src]="valueToShow()" class="w-full h-full object-cover" />
|
<img [src]="valueToShow()" class="h-full w-full object-cover" />
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
} @else if (valueType() === "tag") {
|
} @else if (valueType() === 'tag') {
|
||||||
<p-tag [value]="valueToShow()?.toString()" [severity]="value ? 'contrast' : 'danger'" />
|
<p-tag [value]="valueToShow()?.toString()" [severity]="value ? 'contrast' : 'danger'" />
|
||||||
} @else {
|
} @else {
|
||||||
<span class="text-text-color text-base font-bold grow"> {{ valueToShow() }}</span>
|
<span class="text-text-color grow text-base font-bold"> {{ valueToShow() }}</span>
|
||||||
}
|
}
|
||||||
</ng-content>
|
</ng-content>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
<form [formGroup]="form">
|
<form [formGroup]="form">
|
||||||
<app-price-input [control]="form.controls.unit_price" name="unit_price" label="مبلغ واحد" />
|
<app-price-input [control]="form.controls.unit_price" name="unit_price" label="مبلغ واحد" />
|
||||||
<app-input [control]="form.controls.quantity" name="quantity" label="مقدار" type="number" suffix="گرم" />
|
<app-input [control]="form.controls.quantity" name="quantity" label="مقدار" type="number" suffix="گرم" />
|
||||||
<app-enum-select [control]="form.controls.payload.controls.karat" type="goldKarat" name="karat" />
|
@if (!isCorrection) {
|
||||||
|
<app-enum-select [control]="form.controls.payload.controls.karat" type="goldKarat" name="karat" />
|
||||||
|
}
|
||||||
|
|
||||||
<app-amount-percentage-input
|
<app-amount-percentage-input
|
||||||
[percentageControl]="form.controls.payload.controls.wages_percentage"
|
[percentageControl]="form.controls.payload.controls.wages_percentage"
|
||||||
|
|||||||
@@ -15,6 +15,14 @@
|
|||||||
[style]="{ display: 'none' }"
|
[style]="{ display: 'none' }"
|
||||||
>
|
>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
<input
|
||||||
|
#cameraInput
|
||||||
|
type="file"
|
||||||
|
class="hidden"
|
||||||
|
[accept]="accept"
|
||||||
|
[attr.capture]="accept?.includes('image') ? cameraCapture : null"
|
||||||
|
(change)="onNativeFileSelected($event)"
|
||||||
|
/>
|
||||||
<ng-template
|
<ng-template
|
||||||
#content
|
#content
|
||||||
let-files
|
let-files
|
||||||
@@ -35,7 +43,7 @@
|
|||||||
icon="pi pi-pencil"
|
icon="pi pi-pencil"
|
||||||
severity="warn"
|
severity="warn"
|
||||||
size="small"
|
size="small"
|
||||||
(click)="chooseCallback()"
|
(click)="openFilePicker()"
|
||||||
></button>
|
></button>
|
||||||
<button
|
<button
|
||||||
pButton
|
pButton
|
||||||
@@ -49,7 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
} @else {
|
} @else {
|
||||||
<div class="flex items-center justify-center flex-col cursor-pointer py-5 w-full" (click)="chooseCallback()">
|
<div class="flex items-center justify-center flex-col cursor-pointer py-5 w-full" (click)="openFilePicker()">
|
||||||
<i class="pi pi-cloud-upload border-2! rounded-full! p-8! text-4xl! text-muted-color!"></i>
|
<i class="pi pi-cloud-upload border-2! rounded-full! p-8! text-4xl! text-muted-color!"></i>
|
||||||
<p class="mt-6 mb-0">فایل مورد نظر خود را در اینجا رها کنید</p>
|
<p class="mt-6 mb-0">فایل مورد نظر خود را در اینجا رها کنید</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Maybe } from '@/core';
|
import { Maybe } from '@/core';
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
|
ElementRef,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
Input,
|
Input,
|
||||||
OnChanges,
|
OnChanges,
|
||||||
@@ -22,6 +23,7 @@ export class SharedUploadFileComponent implements OnChanges, OnDestroy {
|
|||||||
@Input() loading: boolean = false;
|
@Input() loading: boolean = false;
|
||||||
@Input() name: string = 'file';
|
@Input() name: string = 'file';
|
||||||
@Input() accept: string = 'image/*';
|
@Input() accept: string = 'image/*';
|
||||||
|
@Input() cameraCapture: 'user' | 'environment' = 'environment';
|
||||||
@Input() maxSize: Maybe<number> = 5 * 1024 * 1024;
|
@Input() maxSize: Maybe<number> = 5 * 1024 * 1024;
|
||||||
@Input() error: Maybe<string> = null;
|
@Input() error: Maybe<string> = null;
|
||||||
@Input() hint: Maybe<string> = null;
|
@Input() hint: Maybe<string> = null;
|
||||||
@@ -30,6 +32,7 @@ export class SharedUploadFileComponent implements OnChanges, OnDestroy {
|
|||||||
@Output() onSelect = new EventEmitter<onSelectFileArgs>();
|
@Output() onSelect = new EventEmitter<onSelectFileArgs>();
|
||||||
|
|
||||||
@ViewChild(FileUpload) uploader?: FileUpload;
|
@ViewChild(FileUpload) uploader?: FileUpload;
|
||||||
|
@ViewChild('cameraInput') cameraInput?: ElementRef<HTMLInputElement>;
|
||||||
|
|
||||||
filePreview: Maybe<string> = null;
|
filePreview: Maybe<string> = null;
|
||||||
private objectUrl: Maybe<string> = null;
|
private objectUrl: Maybe<string> = null;
|
||||||
@@ -63,8 +66,26 @@ export class SharedUploadFileComponent implements OnChanges, OnDestroy {
|
|||||||
this.onSelect.emit({ data: payload, file });
|
this.onSelect.emit({ data: payload, file });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openFilePicker() {
|
||||||
|
this.cameraInput?.nativeElement.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
onNativeFileSelected(event: Event) {
|
||||||
|
const input = event.target as HTMLInputElement;
|
||||||
|
const file = input.files?.[0];
|
||||||
|
if (!file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setPreviewFromFile(file);
|
||||||
|
const payload = new FormData();
|
||||||
|
payload.append(this.name, file, file.name);
|
||||||
|
this.onSelect.emit({ data: payload, file });
|
||||||
|
input.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
onEditFile() {
|
onEditFile() {
|
||||||
this.uploader?.choose();
|
this.openFilePicker();
|
||||||
}
|
}
|
||||||
|
|
||||||
onDeleteFilePreview() {
|
onDeleteFilePreview() {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<input pInputText readonly [name]="name" [value]="valueToShow" class="w-full" />
|
<input pInputText readonly [name]="name" [value]="valueToShow" class="w-full" />
|
||||||
</uikit-field>
|
</uikit-field>
|
||||||
<p-popover #op appendTo="body">
|
<p-popover #op appendTo="body">
|
||||||
<div #wrapperRef class="dir-rtl border-divider bg-background-paper w-full min-w-sm overflow-auto rounded-md">
|
<div #wrapperRef class="dir-rtl border-divider bg-background-paper w-full min-w-[320px] overflow-auto rounded-md">
|
||||||
<div class="bg-primary-main sticky top-0 flex justify-center px-3">
|
<div class="bg-primary-main sticky top-0 flex justify-center px-3">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<div class="flex h-8 items-center">
|
<div class="flex h-8 items-center">
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.listKeyValue {
|
.listKeyValue {
|
||||||
@apply grid md:grid-cols-3 sm:grid-cols-2 sm:gap-4 gap-3 items-center;
|
@apply grid items-center gap-3 sm:grid-cols-2 sm:gap-4 md:grid-cols-3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cardShadow {
|
.cardShadow {
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.summaryList {
|
.summaryList {
|
||||||
@apply max-h-125 flex;
|
@apply flex max-h-125;
|
||||||
> * {
|
> * {
|
||||||
@apply w-full;
|
@apply w-full;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,6 @@ a {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-wrapper {
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
html {
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|||||||
@@ -1,23 +1,7 @@
|
|||||||
.layout-main-container {
|
.layout-main-container {
|
||||||
display: flex;
|
// padding: 2rem 1rem 2rem 2rem;
|
||||||
flex-direction: column;
|
|
||||||
// height: 100vh;
|
|
||||||
// overflow: hidden;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 2rem 1rem 2rem 2rem;
|
|
||||||
transition: margin-inline-start var(--layout-section-transition-duration);
|
transition: margin-inline-start var(--layout-section-transition-duration);
|
||||||
&.hideMenu {
|
&.hideMenu {
|
||||||
margin: 0 !important;
|
|
||||||
transform: translateX(0) !important;
|
transform: translateX(0) !important;
|
||||||
padding-inline-start: 2rem !important;
|
|
||||||
}
|
|
||||||
&.isFullPage {
|
|
||||||
padding-inline-start: 0 !important;
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-main {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
// overflow: auto;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
.p-inputtext {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
// TIS tenant environment configuration
|
// TIS tenant environment configuration
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: true,
|
production: true,
|
||||||
// apiBaseUrl: 'https://psp-api.shift-am.ir',
|
apiBaseUrl: 'https://psp-api.shift-am.ir',
|
||||||
// apiBaseUrl: 'http://192.168.128.73:5002',
|
// apiBaseUrl: 'http://192.168.128.73:5002',
|
||||||
apiBaseUrl: 'http://localhost:5002',
|
// apiBaseUrl: 'http://192.168.0.162:5002',
|
||||||
|
// apiBaseUrl: 'http://localhost:5002',
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
port: 5000,
|
port: 5000,
|
||||||
enableLogging: false,
|
enableLogging: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user