set sepas favicon and update many things in correction and shared sale invoice
Production CI / validate-and-build (push) Failing after 1m2s

This commit is contained in:
2026-06-17 08:48:34 +03:30
parent ea458c7b72
commit b57d6b4e4b
31 changed files with 209 additions and 127 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 19 KiB

@@ -8,13 +8,13 @@ import {
@Injectable({ providedIn: 'root' })
export class PosConfigSendToFiscalActivationService {
get(): IPosConfigSendToFiscalActivationResponse {
const defaultPrice = Boolean(
const sendToFiscalActivation = Boolean(
window.localStorage.getItem(LOCAL_STORAGE_KEYS.POS_CONFIG_SEND_TO_FISCAL_ACTIVATION) ===
'true'
);
this.submit(defaultPrice);
return defaultPrice;
this.submit(sendToFiscalActivation);
return sendToFiscalActivation;
}
submit(data: IPosConfigSendToFiscalActivationPayload) {
@@ -1,10 +1,3 @@
import { IPosOrderItem } from '../../shop/models';
import { ICorrectionRequest } from '@/shared/components/invoices/models';
export interface IPosCorrectionRequest {
total_amount: number;
discount_amount: number;
tax_amount: number;
invoice_date: string;
items: IPosOrderItem[];
notes?: string;
}
export interface IPosCorrectionRequest extends ICorrectionRequest {}
@@ -1,10 +1,9 @@
import { IPosOrderItem } from '../../shop/models';
export interface IPosReturnFromSaleRequest {
total_amount: number;
discount_amount: number;
tax_amount: number;
invoice_date: string;
items: IPosOrderItem[];
notes?: string;
items: IPosReturnFromSaleItem[];
}
export interface IPosReturnFromSaleItem {
good_id: string;
quantity: number;
}
@@ -13,6 +13,7 @@ import {
IPosSaleInvoicesSummaryRawResponse,
IPosSaleInvoicesSummaryResponse,
} from '../models';
import { IPosReturnFromSaleRequest } from '../models/returnFromSale';
@Injectable({ providedIn: 'root' })
export class PosSaleInvoicesService {
@@ -65,7 +66,10 @@ export class PosSaleInvoicesService {
);
}
returnFromSale(data: any, invoiceId: string): Observable<IPosSaleInvoiceFiscalActionResponse> {
returnFromSale(
data: IPosReturnFromSaleRequest,
invoiceId: string
): Observable<IPosSaleInvoiceFiscalActionResponse> {
return this.http.post<IPosSaleInvoiceFiscalActionResponse>(
this.apiRoutes.tsp.returnFromSale(invoiceId),
data
@@ -44,11 +44,14 @@ export class PosService {
getGoodCategories(): Observable<IListingResponse<IGoodCategoryResponse>> {
return this.http.get<IListingResponse<IGoodCategoryRawResponse>>(
this.apiRoutes.goodCategories(),
this.apiRoutes.goodCategories()
);
}
submitOrder(payload: IPosOrderRequest): Observable<IPosOrderResponse> {
return this.http.post<IPosOrderRawResponse>(this.apiRoutes.submitOrder(), payload);
submitOrder(payload: IPosOrderRequest, send_to_tsp: boolean): Observable<IPosOrderResponse> {
return this.http.post<IPosOrderRawResponse>(this.apiRoutes.submitOrder(), {
...payload,
send_to_tsp,
});
}
}
@@ -11,6 +11,7 @@ import {
} from '@/utils';
import { computed, inject, Injectable, signal } from '@angular/core';
import { catchError, finalize, firstValueFrom, map, throwError } from 'rxjs';
import { PosConfigSendToFiscalActivationService } from '../../configs/components/sendToFiscalActivation/services/main.service';
import { ICustomer, IPayment, IPosOrderRequest, IPosOrderResponse } from '../models';
import { IPosInOrderGood, IPosOrderItem } from '../models/types';
import { PosService } from '../services/main.service';
@@ -64,6 +65,9 @@ export const INITIAL_POS_STATE: IPosLandingState = {
@Injectable({ providedIn: 'any' })
export class PosLandingStore {
private readonly service = inject(PosService);
private readonly posConfigSendToFiscalActivationService = inject(
PosConfigSendToFiscalActivationService
);
private state$ = signal<IPosLandingState>({ ...INITIAL_POS_STATE });
@@ -295,7 +299,9 @@ export class PosLandingStore {
let res: Maybe<IPosOrderResponse> = null;
return this.service.submitOrder(orderPayload).pipe(
return this.service
.submitOrder(orderPayload, this.posConfigSendToFiscalActivationService.get())
.pipe(
finalize(() => {
this.setState({ submitOrderLoading: false });
}),
@@ -17,6 +17,8 @@ export class CatalogInvoiceTypeTagComponent {
return 'success';
case 'CORRECTION':
return 'warn';
case 'RETURN':
return 'warn';
case 'REVOKE':
return 'danger';
}
@@ -28,6 +30,8 @@ export class CatalogInvoiceTypeTagComponent {
return 'اصلی';
case 'CORRECTION':
return 'اصلاحی';
case 'RETURN':
return 'برگشت از فروش';
case 'REVOKE':
return 'ابطالی';
}
@@ -1,6 +1,7 @@
export const InvoiceTypes = {
ORIGINAL: 'ORIGINAL',
CORRECTION: 'CORRECTION',
RETURN: 'RETURN',
REVOKE: 'REVOKE',
} as const;
@@ -43,7 +43,7 @@
<pos-order-price-info-card [info]="totalPriceInfo" />
<app-form-footer-actions [loading]="submitLoading()" />
<app-form-footer-actions [loading]="submitLoading()" (onCancel)="close()" />
</form>
<shared-light-bottomsheet
+2 -1
View File
@@ -1,4 +1,4 @@
import { IPosOrderItem } from '@/domains/pos/modules/shop/models';
import { IPayment, IPosOrderItem } from '@/domains/pos/modules/shop/models';
import { IGoldPayload, IStandardPayload } from '@/shared/models';
export type TCorrectionItemPayload = IPosOrderItem<IGoldPayload | IStandardPayload> & {
@@ -18,4 +18,5 @@ export interface ICorrectionRequest {
invoice_date: string;
items: IPosOrderItem[];
notes?: string;
payments?: IPayment;
}
@@ -25,8 +25,6 @@
</div>
}
amount:{{ payByTerminalSteps()[0]?.amount || '' }} - terminalId:
{{ payByTerminalSteps()[0]?.info?.terminal_id || '' }}- payed:{{ payByTerminalSteps()[0]?.payed || '' }}
<uikit-field label="تعداد مراحل پرداخت با پوز" name="pay_by_terminal_steps">
<p-select
[options]="payByTerminalSteps()"
@@ -22,5 +22,5 @@
<pos-order-price-info-card [info]="totalPriceInfo" />
<app-form-footer-actions />
<app-form-footer-actions (onCancel)="close()" />
</form>
@@ -42,6 +42,7 @@ export class SharedReturnFormComponent extends AbstractForm<
IInvoiceItem[]
> {
@Input({ required: true }) invoiceDate!: string;
@Input({ required: true }) loading!: boolean;
form = this.fb.group({
invoice_date: [this.invoiceDate],
@@ -164,7 +165,9 @@ export class SharedReturnFormComponent extends AbstractForm<
const initialMap = new Map(
(this.initialValues || []).map((item) => [String(item.id), Number(item.quantity || 0)])
);
const hasChanges = payload.some((item) => item.quantity !== Number(initialMap.get(item.id) || 0));
const hasChanges = payload.some(
(item) => item.quantity !== Number(initialMap.get(item.id) || 0)
);
if (!hasChanges) {
this.toastService.warn({
@@ -23,8 +23,8 @@ export interface ISaleInvoiceFullRawResponse {
status: IEnumTranslate<TspProviderResponseStatus>;
main_id: Maybe<string>;
tax_id: Maybe<string>;
reference_invoice: Maybe<string>;
refrence_by: Maybe<string>;
reference_invoice: Maybe<ReferenceInvoice>;
referenced_by: Maybe<ReferenceInvoice>;
notes: Maybe<string>;
settlement_type: IEnumTranslate<InvoiceSettlementType>;
}
@@ -48,6 +48,11 @@ export interface IInvoiceItem {
good: GoodSummary;
tax_amount: string;
}
interface ReferenceInvoice {
id: string;
invoice_number: number;
}
interface GoodSummary {
name: string;
barcode?: string;
@@ -1,6 +1,25 @@
@if (invoice) {
<p-card>
<div class="flex flex-col gap-4">
@if (invoice.referenced_by) {
<p-message severity="warn" [closable]="false">
این صورت‌حساب، مرجع صورت‌حساب شماره‌ی
<a [href]="referenceByInvoiceRoute()" class="text-lg font-bold">
{{ invoice.referenced_by.invoice_number }}
</a>
می‌باشد.
</p-message>
}
@if (invoice.reference_invoice) {
<p-message severity="info" [closable]="false">
صورت‌حساب مرجع به شماره‌ی
<a [href]="referenceInvoiceRoute()" class="text-lg font-bold">
{{ invoice.reference_invoice.invoice_number }}
</a>
می‌باشد.
</p-message>
}
<div class="listKeyValue">
<app-key-value label="شماره منحصر به فرد مالیاتی" [value]="invoice.tax_id" />
<app-key-value label="تاریخ صورت‌حساب‌" [value]="invoice.invoice_date" type="date" />
@@ -41,7 +60,7 @@
<app-key-value label="کسب و کار" [value]="invoice.pos!.complex.business_activity.name" />
<app-key-value label="مجموعه" [value]="invoice.pos!.complex.name" />
<app-key-value label="پایانه فروش" [value]="invoice.pos!.name" />
@if (invoice.consumer_account?.account?.username) {
@if (invoice.consumer_account.account.username) {
<app-key-value label="ایجاد کننده" [value]="invoice.consumer_account.account.username" />
}
</div>
@@ -5,9 +5,11 @@ import {
} from '@/shared/catalog';
import { CatalogInvoiceSettlementTypeTagComponent } from '@/shared/catalog/invoiceSettlementType';
import { PriceMaskDirective } from '@/shared/directives';
import { Component, Input } from '@angular/core';
import { Component, computed, inject, Input } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Card } from 'primeng/card';
import { Divider } from 'primeng/divider';
import { Message } from 'primeng/message';
import { KeyValueComponent } from '../key-value.component/key-value.component';
import { IColumn, PageDataListComponent } from '../pageDataList/page-data-list.component';
import { ISaleInvoiceFullResponse } from './sale-invoice-full-response.model';
@@ -26,6 +28,7 @@ export type TSaleInvoiceSingleViewVariant = 'full' | 'customer' | 'pos';
CatalogInvoiceSettlementTypeTagComponent,
PageDataListComponent,
PriceMaskDirective,
Message,
],
})
export class SaleInvoiceSingleInfoCardComponent {
@@ -33,6 +36,8 @@ export class SaleInvoiceSingleInfoCardComponent {
@Input() invoice!: Maybe<ISaleInvoiceFullResponse>;
@Input() variant: TSaleInvoiceSingleViewVariant = 'full';
private readonly route = inject(ActivatedRoute);
columns: IColumn[] = [
{
field: 'name',
@@ -101,4 +106,35 @@ export class SaleInvoiceSingleInfoCardComponent {
type: 'price',
},
];
referenceInvoiceRoute = computed(() => {
const referenceInvoiceId = this.invoice?.reference_invoice?.id;
const pagePath = this.route.pathFromRoot
.flatMap((route) => route.snapshot.url.map((segment) => segment.path))
.join('/');
if (!pagePath || !referenceInvoiceId) {
return pagePath;
}
const pathParts = pagePath.split('/').filter(Boolean);
pathParts[pathParts.length - 1] = referenceInvoiceId;
return `/${pathParts.join('/')}`;
});
referenceByInvoiceRoute = computed(() => {
const referenceInvoiceId = this.invoice?.referenced_by?.id;
const pagePath = this.route.pathFromRoot
.flatMap((route) => route.snapshot.url.map((segment) => segment.path))
.join('/');
if (!pagePath || !referenceInvoiceId) {
return pagePath;
}
const pathParts = pagePath.split('/').filter(Boolean);
pathParts[pathParts.length - 1] = referenceInvoiceId;
return `/${pathParts.join('/')}`;
});
}
@@ -7,7 +7,7 @@
<ng-template #actions>
<p-button (click)="showQrCode()" icon="pi pi-qrcode" outlined size="small" />
<p-button (click)="printInvoice()" icon="pi pi-print" outlined size="small" label="چاپ" />
@if (!isApplication) {
@if (!isApplication && canDoActionOnInvoice()) {
<p-button (click)="menu.toggle($event)" icon="pi pi-ellipsis-v" label="عملیات بیشتر" outlined size="small">
</p-button>
<p-menu #menu [model]="moreActionMenuItems()" [popup]="true"></p-menu>
@@ -18,7 +18,7 @@
<shared-sale-invoice-single-info-card [loading]="loading" [invoice]="invoice" [variant]="variant" />
</div>
@if (isApplication && moreActionMenuItems().length) {
@if (isApplication && moreActionMenuItems().length && canDoActionOnInvoice()) {
<div class="border-surface-border bg-surface-card sticky bottom-0 z-10 mt-4 w-full rounded-t-2xl border-t p-3">
<div class="flex flex-wrap justify-center gap-2">
@for (action of moreActionMenuItems(); track action.label || $index) {
@@ -35,11 +35,14 @@
</div>
}
@if (canDoActionOnInvoice()) {
<shared-light-bottomsheet [(visible)]="showReturnFromSaleForm" header=" برگشت از فروش">
<shared-return-form
[initialValues]="invoice.items"
[invoiceDate]="invoice.invoice_date"
(onSubmit)="returnSubmit($event)" />
[loading]="returnFromSaleLoading || false"
(onSubmit)="returnSubmit($event)"
(onClose)="cancelReturn()" />
</shared-light-bottomsheet>
<shared-light-bottomsheet [(visible)]="showCorrectionForm" header="اصلاحی">
<shared-correction-form
@@ -47,8 +50,22 @@
[initialValues]="invoice.items"
[invoiceDate]="invoice.invoice_date"
[beforeSubmit]="beforeCorrectionSubmitHandler.bind(this)"
(onSubmit)="correctionSubmit($event)" />
(onSubmit)="correctionSubmit($event)"
(onClose)="cancelCorrection()" />
</shared-light-bottomsheet>
@if (showCorrectionPaymentDialog()) {
<shared-invoice-payment-form-dialog
[(visible)]="showCorrectionPaymentDialog"
[totalAmount]="correctionRequiredPayment()"
[submitOrderLoading]="correctionLoading"
[isGoldGuild]="false"
[isUnknownCustomer]="true"
(onSubmitPayment)="confirmCorrectionPayment($event)"
(onClose)="cancelCorrectionPayment()" />
}
}
}
<shared-light-bottomsheet [(visible)]="showQrCodeDialog" header="کد QR">
<div class="flex flex-col gap-4">
<span class="text-center text-lg font-bold">
@@ -59,15 +76,3 @@
</p-card>
</div>
</shared-light-bottomsheet>
@if (showCorrectionPaymentDialog()) {
<shared-invoice-payment-form-dialog
[(visible)]="showCorrectionPaymentDialog"
[totalAmount]="correctionRequiredPayment()"
[submitOrderLoading]="false"
[isGoldGuild]="false"
[isUnknownCustomer]="true"
(onSubmitPayment)="confirmCorrectionPayment($event)"
(onClose)="cancelCorrectionPayment()" />
}
}
@@ -3,8 +3,11 @@ import { NativeBridgeService } from '@/core/services';
import { NavigationService } from '@/core/services/navigation.service';
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 { IPayment, IPosOrderItem } from '@/domains/pos/modules/shop/models';
import {
IPosReturnFromSaleItem,
IPosReturnFromSaleRequest,
} from '@/domains/pos/modules/saleInvoices/models/returnFromSale';
import { IPayment } from '@/domains/pos/modules/shop/models';
import { PosInfoStore } from '@/domains/pos/store';
import { TspProviderResponseStatus } from '@/shared/catalog';
import { SharedLightBottomsheetComponent } from '@/shared/components';
@@ -88,6 +91,8 @@ export class SharedSaleInvoiceSingleViewComponent {
@Input() sendToTspLoading: boolean = false;
@Input() resendToTspLoading: boolean = false;
@Input() inquiryLoading: boolean = false;
@Input() correctionLoading: boolean = false;
@Input() returnFromSaleLoading: boolean = false;
@Input() beforeCorrectionSubmit?: (data: ICorrectionRequest) => Promise<boolean> | boolean;
@Output() onRefresh = new EventEmitter<void>();
@@ -115,6 +120,10 @@ export class SharedSaleInvoiceSingleViewComponent {
return '';
});
canDoActionOnInvoice = computed(() => {
return !this.invoice?.referenced_by;
});
showErrors = () => {};
inquiry = () => {
this.onInquiry.emit();
@@ -319,45 +328,35 @@ export class SharedSaleInvoiceSingleViewComponent {
this.pendingCorrectionSubmitResolver = null;
}
cancelCorrection() {
this.showCorrectionForm.set(false);
this.cancelCorrectionPayment();
}
cancelReturn() {
this.showReturnFromSaleForm.set(false);
}
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 || [])
const items: IPosReturnFromSaleItem[] = (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_amount || 0);
const base_total_amount = unit_price * quantity;
const total_amount = Number(source.total_amount || 0);
const tax_amount = Number(source.tax_amount || 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);
.filter((item): item is IPosReturnFromSaleItem => !!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),
};
}
+3
View File
@@ -16,3 +16,6 @@
@apply w-full;
}
}
.p-component.p-overlay.ng-star-inserted {
max-width: 100%;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

+7 -7
View File
@@ -9,13 +9,13 @@ body {
line-height: 1.2;
}
html.application-pos,
body.application-pos {
width: 100%;
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
// html.application-pos,
// body.application-pos {
// width: 100%;
// max-width: 600px;
// margin-left: auto;
// margin-right: auto;
// }
body.application-pos {
overflow-x: hidden;
+2 -2
View File
@@ -1,10 +1,10 @@
// TIS tenant environment configuration
export const environment = {
production: true,
apiBaseUrl: 'https://psp-api.shift-am.ir',
// apiBaseUrl: 'https://psp-api.shift-am.ir',
// apiBaseUrl: 'http://192.168.128.73:5002',
// apiBaseUrl: 'http://192.168.0.162:5002',
// apiBaseUrl: 'http://localhost:5002',
apiBaseUrl: 'http://localhost:5002',
host: 'localhost',
port: 5000,
enableLogging: false,
+4 -1
View File
@@ -15,7 +15,10 @@ export const appRoutes: Routes = [
CONSUMER_ROUTES,
PROVIDER_ROUTES,
PARTNER_ROUTES,
...POS_ROUTES.children!,
{
path: 'pos',
children: [...POS_ROUTES.children!],
},
],
},