set own datepicker and change فاکتور to صورت‌حساب

This commit is contained in:
2026-05-31 13:54:34 +03:30
parent f50219a094
commit 4ec6143068
53 changed files with 557 additions and 13514 deletions
@@ -8,7 +8,7 @@ export const CONSUMER_MENU_ITEMS = [
routerLink: ['/'],
},
{
label: 'فاکتورها',
label: 'صورت‌حساب‌ها',
icon: 'pi pi-fw pi-home',
},
],
@@ -13,7 +13,7 @@
<pos-change-password-form class="w-full" />
<app-card-data cardTitle="تنظیمات پرینت صورت‌حساب" class="w-full">
<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()" />
</app-card-data>
@@ -4,7 +4,7 @@
[modal]="true"
[dismissible]="true"
[showCloseIcon]="true"
header="فیلتر فاکتورها"
header="فیلتر صورت‌حساب‌ها"
styleClass="w-full md:w-[28rem]"
(visibleChange)="visibleChange.emit($event)">
<div class="flex h-full flex-col overflow-y-auto">
@@ -24,8 +24,8 @@
<app-input label="شناسه اقتصادی" [control]="form.controls.customer_economic_code" name="customer_economic_code" />
<!-- <div class="grid grid-cols-2 gap-2">
<uikit-datepicker label="از تاریخ فاکتور" [control]="form.controls.invoice_date_from" name="invoice_date_from" />
<uikit-datepicker label="تا تاریخ فاکتور" [control]="form.controls.invoice_date_to" name="invoice_date_to" />
<uikit-datepicker label="از تاریخ صورت‌حساب‌" [control]="form.controls.invoice_date_from" name="invoice_date_from" />
<uikit-datepicker label="تا تاریخ صورت‌حساب‌" [control]="form.controls.invoice_date_to" name="invoice_date_to" />
</div>
<div class="grid grid-cols-2 gap-2">
@@ -1,5 +1,5 @@
<div class="bg-surface-card">
<app-inner-pages-header pageTitle="لیست فاکتورهای صادر شده" [backRoute]="backRoute">
<app-inner-pages-header pageTitle="لیست صورت‌حساب‌های صادر شده" [backRoute]="backRoute">
<ng-template #actions>
<div class="flex gap-1">
<p-button
@@ -34,7 +34,7 @@
}
} @else if (!items() || items().length === 0) {
<div class="col-span-1">
<p class="text-muted-color text-center">فاکتوری یافت نشد.</p>
<p class="text-muted-color text-center">صورت‌حساب‌ی یافت نشد.</p>
</div>
} @else {
@for (item of items(); track item.id) {
@@ -48,8 +48,8 @@ export class PosSaleInvoiceListComponent {
filters = signal<IPosSaleInvoicesFilterDto>({});
activeFilters = computed(() => {
const labels: Partial<Record<keyof IPosSaleInvoicesFilterDto, string>> = {
invoice_date_from: 'از تاریخ فاکتور',
invoice_date_to: 'تا تاریخ فاکتور',
invoice_date_from: 'از تاریخ صورت‌حساب‌',
invoice_date_to: 'تا تاریخ صورت‌حساب‌',
created_at_from: 'از تاریخ ایجاد',
created_at_to: 'تا تاریخ ایجاد',
invoice_number: 'شماره صورت‌حساب',
@@ -9,10 +9,10 @@
{{ preparedInvoiceType() }}
</app-key-value>
<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" />
</app-key-value>
<app-key-value alignment="end" label="تاریخ فاکتور" [value]="saleInvoice.created_at" type="dateTime" />
<app-key-value alignment="end" label="تاریخ صورت‌حساب‌" [value]="saleInvoice.created_at" type="date" />
</div>
<hr />
<div class="flex items-center justify-center gap-4">
@@ -27,7 +27,7 @@
}
@if (saleInvoice.status.value.toLowerCase() === 'not_send') {
<p-button
label="ارسال فاکتور"
label="ارسال صورت‌حساب‌"
type="button"
(click)="sendInvoice()"
[loading]="sendingLoading()"
@@ -74,12 +74,12 @@ export class SaleInvoiceCardComponent {
.subscribe((res) => {
if (res.status === 'SEND_FAILURE') {
this.toastService.error({
text: res.message || 'خطا در ارسال فاکتور رخ داده است.',
text: res.message || 'خطا در ارسال صورت‌حساب‌ رخ داده است.',
});
} else {
this.toastService.success({ text: 'ارسال فاکتور با موفقیت انجام شد.' });
this.toastService.success({ text: 'ارسال صورت‌حساب‌ با موفقیت انجام شد.' });
}
// this.toastService.success({ text: 'ارسال فاکتور با موفقیت انجام شد.' });
// this.toastService.success({ text: 'ارسال صورت‌حساب‌ با موفقیت انجام شد.' });
this.refreshRequested.emit();
});
}
@@ -91,7 +91,7 @@ export class SaleInvoiceCardComponent {
.pipe(finalize(() => this.gettingStatusLoading.set(false)))
.subscribe((res) => {
this.toastService.info({
text: `وضعیت فعلی فاکتور شماره‌ی ${this.saleInvoice.invoice_number}، ${taxProviderStatusTranslatorUtil(res.status)} می‌باشد.`,
text: `وضعیت فعلی صورت‌حساب‌ شماره‌ی ${this.saleInvoice.invoice_number}، ${taxProviderStatusTranslatorUtil(res.status)} می‌باشد.`,
});
this.refreshRequested.emit();
});
@@ -104,9 +104,11 @@ export class SaleInvoiceCardComponent {
.pipe(finalize(() => this.resendingLoading.set(false)))
.subscribe((res) => {
if (res.status === 'FAILURE') {
this.toastService.error({ text: res.message || 'خطا در ارسال مجدد فاکتور رخ داده است.' });
this.toastService.error({
text: res.message || 'خطا در ارسال مجدد صورت‌حساب‌ رخ داده است.',
});
} else {
this.toastService.success({ text: 'ارسال مجدد فاکتور با موفقیت انجام شد.' });
this.toastService.success({ text: 'ارسال مجدد صورت‌حساب‌ با موفقیت انجام شد.' });
}
this.refreshRequested.emit();
});
@@ -118,7 +120,7 @@ export class SaleInvoiceCardComponent {
.revoke(this.saleInvoice.id)
.pipe(finalize(() => this.revokingInvoiceLoading.set(false)))
.subscribe(() => {
this.toastService.success({ text: 'ابطال فاکتور با موفقیت انجام شد.' });
this.toastService.success({ text: 'ابطال صورت‌حساب‌ با موفقیت انجام شد.' });
this.refreshRequested.emit();
});
}
@@ -12,7 +12,7 @@ export const posSaleInvoicesNamedRoutes: NamedRoutes<TPosSaleInvoicesRouteNames>
loadComponent: () =>
import('../../views/list.component').then((m) => m.PosSaleInvoicesComponent),
meta: {
title: 'فاکتورها',
title: 'صورت‌حساب‌ها',
pagePath: () => baseRoute,
},
},
@@ -21,7 +21,7 @@ export const posSaleInvoicesNamedRoutes: NamedRoutes<TPosSaleInvoicesRouteNames>
loadComponent: () =>
import('../../views/single.component').then((m) => m.PosSaleInvoiceComponent),
meta: {
title: 'جزئیات فاکتور',
title: 'جزئیات صورت‌حساب‌',
pagePath: (invoiceId: string) => `${baseRoute}/${invoiceId}`,
},
},
@@ -41,9 +41,18 @@
<hr />
<div class="sticky bottom-0 flex flex-col gap-4 py-2">
<p-card class="border-surface-border border">
<div class="flex shrink-0 items-center justify-between gap-2">
<app-key-value label="مشتری" [value]="customerNameToShow()" />
<button pButton outlined icon="pi pi-pencil" size="small" (click)="openCustomerDialog()"></button>
<div class="flex flex-col gap-4">
<app-datepicker
label="تاریخ صورت‌حساب‌"
alignment="horizontal"
[min]="invoiceMinDate"
[max]="invoiceMaxDate"
[control]="invoiceDate"
(valueChange)="changeDate($event)" />
<div class="flex shrink-0 items-center justify-between gap-2">
<app-key-value label="مشتری" [value]="customerNameToShow()" />
<button pButton outlined icon="pi pi-pencil" size="small" (click)="openCustomerDialog()"></button>
</div>
</div>
</p-card>
<pos-order-price-info-card />
@@ -1,6 +1,8 @@
// import { CustomersSelectComponent } from '@/modules/customers/components/select/select.component';
// import { ICustomerResponse } from '@/modules/customers/models';
import { KeyValueComponent } from '@/shared/components';
import { MiniMonthlyCalendarComponent } from '@/uikit';
import { formatGregorian, gregorianAddUnit } from '@/utils';
import {
ChangeDetectionStrategy,
Component,
@@ -10,7 +12,7 @@ import {
Output,
signal,
} from '@angular/core';
import { FormsModule } from '@angular/forms';
import { FormControl, FormsModule } from '@angular/forms';
import { ButtonDirective } from 'primeng/button';
import { Card } from 'primeng/card';
import images from 'src/assets/images';
@@ -33,6 +35,7 @@ import { POSOrderPriceInfoCardComponent } from './price-info-card.component';
PosOrderCustomerDialogComponent,
KeyValueComponent,
Card,
MiniMonthlyCalendarComponent,
],
})
export class PosOrderSectionComponent {
@@ -43,6 +46,10 @@ export class PosOrderSectionComponent {
placeholderImage = images.placeholders.default;
isVisibleCustomerForm = signal(false);
invoiceMinDate = formatGregorian(gregorianAddUnit(new Date(), -7, 'days'));
invoiceMaxDate = formatGregorian(new Date());
invoiceDate = new FormControl(this.store.invoiceDate());
inOrderGoods = computed(() => this.store.inOrderGoods());
customer = computed(() => this.store.customer());
@@ -88,4 +95,8 @@ export class PosOrderSectionComponent {
}
submitCustomer() {}
changeDate(date: string) {
this.store.setInvoiceDate(date);
}
}
@@ -9,12 +9,14 @@
<qrcode [qrdata]="publicInvoiceRoute()" [width]="220" [errorCorrectionLevel]="'M'"></qrcode>
<div class="flex items-center gap-2">
<i class="" class="pi pi-check-circle text-xl! text-green-700"></i>
<p class="text-lg font-bold">فاکتور شما با موفقیت ایجاد شد.</p>
<p class="text-lg font-bold">صورت‌حساب‌ شما با موفقیت ایجاد شد.</p>
</div>
</div>
<div class="flex justify-center gap-2">
<button pButton type="button" outlined (click)="printInvoice()">چاپ</button>
<button pButton type="button" outlined (click)="sendInvoice()">ارسال به سامانه مودیان</button>
<button pButton type="button" outlined [loading]="sendingLoading()" (click)="sendInvoice()">
ارسال به سامانه مودیان
</button>
<button pButton type="button" outlined (click)="openOrderDetails()">جزئیات</button>
</div>
</shared-light-bottomsheet>
@@ -53,7 +53,7 @@ export class PosOrderSubmittedDialogComponent extends AbstractDialog {
.sendToTsp(this.invoice.id)
.pipe(finalize(() => this.sendingLoading.set(false)))
.subscribe(() => {
this.toastService.success({ text: 'ارسال فاکتور با موفقیت انجام شد.' });
this.toastService.success({ text: 'ارسال صورت‌حساب‌ با موفقیت انجام شد.' });
this.sended.set(true);
this.close();
});
@@ -65,7 +65,7 @@ export class PosOrderSubmittedDialogComponent extends AbstractDialog {
title: `فروشگاه ${this.posName()}`,
items: [
{
label: 'شماره فاکتور',
label: 'شماره صورت‌حساب‌',
value: this.invoice.code,
},
{ label: 'تاریخ', value: formatJalali(this.invoice.invoice_date, 'YYYY/MM/DD') },
@@ -287,7 +287,7 @@ export class PosPaymentFormDialogComponent extends AbstractFormDialog<IPayment,
if (this.selectedSettlementType() === 'CASH') {
if (this.remainedAmount() > 0) {
return this.toastServices.warn({
text: 'فاکتور تسویه نشده است. لطفا مبلغ پرداخت را کامل کنید..',
text: 'صورت‌حساب‌ تسویه نشده است. لطفا مبلغ پرداخت را کامل کنید..',
});
}
}
@@ -1,9 +1,14 @@
import { Maybe } from '@/core';
// import { ICustomerResponse } from '@/modules/customers/models';
import { ToastService } from '@/core/services/toast.service';
import { IGoodCategoryResponse, IGoodResponse } from '@/domains/pos/models/good.io';
import { CustomerType } from '@/shared/localEnum/constants/customerTypes';
import { createUUID, JALALI_DATE_FORMATS, nowJalali } from '@/utils';
import {
createUUID,
formatDate,
GREGORIAN_DATE_FORMATS,
JALALI_DATE_FORMATS,
nowGregorian,
} from '@/utils';
import { computed, inject, Injectable, signal } from '@angular/core';
import { catchError, finalize, firstValueFrom, map, throwError } from 'rxjs';
import { ICustomer, IPayment, IPosOrderRequest, IPosOrderResponse } from '../models';
@@ -47,7 +52,7 @@ export const INITIAL_POS_STATE: IPosLandingState = {
customerDetails: {
type: CustomerType.UNKNOWN,
},
invoiceDate: nowJalali(JALALI_DATE_FORMATS.NUMERIC_WITH_FULL_TIME),
invoiceDate: nowGregorian(JALALI_DATE_FORMATS.FULL),
payments: {
cash: 0,
set_off: 0,
@@ -59,7 +64,6 @@ export const INITIAL_POS_STATE: IPosLandingState = {
@Injectable({ providedIn: 'any' })
export class PosLandingStore {
private readonly service = inject(PosService);
private readonly toastServices = inject(ToastService);
private state$ = signal<IPosLandingState>({ ...INITIAL_POS_STATE });
@@ -249,6 +253,10 @@ export class PosLandingStore {
this.setState({ customerDetails: customer });
}
setInvoiceDate(invoiceDate: string) {
this.setState({ invoiceDate });
}
setPayment(payments: IPayment) {
this.setState({ payments });
}
@@ -259,6 +267,7 @@ export class PosLandingStore {
submitOrder() {
this.setState({ submitOrderLoading: true });
const orderPayload: IPosOrderRequest = {
customer_id: this.customer().customer_id,
customer_type: this.customer().type,
@@ -268,7 +277,9 @@ export class PosLandingStore {
good_id: good.id,
measure_unit: good.measure_unit,
})),
invoice_date: new Date().toISOString(),
invoice_date: new Date(
formatDate(this.invoiceDate(), 'gregory', 'en', GREGORIAN_DATE_FORMATS.FULL)
).toISOString(),
payments: this.payments(),
settlement_type: this.state$().settlement_type,
total_amount: this.orderPricingInfo().totalAmount,
@@ -295,7 +306,7 @@ export class PosLandingStore {
customerDetails: {
type: CustomerType.UNKNOWN,
},
invoiceDate: nowJalali(JALALI_DATE_FORMATS.NUMERIC),
invoiceDate: _res.invoice_date,
payments: {
cash: 0,
set_off: 0,
@@ -23,17 +23,17 @@
<!-- [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="flex flex-col items-start gap-1">
<span class="text-base">مبلغ کل فاکتور</span>
<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>
<span class="text-base font-medium">مشاهده صورت‌حساب‌</span>
<i class="pi pi-chevron-up"></i>
</div>
</div>
</button>
}
<shared-light-bottomsheet [(visible)]="showInvoiceBottomSheet" [closable]="true" header="جزییات فاکتور">
<shared-light-bottomsheet [(visible)]="showInvoiceBottomSheet" [closable]="true" header="جزییات صورت‌حساب‌">
<pos-order-section (onAddMoreGoods)="closeInvoiceBottomSheet()" (onSubmit)="submitOrder()" />
</shared-light-bottomsheet>