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
@@ -6,6 +6,8 @@ export const POS_SALE_INVOICES_API_ROUTES = {
tsp: {
send: (invoiceId: string) => `${baseUrl()}/${invoiceId}/send`,
getInquiry: (invoiceId: string) => `${baseUrl()}/${invoiceId}/inquiry`,
correction: (invoiceId: string) => `${baseUrl()}/${invoiceId}/correction`,
returnFromSale: (invoiceId: string) => `${baseUrl()}/${invoiceId}/return_from_sale`,
revoke: (invoiceId: string) => `${baseUrl()}/${invoiceId}/revoke`,
retry: (invoiceId: string) => `${baseUrl()}/${invoiceId}/retry`,
status: (invoiceId: string) => `${baseUrl()}/${invoiceId}/fiscal/status`,
@@ -0,0 +1,10 @@
import { IPosOrderItem } from '../../shop/models';
export interface IPosCorrectionRequest {
total_amount: number;
discount_amount: number;
tax_amount: number;
invoice_date: string;
items: IPosOrderItem[];
notes?: string;
}
@@ -0,0 +1,10 @@
import { IPosOrderItem } from '../../shop/models';
export interface IPosReturnFromSaleRequest {
total_amount: number;
discount_amount: number;
tax_amount: number;
invoice_date: string;
items: IPosOrderItem[];
notes?: string;
}
@@ -21,11 +21,11 @@ export class PosSaleInvoicesService {
private apiRoutes = POS_SALE_INVOICES_API_ROUTES;
getAll(
query: IPosSaleInvoicesFilterDto = {},
query: IPosSaleInvoicesFilterDto = {}
): Observable<IPaginatedResponse<IPosSaleInvoicesSummaryResponse>> {
return this.http.get<IPaginatedResponse<IPosSaleInvoicesSummaryRawResponse>>(
this.apiRoutes.list(),
{ params: query as Record<string, string | number | boolean> },
{ params: query as Record<string, string | number | boolean> }
);
}
@@ -36,14 +36,14 @@ export class PosSaleInvoicesService {
sendToTsp(invoiceId: string): Observable<IPosSaleInvoiceFiscalActionResponse> {
return this.http.post<IPosSaleInvoiceFiscalActionResponse>(
this.apiRoutes.tsp.send(invoiceId),
{},
{}
);
}
retrySendToTsp(invoiceId: string): Observable<IPosSaleInvoiceFiscalActionResponse> {
return this.http.post<IPosSaleInvoiceFiscalActionResponse>(
this.apiRoutes.tsp.retry(invoiceId),
{},
{}
);
}
@@ -54,20 +54,34 @@ export class PosSaleInvoicesService {
getInquiry(invoiceId: string): Observable<IPosSaleInvoiceFiscalStatusResponse> {
return this.http.get<IPosSaleInvoiceFiscalStatusResponse>(
this.apiRoutes.tsp.getInquiry(invoiceId),
{},
{}
);
}
correction(data: any, invoiceId: string): Observable<IPosSaleInvoiceFiscalActionResponse> {
return this.http.post<IPosSaleInvoiceFiscalActionResponse>(
this.apiRoutes.tsp.correction(invoiceId),
data
);
}
returnFromSale(data: any, invoiceId: string): Observable<IPosSaleInvoiceFiscalActionResponse> {
return this.http.post<IPosSaleInvoiceFiscalActionResponse>(
this.apiRoutes.tsp.returnFromSale(invoiceId),
data
);
}
revoke(invoiceId: string): Observable<IPosSaleInvoiceFiscalStatusResponse> {
return this.http.post<IPosSaleInvoiceFiscalStatusResponse>(
this.apiRoutes.tsp.revoke(invoiceId),
{},
{}
);
}
getFiscalAttempts(invoiceId: string): Observable<IPosSaleInvoiceFiscalAttemptsResponse> {
return this.http.get<IPosSaleInvoiceFiscalAttemptsResponse>(
this.apiRoutes.tsp.attempts(invoiceId),
this.apiRoutes.tsp.attempts(invoiceId)
);
}
}
@@ -4,6 +4,8 @@ import { TspProviderResponseStatus } from '@/shared/catalog';
import taxProviderStatusTranslatorUtil from '@/shared/catalog/taxProviderStatus/tax-provider-status-translator.util';
import { inject, Injectable } from '@angular/core';
import { catchError, finalize } from 'rxjs';
import { IPosCorrectionRequest } from '../models/correction';
import { IPosReturnFromSaleRequest } from '../models/returnFromSale';
import { PosSaleInvoicesService } from '../services/main.service';
interface PosSaleInvoiceState extends EntityState<ISaleInvoiceFullResponse> {}
@@ -53,6 +55,12 @@ export class PosSaleInvoiceStore extends EntityStore<
sendToTsp(invoceId: string) {
return this.service.sendToTsp(invoceId);
}
correction(data: IPosCorrectionRequest, invoceId: string) {
return this.service.correction(data, invoceId);
}
returnFromSale(data: IPosReturnFromSaleRequest, invoceId: string) {
return this.service.returnFromSale(data, invoceId);
}
inquiry(invoceId: string) {
return this.service.getInquiry(invoceId);
}
@@ -7,5 +7,7 @@
[inquiryLoading]="inquiryLoading()"
(onSendToTsp)="sendToTsp()"
(onInquiry)="inquiry()"
(onCorrection)="correction($event)"
(onReturnFromSale)="returnFromSale($event)"
variant="pos" />
</div>
@@ -6,6 +6,8 @@ import { Component, computed, inject, signal } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { finalize } from 'rxjs';
import { posSaleInvoicesNamedRoutes } from '../constants';
import { IPosCorrectionRequest } from '../models/correction';
import { IPosReturnFromSaleRequest } from '../models/returnFromSale';
import { PosSaleInvoiceStore } from '../store/main.store';
@Component({
@@ -78,10 +80,10 @@ export class PosSaleInvoiceComponent {
)
.subscribe();
}
correction() {
correction(data: IPosCorrectionRequest) {
this.correctionLoading.set(true);
this.store
.sendToTsp(this.invoiceId())
.correction(data, this.invoiceId())
.pipe(
finalize(() => {
this.correctionLoading.set(false);
@@ -89,10 +91,10 @@ export class PosSaleInvoiceComponent {
)
.subscribe();
}
backFromSale() {
returnFromSale(data: IPosReturnFromSaleRequest) {
this.backFromSaleLoading.set(true);
this.store
.sendToTsp(this.invoiceId())
.returnFromSale(data, this.invoiceId())
.pipe(
finalize(() => {
this.backFromSaleLoading.set(false);
@@ -11,7 +11,6 @@ import {
} from '@angular/core';
import { ButtonDirective } from 'primeng/button';
import { Skeleton } from 'primeng/skeleton';
import { Tag } from 'primeng/tag';
import images from 'src/assets/images';
import { PosLandingStore } from '../../store/main.store';
import { FavoriteCTAComponent } from './favorite-CTA.component';
@@ -20,7 +19,7 @@ import { FavoriteCTAComponent } from './favorite-CTA.component';
selector: 'pos-goods-list-view',
templateUrl: './list-view.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ButtonDirective, Skeleton, FavoriteCTAComponent, Tag],
imports: [ButtonDirective, Skeleton, FavoriteCTAComponent],
})
export class PosGoodsListViewComponent {
private readonly store = inject(PosLandingStore);
@@ -136,6 +136,7 @@ export class PosLandingStore {
}
private async getGoods() {
// if (this.state$().goods) return;
this.setState({ getGoodsLoading: true });
try {
const res = await firstValueFrom(this.service.getGoods(this.state$().searchQuery));
@@ -146,6 +147,7 @@ export class PosLandingStore {
}
private async getGoodCategories() {
// if (this.state$().goodCategories) return;
this.setState({ getGoodCategoriesLoading: true });
try {
const res = await firstValueFrom(this.service.getGoodCategories());