import { Maybe } from '@/core'; import { NativeBridgeService } from '@/core/services'; import { ToastService } from '@/core/services/toast.service'; import { PosConfigPrintService } from '@/domains/pos/modules/configs/components/print/services/main.service'; import { PosInfoStore } from '@/domains/pos/store'; import { CatalogInvoiceTypeTagComponent, CatalogTaxProviderStatusTagComponent, } from '@/shared/catalog'; import { CatalogInvoiceSettlementTypeTagComponent } from '@/shared/catalog/invoiceSettlementType'; import { AppCardComponent, KeyValueComponent, SharedLightBottomsheetComponent, } from '@/shared/components'; import { ISaleInvoiceFullResponse } from '@/shared/components/invoices/sale-invoice-full-response.model'; import { PageLoadingComponent } from '@/shared/components/page-loading.component'; import { IColumn, PageDataListComponent, } from '@/shared/components/pageDataList/page-data-list.component'; import { PriceMaskDirective } from '@/shared/directives'; import { UikitEmptyStateComponent } from '@/uikit'; import { formatWithCurrency } from '@/utils'; import { Component, computed, EventEmitter, inject, Input, Output, signal, SimpleChanges, TemplateRef, ViewChild, } from '@angular/core'; import { UrlTree } from '@angular/router'; import { MenuItem } from 'primeng/api'; import { Button } from 'primeng/button'; import { Divider } from 'primeng/divider'; import { Menu } from 'primeng/menu'; import { ProgressSpinner } from 'primeng/progressspinner'; import { TableModule } from 'primeng/table'; import { Observable } from 'rxjs'; import { AppConfirmationService } from '../confirmationDialog/confirmation-dialog.service'; import { SharedReturnFormComponent } from './returnForm/form.component'; export type TSaleInvoiceSingleViewVariant = 'full' | 'customer' | 'pos'; @Component({ selector: 'shared-sale-invoice-single-view', templateUrl: './sale-invoice-single-view.component.html', imports: [ AppCardComponent, KeyValueComponent, Divider, PageDataListComponent, TableModule, PageLoadingComponent, UikitEmptyStateComponent, PriceMaskDirective, CatalogTaxProviderStatusTagComponent, CatalogInvoiceTypeTagComponent, Menu, Button, CatalogInvoiceSettlementTypeTagComponent, SharedLightBottomsheetComponent, ProgressSpinner, SharedReturnFormComponent, ], }) export class SharedSaleInvoiceSingleViewComponent { private readonly nativeBridge = inject(NativeBridgeService); private readonly posInfoStore = inject(PosInfoStore); private readonly toastService = inject(ToastService); //TODO: below service Must be transform from pos to shared. private readonly service = inject(PosConfigPrintService); private readonly confirmationService = inject(AppConfirmationService); @Input({ required: true }) loading!: boolean; @Input() invoice!: Maybe; @Input() variant: TSaleInvoiceSingleViewVariant = 'full'; @Input() backRoute?: UrlTree | string | any[]; @Input() sendToTspLoading: boolean = false; @Input() resendToTspLoading: boolean = false; @Input() inquiryLoading: boolean = false; @Output() onRefresh = new EventEmitter(); @Output() onSendToTsp = new EventEmitter>(); @Output() onInquiry = new EventEmitter>(); @ViewChild('totalAmount', { static: false }) totalAmount!: TemplateRef; moreActionMenuItems = signal([]); showCorrectionForm = signal(false); showBackFromSaleForm = signal(false); constructor() { this.showErrors = this.showErrors.bind(this); this.showRevokeConfirmation = this.showRevokeConfirmation.bind(this); this.showCorrection = this.showCorrection.bind(this); this.showBackFromSale = this.showBackFromSale.bind(this); this.printInvoice = this.printInvoice.bind(this); this.send = this.send.bind(this); this.inquiry = this.inquiry.bind(this); } get actionLoading() { return this.sendToTspLoading || this.inquiryLoading || this.resendToTspLoading; } showErrors() {} inquiry() { this.onInquiry.emit(); } send() { this.onSendToTsp.emit(); } async showRevokeConfirmation() { await this.confirmationService.ask({ header: `ابطال صورت‌حساب‌ شماره ${this.invoice!.invoice_number}`, message: `در صورت تایید ابطال صورت‌حساب‌ شماره ${this.invoice!.invoice_number} بر روی دکمه‌ی ابطال کلیک کنید.`, acceptLabel: 'ابطال', acceptButtonProps: { severity: 'dangerdock', }, variant: 'danger', accept: async () => { // this.deferredInstallPrompt.prompt(); // this.deferredInstallPrompt.userChoice.finally(() => { // this.deferredInstallPrompt = null; // this.canInstall.set(false); // window.location.reload(); // }); // }, }, }); } showCorrection() {} showBackFromSale() { this.showBackFromSaleForm.set(true); } ngOnChanges(changes: SimpleChanges) { if (changes['invoice'] && this.invoice) { const invoiceStatus = this.invoice.status.value; const actions: MenuItem[] = [ { label: 'ارسال صورت‌حساب', icon: 'pi pi-send', neededStatus: 'NOT_SEND', command: this.send, }, { label: 'استعلام وضعیت', icon: 'pi pi-info', neededStatus: 'FISCAL_QUEUED', command: this.inquiry, }, { label: 'دلایل خطا', icon: 'pi pi-question', neededStatus: 'FAILURE', command: this.showErrors, }, { label: 'ابطال', icon: 'pi pi-eraser', neededStatus: 'SUCCESS', command: this.showRevokeConfirmation, }, { label: 'اصلاح', icon: 'pi pi-file-edit', neededStatus: 'SUCCESS', command: this.showCorrection, }, { label: 'برگشت از فروش', icon: 'pi pi-cart-minus', neededStatus: 'SUCCESS', command: this.showBackFromSale, }, { label: 'چاپ', icon: 'pi pi-print', neededStatus: '', command: this.printInvoice, }, ]; this.moreActionMenuItems.set( actions.filter( // @ts-ignore (action) => !action.neededStatus || action.neededStatus === invoiceStatus ) ); } } readonly posName = computed(() => { if (this.posInfoStore.entity()) { const { name, businessActivity, complex } = this.posInfoStore.entity()!; return `${name} (${businessActivity.name} - ${complex.name})`; } return ''; }); preparePrint = async () => { if (this.invoice) { const mustPrintConfig = await this.service.get(); const defaultPrintItems = [ { title: 'اطلاعات صورت‌حساب', items: [ { label: 'شماره منحصر به فرد مالیاتی', value: 'this.invoice', show: true, }, { label: 'شماره صورت‌حساب', value: this.invoice.code, show: true, }, { label: 'موضوع صورت‌حساب', value: 'this.invoice', show: mustPrintConfig.invoice_template ?? true, }, { label: 'نوع صورت‌حساب', value: 'this.invoice', show: mustPrintConfig.invoice_template, }, { label: 'تاریخ و ساعت', value: this.invoice.invoice_date, show: true, }, { label: 'وضعیت صورت‌حساب مالیاتی', value: this.invoice.status.translate, show: mustPrintConfig.show_payment_info ?? true, }, ].filter((item) => item.show), }, { title: `اطلاعات فروشنده`, items: [ { label: 'عنوان فروشگاه', value: this.invoice.pos.complex.business_activity.name, show: mustPrintConfig.business_name, }, { label: 'عنوان شعبه', value: this.invoice.pos.complex.name, show: mustPrintConfig.complex_name, }, { label: 'عنوان پایانه‌ فروش', value: this.invoice.pos.name, show: mustPrintConfig.pos_name, }, { label: 'شماره اقتصادی', value: 'this.invoice.pos.complex.business_activity.economic_code', show: mustPrintConfig.economic_code, }, ].filter((item) => item.show), }, { title: `اطلاعات خریدار`, items: [ { label: 'نام خریدار', value: (this.invoice.customer ? this.invoice.customer.type === 'LEGAL' ? this.invoice.customer.legal?.company_name : `${this.invoice.customer.individual?.first_name} ${this.invoice.customer.individual?.last_name}` : this.invoice.unknown_customer?.name) || '-', show: mustPrintConfig.customer_name, }, { label: 'شماره اقتصادی', value: (this.invoice.customer ? this.invoice.customer.type === 'LEGAL' ? this.invoice.customer.legal?.economic_code : this.invoice.customer.individual?.economic_code || '-' : '-') || '-', show: mustPrintConfig.customer_economic_code, }, ].filter((item) => item.show), }, ].filter((item) => item.items.length); if (mustPrintConfig.show_items) { for (let item of this.invoice.items) { defaultPrintItems.push({ title: 'جزییات صورت‌حساب', items: [ { label: 'شرح', value: item.good.name, show: mustPrintConfig.items?.name, }, { label: 'شناسه کالا / خدمت', value: item.sku_code, show: mustPrintConfig.items?.sku, }, { label: 'تعداد / مقدار', value: `${item.quantity} ${item.measure_unit_text}`, show: mustPrintConfig.items?.quantity, }, { label: 'قیمت واحد', value: formatWithCurrency(item.unit_price), show: mustPrintConfig.items?.base_amount, }, { label: 'اجرت', value: formatWithCurrency(item.payload.wages), show: mustPrintConfig.items?.wage && item.good_snapshot.pricing_model === 'GOLD', }, { label: 'سود', value: formatWithCurrency(item.payload.wages), show: mustPrintConfig.items?.profit && item.good_snapshot.pricing_model === 'GOLD', }, { label: 'حق‌العمل', value: formatWithCurrency(item.payload.commission), show: mustPrintConfig.items?.commission && item.good_snapshot.pricing_model === 'GOLD', }, { label: 'مالیات بر ارزش افزوده', value: 'item.good.tax', show: mustPrintConfig.items?.tax, }, { label: 'تخفیف', value: formatWithCurrency(item.discount), show: mustPrintConfig.items?.discount, }, { label: 'مبلغ کل', value: formatWithCurrency(item.total_amount), show: mustPrintConfig.items?.total_amount, }, ], }); } } return defaultPrintItems; } return null; }; printInvoice = async () => { try { const printItems = await this.preparePrint(); if (printItems) { this.nativeBridge.print(printItems); } } catch (error) { return this.toastService.error({ text: 'چاپ صورت‌حساب با خطا مواجه شد. لطفا دوباره تلاش کنید.', }); } }; columns: IColumn[] = [ { field: 'name', header: 'عنوان', type: 'nested', nestedOption: { path: 'good_snapshot.name', }, }, { field: 'sku_code', header: 'شناسه کالا', }, { field: 'unit_price', header: 'قیمت واحد', type: 'price', }, { field: 'quantity', header: 'مقدار', customDataModel(item) { return `${item.quantity} ${item.measure_unit_text}`; }, }, { field: 'commission', header: 'کارمزد', type: 'nested', nestedOption: { path: 'payload.commission', type: 'price', }, }, { field: 'wages', header: 'اجرت', type: 'nested', nestedOption: { path: 'payload.wages', type: 'price', }, }, { field: 'profit', header: 'سود', type: 'nested', nestedOption: { path: 'payload.profit', type: 'price', }, }, { field: 'discount_amount', header: 'مبلغ تخفیف', type: 'price', }, { field: 'tax_amount', header: 'مبلغ مالیات', type: 'price', }, { field: 'total_amount', header: 'مبلغ قابل پرداخت', type: 'price', }, ]; refresh() { this.onRefresh.emit(); } }