feat: enhance order submission flow and UI improvements
- Updated categories component to improve loading state and category display. - Modified order section to handle payment submission with event payload. - Refactored payment form dialog to emit order response on successful payment. - Adjusted order response model to enforce required fields. - Improved root component layout and added success dialog for order submission. - Enhanced sale invoice card component to use new TSP API methods. - Updated API routes for sale invoices to reflect TSP changes. - Improved user interface for business activities and partners sections. - Added card shadow styling for better visual hierarchy. - Introduced new order submitted dialog component for post-order actions. - Cleaned up console logs and improved code readability across components.
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
<ng-template #topbarStart>
|
||||
<p-button (click)="toggleMenu()" icon="pi pi-bars" outlined size="large" />
|
||||
<p-button (click)="refresh()" icon="pi pi-bars" outlined size="large" />
|
||||
<p-button (click)="doPay()" icon="pi pi-bars" outlined size="large" />
|
||||
</ng-template>
|
||||
|
||||
<ng-template #topbarCenter>
|
||||
@@ -26,11 +24,34 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@if (loading()) {
|
||||
<shared-page-loading />
|
||||
} @else {
|
||||
<!-- <div class="w-svw h-svh bg-surface-ground flex flex-col gap-4 p-4"> -->
|
||||
<!-- <div class="w-full flex items-center gap-4 shrink-0 justify-between">
|
||||
<div
|
||||
class="h-full relative"
|
||||
(touchstart)="onTouchStart($event)"
|
||||
(touchmove)="onTouchMove($event)"
|
||||
(touchend)="onTouchEnd()"
|
||||
>
|
||||
@if (pullDistance() >= 0) {
|
||||
<div
|
||||
class="w-full flex justify-center items-center py-2 min-h-10 text-xs text-surface-500 overflow-hidden fixed top-0 inset-x-0 z-1000 translate-y--20px"
|
||||
[ngStyle]="{ height: pullDistance() + 'px' }"
|
||||
>
|
||||
<div
|
||||
class="inline-flex p-3 rounded-full opacity-0 transition-opacity shadow-xl bg-surface-card"
|
||||
[ngStyle]="{ opacity: pullDistance() / 100 }"
|
||||
>
|
||||
<i
|
||||
class="pi pi-refresh text-[1.25rem] text-primary"
|
||||
[ngStyle]="{ fontSize: `${1.25 + pullDistance() * 0.007}rem`, rotate: pullDistance() * 2 + 'deg' }"
|
||||
></i>
|
||||
</div>
|
||||
<!-- [ngStyle]="{ transform: 'scale(1.' + pullDistance() * 10 + ')' }" -->
|
||||
</div>
|
||||
}
|
||||
@if (loading()) {
|
||||
<shared-page-loading />
|
||||
} @else {
|
||||
<!-- <div class="w-svw h-svh bg-surface-ground flex flex-col gap-4 p-4"> -->
|
||||
<!-- <div class="w-full flex items-center gap-4 shrink-0 justify-between">
|
||||
<div class="flex gap-2 items-center">
|
||||
@if (posInfo()) {
|
||||
<div class="w-10 h-10">
|
||||
@@ -53,27 +74,28 @@
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
@if (error()) {
|
||||
@switch (error()?.status) {
|
||||
@case (412) {
|
||||
<pos-choose-cards class="h-full" (onChoose)="onChoosePos()" />
|
||||
}
|
||||
@default {
|
||||
<div class="h-full w-full flex items-center justify-center">
|
||||
<p-card class="border border-surface-border">
|
||||
<div class="flex flex-col gap-2 items-center justify-between shrink-0">
|
||||
<i class="pi pi-exclamation-triangle text-6xl! mb-3 text-error" aria-hidden="true"></i>
|
||||
<span class="text-xl font-semibold mb-2 text-error block"> عدم دسترسی </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>
|
||||
@if (error()) {
|
||||
@switch (error()?.status) {
|
||||
@case (412) {
|
||||
<pos-choose-cards class="h-full" (onChoose)="onChoosePos()" />
|
||||
}
|
||||
@default {
|
||||
<div class="h-full w-full flex items-center justify-center">
|
||||
<p-card class="border border-surface-border">
|
||||
<div class="flex flex-col gap-2 items-center justify-between shrink-0">
|
||||
<i class="pi pi-exclamation-triangle text-6xl! mb-3 text-error" aria-hidden="true"></i>
|
||||
<span class="text-xl font-semibold mb-2 text-error block"> عدم دسترسی </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>
|
||||
}
|
||||
} @else {
|
||||
<pos-main-menu-sidebar [(visible)]="mainMenuVisible" />
|
||||
<router-outlet></router-outlet>
|
||||
<!-- </div> -->
|
||||
}
|
||||
<!-- </div> -->
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { NativeBridgeService } from '@/core/services';
|
||||
import { ToastService } from '@/core/services/toast.service';
|
||||
import { LayoutService } from '@/layout/service/layout.service';
|
||||
import { PageLoadingComponent } from '@/shared/components/page-loading.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
@@ -34,6 +35,7 @@ import { PosMainMenuSidebarComponent } from './mainMenuSidebar/main-menu-sidebar
|
||||
Button,
|
||||
PosMainMenuSidebarComponent,
|
||||
Menu,
|
||||
CommonModule,
|
||||
],
|
||||
})
|
||||
export class PosLayoutComponent implements AfterViewInit {
|
||||
@@ -84,6 +86,10 @@ export class PosLayoutComponent implements AfterViewInit {
|
||||
placeholderLogo = images.placeholders.logo;
|
||||
|
||||
now = new Date();
|
||||
private touchStartY = 0;
|
||||
private pulling = false;
|
||||
pullDistance = signal(0);
|
||||
readonly pullThreshold = 80;
|
||||
|
||||
getData() {
|
||||
this.posProfileStore.getData().subscribe({
|
||||
@@ -101,24 +107,6 @@ export class PosLayoutComponent implements AfterViewInit {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
doPay() {
|
||||
// this.nativeBridgeService.pay({
|
||||
// amount: 10_000,
|
||||
// id: '1',
|
||||
// });
|
||||
this.nativeBridgeService.print({
|
||||
title: 'salam',
|
||||
items: [
|
||||
{
|
||||
label: 'مجموع قیمت',
|
||||
value: '10_000',
|
||||
},
|
||||
],
|
||||
});
|
||||
// @ts-ignore
|
||||
// window.NativeBridge.pay(12312, 'test');
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.layoutService.changeIsFullPage(true);
|
||||
this.getData();
|
||||
@@ -137,7 +125,33 @@ export class PosLayoutComponent implements AfterViewInit {
|
||||
this.layoutService.setTopbarEndSlot(null);
|
||||
}
|
||||
|
||||
refresh() {
|
||||
window.location.reload();
|
||||
onTouchStart(event: TouchEvent) {
|
||||
if (window.scrollY > 0 || event.touches.length !== 1) return;
|
||||
this.touchStartY = event.touches[0].clientY;
|
||||
this.pulling = true;
|
||||
}
|
||||
|
||||
onTouchMove(event: TouchEvent) {
|
||||
if (!this.pulling) return;
|
||||
const delta = event.touches[0].clientY - this.touchStartY;
|
||||
if (delta <= 0) {
|
||||
this.pullDistance.set(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const damped = Math.min(delta * 0.5, 140);
|
||||
this.pullDistance.set(damped);
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
onTouchEnd() {
|
||||
if (!this.pulling) return;
|
||||
const shouldRefresh = this.pullDistance() >= this.pullThreshold;
|
||||
this.pulling = false;
|
||||
this.pullDistance.set(0);
|
||||
if (shouldRefresh) {
|
||||
this.layoutService.changeIsFullPage(true);
|
||||
this.getData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
<div class="flex gap-3 overflow-auto">
|
||||
@if (loading()) {
|
||||
@for (i of [1, 2, 3, 4, 5]; track i) {
|
||||
<p-skeleton width="6rem" height="2.5rem" />
|
||||
}
|
||||
} @else {
|
||||
@for (category of categories(); track category.id) {
|
||||
<div
|
||||
[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' +
|
||||
(selectedCategory() === category.id ? ' bg-surface-card' : '')
|
||||
"
|
||||
(click)="changeSelectedCategory(category)"
|
||||
>
|
||||
<span class="text-sm text-muted-color font-bold"> {{ category.name }}</span>
|
||||
<div class="overflow-x-auto">
|
||||
<div class="w-full overflow-visible flex gap-3">
|
||||
@if (loading()) {
|
||||
@for (i of [1, 2, 3, 4, 5]; track i) {
|
||||
<p-skeleton width="6rem" height="2.5rem" />
|
||||
}
|
||||
} @else {
|
||||
@for (category of categories(); track category.id) {
|
||||
<div
|
||||
[class]="
|
||||
'flex items-center justify-center py-0.5 px-2 rounded-sm bg-surface-300 text-xs text-muted-color' +
|
||||
(selectedCategory() === category.id ? ' bg-amber-400! text-white' : '')
|
||||
'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' +
|
||||
(selectedCategory() === category.id ? ' bg-surface-card' : '')
|
||||
"
|
||||
(click)="changeSelectedCategory(category)"
|
||||
>
|
||||
<span>
|
||||
{{ category.goods_count }}
|
||||
</span>
|
||||
<span class="text-sm text-muted-color font-bold"> {{ category.name }}</span>
|
||||
<div
|
||||
[class]="
|
||||
'flex items-center justify-center py-0.5 px-2 rounded-sm bg-surface-300 text-xs text-muted-color' +
|
||||
(selectedCategory() === category.id ? ' bg-amber-400! text-white' : '')
|
||||
"
|
||||
>
|
||||
<span>
|
||||
{{ category.goods_count }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -63,4 +63,4 @@
|
||||
|
||||
<pos-order-customer-dialog [(visible)]="isVisibleCustomerForm" (onSubmit)="submitCustomer()" />
|
||||
<!-- <pos-pre-invoice-dialog [(visible)]="isVisiblePreInvoiceForm" /> -->
|
||||
<pos-payment-form-dialog [(visible)]="isVisiblePaymentForm" (onSubmit)="submitPayment()" />
|
||||
<pos-payment-form-dialog [(visible)]="isVisiblePaymentForm" (onSubmit)="submitPayment($event)" />
|
||||
|
||||
@@ -6,6 +6,7 @@ import { FormsModule } from '@angular/forms';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { Card } from 'primeng/card';
|
||||
import images from 'src/assets/images';
|
||||
import { IPosOrderResponse } from '../../models';
|
||||
import { PosLandingStore } from '../../store/main.store';
|
||||
import { PosOrderCustomerDialogComponent } from '../customers/customer-dialog.component';
|
||||
import { GoldPayloadOrderCardComponent } from '../payloads/gold/order-card.component';
|
||||
@@ -31,7 +32,7 @@ import { POSOrderPriceInfoCardComponent } from './price-info-card.component';
|
||||
export class PosOrderSectionComponent {
|
||||
private readonly store = inject(PosLandingStore);
|
||||
@Output() onAddMoreGoods = new EventEmitter<void>();
|
||||
@Output() onSuccess = new EventEmitter<void>();
|
||||
@Output() onSuccess = new EventEmitter<IPosOrderResponse>();
|
||||
|
||||
placeholderImage = images.placeholders.default;
|
||||
|
||||
@@ -84,9 +85,7 @@ export class PosOrderSectionComponent {
|
||||
}
|
||||
|
||||
submitCustomer() {}
|
||||
submitPayment() {
|
||||
console.log('submitPayment');
|
||||
|
||||
this.onSuccess.emit();
|
||||
submitPayment(invoice: IPosOrderResponse) {
|
||||
this.onSuccess.emit(invoice);
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<shared-dialog
|
||||
[(visible)]="visible"
|
||||
header="ثبت موفقیتآمیز"
|
||||
[modal]="true"
|
||||
[style]="{ width: '420px' }"
|
||||
[closable]="true"
|
||||
(onHide)="close()"
|
||||
>
|
||||
<div class="text-center pt-10 pb-14 flex flex-col items-center justify-center gap-4">
|
||||
<i class="" class="pi pi-check-circle text-6xl! text-green-700"></i>
|
||||
<p class="text-lg font-bold">فاکتور شما با موفقیت ایجاد شد.</p>
|
||||
</div>
|
||||
<div class="flex gap-2 justify-center">
|
||||
<button pButton type="button" outlined (click)="printInvoice()">چاپ</button>
|
||||
<button pButton type="button" outlined (click)="sendToTsp()">ارسال به سامانه مودیان</button>
|
||||
<button pButton type="button" outlined (click)="openOrderDetails()">جزئیات</button>
|
||||
</div>
|
||||
</shared-dialog>
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
import { NativeBridgeService } from '@/core/services';
|
||||
import { ToastService } from '@/core/services/toast.service';
|
||||
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
|
||||
import { SharedDialogComponent } from '@/shared/components';
|
||||
import { Component, inject, Input, signal } from '@angular/core';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { finalize } from 'rxjs';
|
||||
import { PosSaleInvoicesService } from '../../../saleInvoices/services/main.service';
|
||||
import { IPosOrderResponse } from '../../models';
|
||||
|
||||
@Component({
|
||||
selector: 'pos-order-submitted-dialog',
|
||||
templateUrl: 'order-submitted-dialog.component.html',
|
||||
imports: [SharedDialogComponent, ButtonDirective],
|
||||
})
|
||||
export class PosOrderSubmittedDialogComponent extends AbstractDialog {
|
||||
@Input({ required: true }) invoice!: IPosOrderResponse;
|
||||
private readonly nativeBridgeService = inject(NativeBridgeService);
|
||||
private readonly service = inject(PosSaleInvoicesService);
|
||||
private readonly toastService = inject(ToastService);
|
||||
|
||||
sendingLoading = signal(false);
|
||||
sended = signal(false);
|
||||
|
||||
openOrderDetails() {
|
||||
this.close();
|
||||
}
|
||||
|
||||
sendInvoice() {
|
||||
this.sendingLoading.set(true);
|
||||
this.service
|
||||
.sendToTsp(this.invoice.id)
|
||||
.pipe(finalize(() => this.sendingLoading.set(false)))
|
||||
.subscribe(() => {
|
||||
this.toastService.success({ text: 'ارسال فاکتور با موفقیت انجام شد.' });
|
||||
this.sended.set(true);
|
||||
});
|
||||
}
|
||||
|
||||
printInvoice() {
|
||||
const printResult = this.nativeBridgeService.print({
|
||||
title: 'رسید پرداخت',
|
||||
items: [
|
||||
{ label: 'مبلغ کل', value: String(this.invoice.code) },
|
||||
// { label: 'نقدی', value: String(this.invoice.payment.cash || 0) },
|
||||
// { label: 'تهاتر', value: String(this.invoice.payment.set_off || 0) },
|
||||
// {
|
||||
// label: 'پایانه',
|
||||
// value: String((this.invoice.payment.terminals || []).reduce((acc, item) => acc + item, 0)),
|
||||
// },
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
sendToTsp() {}
|
||||
}
|
||||
@@ -6,12 +6,12 @@ import { InputComponent, KeyValueComponent } from '@/shared/components';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, OnDestroy, OnInit, computed, inject, signal } from '@angular/core';
|
||||
import { Component, computed, inject, signal } from '@angular/core';
|
||||
import { FormControl, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { Select } from 'primeng/select';
|
||||
import { catchError, throwError } from 'rxjs';
|
||||
import { IPayment, TOrderPaymentTypes } from '../../models';
|
||||
import { IPayment, IPosOrderResponse, TOrderPaymentTypes } from '../../models';
|
||||
import { PosPaymentBridgeAbstract } from '../../services/payment-bridge.abstract';
|
||||
import { PosPaymentBridgeService } from '../../services/payment-bridge.service';
|
||||
import { PosLandingStore } from '../../store/main.store';
|
||||
@@ -32,10 +32,7 @@ import { PosLandingStore } from '../../store/main.store';
|
||||
],
|
||||
providers: [{ provide: PosPaymentBridgeAbstract, useExisting: PosPaymentBridgeService }],
|
||||
})
|
||||
export class PosPaymentFormDialogComponent
|
||||
extends AbstractFormDialog<IPayment, IPayment>
|
||||
implements OnInit, OnDestroy
|
||||
{
|
||||
export class PosPaymentFormDialogComponent extends AbstractFormDialog<IPayment, IPosOrderResponse> {
|
||||
private readonly store = inject(PosLandingStore);
|
||||
private readonly paymentBridge = inject(PosPaymentBridgeAbstract);
|
||||
private readonly nativeBridgeService = inject(NativeBridgeService);
|
||||
@@ -72,8 +69,8 @@ export class PosPaymentFormDialogComponent
|
||||
|
||||
private initForm = () => {
|
||||
const form = this.fb.group({
|
||||
set_off: [this.initialValues?.set_off || 0],
|
||||
cash: [this.initialValues?.cash || 0],
|
||||
set_off: [0],
|
||||
cash: [0],
|
||||
terminals: this.fb.array([this.fb.control(0)]),
|
||||
});
|
||||
|
||||
@@ -237,10 +234,7 @@ export class PosPaymentFormDialogComponent
|
||||
)
|
||||
.subscribe((res) => {
|
||||
this.close();
|
||||
this.onSubmit.emit();
|
||||
this.toastServices.success({
|
||||
text: 'فاکتور شما با موفقیت ایجاد شد',
|
||||
});
|
||||
this.onSubmit.emit(res);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -289,7 +283,7 @@ export class PosPaymentFormDialogComponent
|
||||
// }
|
||||
}
|
||||
|
||||
override onSuccess(response: IPayment): void {}
|
||||
override onSuccess(response: IPosOrderResponse): void {}
|
||||
|
||||
private extractAmountFromPaymentResult(payload: unknown): number | null {
|
||||
if (!payload || typeof payload !== 'object') return null;
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ export interface IPosOrderRequest {
|
||||
}
|
||||
|
||||
export interface IPosOrderRawResponse {
|
||||
id?: string;
|
||||
code?: string;
|
||||
id: string;
|
||||
code: string;
|
||||
}
|
||||
export interface IPosOrderResponse extends IPosOrderRawResponse {}
|
||||
|
||||
@@ -1,47 +1,48 @@
|
||||
@if (loading()) {
|
||||
<shared-page-loading />
|
||||
} @else if (pos()) {
|
||||
<div class="w-full h-[calc(100dvh-5.5rem)] overflow-hidden">
|
||||
<div
|
||||
[class]="`w-full h-full flex max-md:flex-col gap-4 pb-4 pt-0 overflow-hidden ${inOrderGoods().length > 0 ? 'pb-18!' : ''}`"
|
||||
>
|
||||
<div class="grow h-full overflow-auto">
|
||||
<div class="w-full min-h-[calc(100dvh-5.5rem)] md:overflow-hidden">
|
||||
<div [class]="`w-full h-full flex max-md:flex-col gap-4 pb-4 pt-0`">
|
||||
<div class="grow min-h-[calc(100dvh-5.5rem)]">
|
||||
<pos-goods class="block h-full" />
|
||||
</div>
|
||||
<div class="md:shrink-0 md:h-full md:block hidden p-4 overflow-auto">
|
||||
<div class="md:shrink-0 h-full md:block hidden p-4 overflow-auto">
|
||||
<pos-order-section />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (inOrderGoods().length > 0) {
|
||||
<button
|
||||
type="button"
|
||||
pButton
|
||||
class="sticky! bottom-0 inset-x-0 w-full right-0 z-1200 border-t border-surface-border bg-surface-0 px-4 py-3 shadow-[0_-4px_16px_rgba(0,0,0,0.08)] md:hidden rounded-b-none!"
|
||||
[style.paddingBottom]="'calc(0.75rem + env(safe-area-inset-bottom))'"
|
||||
(click)="openInvoiceBottomSheet()"
|
||||
>
|
||||
<div class="mx-auto flex w-full max-w-3xl items-center justify-between">
|
||||
<div class="flex flex-col items-start gap-1">
|
||||
<span class="text-base">مبلغ کل فاکتور</span>
|
||||
<span class="text-xl font-semibold" [appPriceMask]="priceInfo().totalAmount"></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-base font-medium">مشاهده فاکتور</span>
|
||||
<i class="pi pi-chevron-up"></i>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
}
|
||||
|
||||
<shared-dialog
|
||||
[(visible)]="showInvoiceBottomSheet"
|
||||
position="bottom"
|
||||
[modal]="true"
|
||||
[closable]="true"
|
||||
header="فاکتور"
|
||||
>
|
||||
<pos-order-section (onAddMoreGoods)="closeInvoiceBottomSheet()" (onSuccess)="closeInvoiceBottomSheet()" />
|
||||
</shared-dialog>
|
||||
</div>
|
||||
|
||||
@if (inOrderGoods().length > 0) {
|
||||
<button
|
||||
type="button"
|
||||
pButton
|
||||
class="sticky! bottom-0 inset-x-0 w-full right-0 z-1200 border-t border-surface-border bg-surface-0 px-4 py-3 shadow-[0_-4px_16px_rgba(0,0,0,0.08)] md:hidden! rounded-b-none!"
|
||||
[style.paddingBottom]="'calc(0.75rem + env(safe-area-inset-bottom))'"
|
||||
(click)="openInvoiceBottomSheet()"
|
||||
>
|
||||
<div class="mx-auto flex w-full max-w-3xl items-center justify-between">
|
||||
<div class="flex flex-col items-start gap-1">
|
||||
<span class="text-base">مبلغ کل فاکتور</span>
|
||||
<span class="text-xl font-semibold" [appPriceMask]="priceInfo().totalAmount"></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-base font-medium">مشاهده فاکتور</span>
|
||||
<i class="pi pi-chevron-up"></i>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
}
|
||||
<shared-dialog
|
||||
[(visible)]="showInvoiceBottomSheet"
|
||||
position="bottom"
|
||||
[modal]="true"
|
||||
[closable]="true"
|
||||
header="فاکتور"
|
||||
>
|
||||
<pos-order-section (onAddMoreGoods)="closeInvoiceBottomSheet()" (onSuccess)="onSuccessSubmit($event)" />
|
||||
</shared-dialog>
|
||||
|
||||
@if (responseInvoice()) {
|
||||
<pos-order-submitted-dialog [(visible)]="isVisibleSuccessDialog" [invoice]="responseInvoice()!" />
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// import { CatalogRoleTagComponent } from '@/shared/catalog/roles';
|
||||
import { Maybe } from '@/core';
|
||||
import { PosInfoStore } from '@/domains/pos/store/pos.store';
|
||||
import { SharedDialogComponent } from '@/shared/components';
|
||||
import { PageLoadingComponent } from '@/shared/components/page-loading.component';
|
||||
@@ -7,6 +8,8 @@ import { Component, computed, inject, signal } from '@angular/core';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { PosGoodsComponent } from '../components/goods.component';
|
||||
import { PosOrderSectionComponent } from '../components/order/order-section.component';
|
||||
import { PosOrderSubmittedDialogComponent } from '../components/order/order-submitted-dialog.component';
|
||||
import { IPosOrderResponse } from '../models';
|
||||
import { PosLandingStore } from '../store/main.store';
|
||||
|
||||
@Component({
|
||||
@@ -21,12 +24,16 @@ import { PosLandingStore } from '../store/main.store';
|
||||
PriceMaskDirective,
|
||||
SharedDialogComponent,
|
||||
ButtonDirective,
|
||||
PosOrderSubmittedDialogComponent,
|
||||
],
|
||||
})
|
||||
export class PosLandingComponent {
|
||||
private readonly infoStore = inject(PosInfoStore);
|
||||
private readonly landingStore = inject(PosLandingStore);
|
||||
|
||||
isVisibleSuccessDialog = signal(false);
|
||||
responseInvoice = signal<Maybe<IPosOrderResponse>>(null);
|
||||
|
||||
readonly loading = computed(() => this.infoStore.loading());
|
||||
readonly pos = computed(() => this.infoStore.entity());
|
||||
readonly error = computed(() => this.infoStore.error());
|
||||
@@ -45,4 +52,14 @@ export class PosLandingComponent {
|
||||
closeInvoiceBottomSheet() {
|
||||
this.showInvoiceBottomSheet.set(false);
|
||||
}
|
||||
|
||||
onSuccessSubmit(invoice: IPosOrderResponse) {
|
||||
this.closeInvoiceBottomSheet();
|
||||
this.responseInvoice.set(invoice);
|
||||
this.isVisibleSuccessDialog.set(true);
|
||||
}
|
||||
|
||||
closeSuccessDialog() {
|
||||
this.isVisibleSuccessDialog.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ export class SaleInvoiceCardComponent {
|
||||
if (customer) {
|
||||
const { legal, individual } = customer;
|
||||
let text = 'نوع اول - ';
|
||||
console.log(customer);
|
||||
if (legal) {
|
||||
text += `حقوقی (${legal.company_name})`;
|
||||
}
|
||||
@@ -67,7 +66,7 @@ export class SaleInvoiceCardComponent {
|
||||
sendInvoice() {
|
||||
this.sendingLoading.set(true);
|
||||
this.service
|
||||
.sendFiscal(this.saleInvoice.id)
|
||||
.sendToTsp(this.saleInvoice.id)
|
||||
.pipe(finalize(() => this.sendingLoading.set(false)))
|
||||
.subscribe(() => {
|
||||
this.toastService.success({ text: 'ارسال فاکتور با موفقیت انجام شد.' });
|
||||
@@ -88,7 +87,7 @@ export class SaleInvoiceCardComponent {
|
||||
resendInvoice() {
|
||||
this.resendingLoading.set(true);
|
||||
this.service
|
||||
.retryFiscal(this.saleInvoice.id)
|
||||
.retrySendToTsp(this.saleInvoice.id)
|
||||
.pipe(finalize(() => this.resendingLoading.set(false)))
|
||||
.subscribe(() => {
|
||||
this.toastService.success({ text: 'ارسال مجدد فاکتور با موفقیت انجام شد.' });
|
||||
|
||||
@@ -3,12 +3,12 @@ const baseUrl = () => `/api/v1/pos/sales_invoices`;
|
||||
export const POS_SALE_INVOICES_API_ROUTES = {
|
||||
list: () => baseUrl(),
|
||||
single: (invoiceId: string) => `${baseUrl()}/${invoiceId}`,
|
||||
fiscal: {
|
||||
tsp: {
|
||||
send: (invoiceId: string) => `${baseUrl()}/${invoiceId}/send`,
|
||||
retry: (invoiceId: string) => `${baseUrl()}/${invoiceId}/fiscal/retry`,
|
||||
status: (invoiceId: string) => `${baseUrl()}/${invoiceId}/fiscal/status`,
|
||||
getInquiry: (invoiceId: string) => `${baseUrl()}/${invoiceId}/inquiry`,
|
||||
revoke: (invoiceId: string) => `${baseUrl()}/${invoiceId}/revoke`,
|
||||
retry: (invoiceId: string) => `${baseUrl()}/${invoiceId}/fiscal/retry`,
|
||||
status: (invoiceId: string) => `${baseUrl()}/${invoiceId}/fiscal/status`,
|
||||
attempts: (invoiceId: string) => `${baseUrl()}/${invoiceId}/fiscal/attempts`,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -32,43 +32,41 @@ export class PosSaleInvoicesService {
|
||||
return this.http.get<ISaleInvoiceFullRawResponse>(this.apiRoutes.single(invoiceId));
|
||||
}
|
||||
|
||||
sendFiscal(invoiceId: string): Observable<IPosSaleInvoiceFiscalActionResponse> {
|
||||
sendToTsp(invoiceId: string): Observable<IPosSaleInvoiceFiscalActionResponse> {
|
||||
return this.http.post<IPosSaleInvoiceFiscalActionResponse>(
|
||||
this.apiRoutes.fiscal.send(invoiceId),
|
||||
this.apiRoutes.tsp.send(invoiceId),
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
retryFiscal(invoiceId: string): Observable<IPosSaleInvoiceFiscalActionResponse> {
|
||||
retrySendToTsp(invoiceId: string): Observable<IPosSaleInvoiceFiscalActionResponse> {
|
||||
return this.http.post<IPosSaleInvoiceFiscalActionResponse>(
|
||||
this.apiRoutes.fiscal.retry(invoiceId),
|
||||
this.apiRoutes.tsp.retry(invoiceId),
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
getFiscalStatus(invoiceId: string): Observable<IPosSaleInvoiceFiscalStatusResponse> {
|
||||
return this.http.get<IPosSaleInvoiceFiscalStatusResponse>(
|
||||
this.apiRoutes.fiscal.status(invoiceId),
|
||||
);
|
||||
return this.http.get<IPosSaleInvoiceFiscalStatusResponse>(this.apiRoutes.tsp.status(invoiceId));
|
||||
}
|
||||
|
||||
getInquiry(invoiceId: string): Observable<IPosSaleInvoiceFiscalStatusResponse> {
|
||||
return this.http.get<IPosSaleInvoiceFiscalStatusResponse>(
|
||||
this.apiRoutes.fiscal.getInquiry(invoiceId),
|
||||
this.apiRoutes.tsp.getInquiry(invoiceId),
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
revoke(invoiceId: string): Observable<IPosSaleInvoiceFiscalStatusResponse> {
|
||||
return this.http.post<IPosSaleInvoiceFiscalStatusResponse>(
|
||||
this.apiRoutes.fiscal.revoke(invoiceId),
|
||||
this.apiRoutes.tsp.revoke(invoiceId),
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
getFiscalAttempts(invoiceId: string): Observable<IPosSaleInvoiceFiscalAttemptsResponse> {
|
||||
return this.http.get<IPosSaleInvoiceFiscalAttemptsResponse>(
|
||||
this.apiRoutes.fiscal.attempts(invoiceId),
|
||||
this.apiRoutes.tsp.attempts(invoiceId),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user