feat: add sale invoice card component with functionality for sending and retrieving invoice status

- Implemented sale invoice card component with HTML and TypeScript files.
- Added API routes for sale invoices including sending, retrying, and checking status.
- Created models for sale invoice fiscal actions and filters.
- Developed service for handling sale invoice operations.
- Introduced store for managing sale invoice state.
- Created views for listing and displaying single sale invoices.
- Added support for managing stock keeping units with forms and services.
- Implemented reusable select components for measure units and SKUs.
- Enhanced shared components for input fields including fiscal ID, SKU type, and VAT.
This commit is contained in:
2026-05-01 19:45:30 +03:30
parent 8104f1b7a7
commit 83f124b910
94 changed files with 1555 additions and 214 deletions
+45 -13
View File
@@ -1,10 +1,12 @@
import { Injectable } from '@angular/core';
import { inject, Injectable } from '@angular/core';
import { environment } from 'src/environments/environment';
import { Maybe } from '../models';
import { ToastService } from './toast.service';
interface INativeBridgeHost {
pay?: (payload: string) => unknown;
pay?: ((payload: string) => unknown) | ((amount: number, id: Maybe<string>) => unknown);
print?: (payload: string) => unknown;
isEnabled?: () => boolean;
}
export interface INativePayRequest {
@@ -25,17 +27,29 @@ export interface INativeBridgeResult<T = unknown> {
@Injectable({ providedIn: 'root' })
export class NativeBridgeService {
private readonly toastService = inject(ToastService);
private get host(): INativeBridgeHost | undefined {
const globalWindow = window as unknown as {
AndroidBridge?: INativeBridgeHost;
Android?: INativeBridgeHost;
AndroidPSP?: INativeBridgeHost;
};
return globalWindow.AndroidBridge || globalWindow.Android;
return globalWindow.AndroidPSP || globalWindow.AndroidBridge || globalWindow.Android;
}
isEnabled(): boolean {
return !!environment.enableNativeBridge;
const hostEnabled = this.host?.isEnabled;
if (typeof hostEnabled === 'function') {
try {
return !!hostEnabled();
} catch {
return false;
}
}
return !!environment.enableNativeBridge && !!this.host;
}
canPay(): boolean {
@@ -47,21 +61,39 @@ export class NativeBridgeService {
}
pay(request: INativePayRequest): INativeBridgeResult {
return this.invoke('pay', request);
this.toastService.info({ text: 'در حال پردازش پرداخت...', life: 3000 });
const fn = this.host?.pay;
if (typeof fn !== 'function') {
return { success: false, error: 'Native method "pay" is not available.' };
}
try {
let raw: unknown;
if (fn.length >= 2) {
raw = (fn as (amount: number, id: Maybe<string>) => unknown)(request.amount, request.id);
} else {
raw = (fn as (payload: string) => unknown)(JSON.stringify(request));
}
const parsed = this.tryParse(raw);
if (parsed && typeof parsed === 'object' && 'success' in parsed) {
return parsed as INativeBridgeResult;
}
return { success: true, data: parsed ?? raw };
} catch (error) {
return { success: false, error: (error as Error).message };
}
}
print(request: INativePrintRequest): INativeBridgeResult {
return this.invoke('print', request);
return this.invokePrint(request);
}
private invoke(method: 'pay' | 'print', payload: object): INativeBridgeResult {
// if (!this.isEnabled()) {
// return { success: false, error: 'Native bridge is disabled for this tenant.' };
// }
const fn = this.host?.[method];
private invokePrint(payload: object): INativeBridgeResult {
const fn = this.host?.print;
if (typeof fn !== 'function') {
return { success: false, error: `Native method "${method}" is not available.` };
return { success: false, error: 'Native method "print" is not available.' };
}
try {