feat: add correction and return from sale functionalities to sale invoices

- Added new API routes for correction and return from sale in POS_SALE_INVOICES_API_ROUTES.
- Implemented correction and return from sale methods in PosSaleInvoicesService.
- Updated PosSaleInvoiceStore to include actions for correction and return from sale.
- Enhanced single.component to handle correction and return from sale events.
- Created correction and return from sale forms with appropriate validation and submission logic.
- Updated sale-invoice-single-view component to manage correction and return from sale actions.
- Added models for correction and return from sale requests.
- Improved user interface messages and form handling for better user experience.
This commit is contained in:
2026-06-06 19:52:58 +03:30
parent 560b3516e1
commit eb39f42b8c
26 changed files with 472 additions and 42 deletions
@@ -2,6 +2,8 @@ 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 { IPosReturnFromSaleRequest } from '@/domains/pos/modules/saleInvoices/models/returnFromSale';
import { IPosOrderItem } from '@/domains/pos/modules/shop/models';
import { PosInfoStore } from '@/domains/pos/store';
import {
CatalogInvoiceTypeTagComponent,
@@ -44,6 +46,8 @@ import { ProgressSpinner } from 'primeng/progressspinner';
import { TableModule } from 'primeng/table';
import { Observable } from 'rxjs';
import { AppConfirmationService } from '../confirmationDialog/confirmation-dialog.service';
import { SharedCorrectionFormComponent } from './correctionForm';
import { CorrectionInvoiceFormValue, ICorrectionRequest, ReturnFromSaleFormValue } from './models';
import { SharedReturnFormComponent } from './returnForm/form.component';
export type TSaleInvoiceSingleViewVariant = 'full' | 'customer' | 'pos';
@@ -68,6 +72,7 @@ export type TSaleInvoiceSingleViewVariant = 'full' | 'customer' | 'pos';
SharedLightBottomsheetComponent,
ProgressSpinner,
SharedReturnFormComponent,
SharedCorrectionFormComponent,
],
})
export class SharedSaleInvoiceSingleViewComponent {
@@ -90,18 +95,20 @@ export class SharedSaleInvoiceSingleViewComponent {
@Output() onSendToTsp = new EventEmitter<Observable<any>>();
@Output() onResendToTsp = new EventEmitter<Observable<any>>();
@Output() onInquiry = new EventEmitter<Observable<any>>();
@Output() onCorrection = new EventEmitter<ICorrectionRequest>();
@Output() onReturnFromSale = new EventEmitter<IPosReturnFromSaleRequest>();
@ViewChild('totalAmount', { static: false }) totalAmount!: TemplateRef<any>;
moreActionMenuItems = signal<MenuItem[]>([]);
showCorrectionForm = signal(false);
showBackFromSaleForm = signal(false);
showReturnFromSaleForm = 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.showReturnFromSale = this.showReturnFromSale.bind(this);
this.printInvoice = this.printInvoice.bind(this);
this.send = this.send.bind(this);
this.resend = this.resend.bind(this);
@@ -119,9 +126,15 @@ export class SharedSaleInvoiceSingleViewComponent {
send() {
this.onSendToTsp.emit();
}
sendCorrection(event: ICorrectionRequest) {
this.onCorrection.emit(event);
}
resend() {
this.onResendToTsp.emit();
}
sendReturnFromSale(event: IPosReturnFromSaleRequest) {
this.onReturnFromSale.emit(event);
}
async showRevokeConfirmation() {
await this.confirmationService.ask({
header: `ابطال صورت‌حساب‌ شماره ${this.invoice!.invoice_number}`,
@@ -143,9 +156,11 @@ export class SharedSaleInvoiceSingleViewComponent {
},
});
}
showCorrection() {}
showBackFromSale() {
this.showBackFromSaleForm.set(true);
showCorrection() {
this.showCorrectionForm.set(true);
}
showReturnFromSale() {
this.showReturnFromSaleForm.set(true);
}
ngOnChanges(changes: SimpleChanges) {
@@ -192,7 +207,7 @@ export class SharedSaleInvoiceSingleViewComponent {
label: 'برگشت از فروش',
icon: 'pi pi-cart-minus',
neededStatus: TspProviderResponseStatus.SUCCESS,
command: this.showBackFromSale,
command: this.showReturnFromSale,
},
{
label: 'چاپ',
@@ -461,4 +476,70 @@ export class SharedSaleInvoiceSingleViewComponent {
refresh() {
this.onRefresh.emit();
}
private mapCorrectionRequest(event: CorrectionInvoiceFormValue): ICorrectionRequest {
const items = (event.items || []).map(({ id, pricing_model, ...item }) => item);
const total_amount = items.reduce((sum, item) => sum + Number(item.total_amount || 0), 0);
const discount_amount = items.reduce((sum, item) => sum + Number(item.discount_amount || 0), 0);
const tax_amount = items.reduce((sum, item) => sum + Number(item.tax_amount || 0), 0);
return {
invoice_date: event.invoice_date,
items,
total_amount,
discount_amount,
tax_amount,
};
}
correctionSubmit(event: CorrectionInvoiceFormValue) {
this.sendCorrection(this.mapCorrectionRequest(event));
}
private mapReturnFromSaleRequest(event: ReturnFromSaleFormValue): IPosReturnFromSaleRequest {
const invoiceItems = this.invoice?.items || [];
const itemMap = new Map(invoiceItems.map((item) => [item.id, item]));
const items: IPosOrderItem[] = (event.items || [])
.map((item) => {
const source = itemMap.get(item.id);
if (!source) return null;
const quantity = Number(item.quantity || 0);
const unit_price = Number(source.unit_price || 0);
const discount_amount = Number(source.discount || 0);
const base_total_amount = unit_price * quantity;
const total_amount = Number(source.total_amount || 0);
const tax_amount = Number(source.payload?.wages || 0);
return {
good_id: source.good_id,
service_id: source.service_id || undefined,
quantity,
unit_price,
discount_amount,
base_total_amount,
total_amount,
tax_amount,
measure_unit: source.good_snapshot.measure_unit,
payload: source.payload as any,
notes: source.notes,
image_url: source.good_snapshot.image_url,
} as IPosOrderItem;
})
.filter((item): item is IPosOrderItem => !!item);
return {
invoice_date: this.invoice?.invoice_date || '',
items,
total_amount: items.reduce((sum, item) => sum + Number(item.total_amount || 0), 0),
discount_amount: items.reduce((sum, item) => sum + Number(item.discount_amount || 0), 0),
tax_amount: items.reduce((sum, item) => sum + Number(item.tax_amount || 0), 0),
};
}
returnSubmit(event: ReturnFromSaleFormValue) {
this.sendReturnFromSale(this.mapReturnFromSaleRequest(event));
}
}