feat: implement payment result handling; refactor payment components and enhance terminal payment logic

This commit is contained in:
2026-05-17 15:21:06 +03:30
parent 6f1ad20cff
commit 78501b907b
13 changed files with 268 additions and 138 deletions
@@ -1,40 +1,41 @@
<div class="w-full min-h-[60svh] p-4 md:p-6">
<section class="mx-auto max-w-3xl overflow-hidden rounded-2xl border border-surface-200 bg-white">
<div class="bg-gradient-to-l from-emerald-50 via-teal-50 to-cyan-50 p-5 md:p-7">
<p class="mb-2 inline-flex items-center rounded-full bg-white px-3 py-1 text-xs font-semibold text-emerald-700">
{{ brandingInfo.title }}
</p>
<span class="block mb-4 text-xl font-bold text-surface-900 md:text-3xl">{{ brandingInfo.fullTitle }}</span>
<p class="mt-3 max-w-2xl text-sm leading-7 text-surface-700 md:text-base">
این نسخه برای استفاده روزانه روی دستگاه های PSP بهینه شده است تا عملیات ثبت و صدور صورتحساب‌‌های مالیاتی با سرعت
بالاتر، پایداری بیشتر و تجربه کاربری ساده تر انجام شود.
</p>
</div>
@defer {
<div class="w-full min-h-[60svh] p-4 md:p-6">
<section class="mx-auto max-w-3xl overflow-hidden rounded-2xl border border-surface-200 bg-white">
<div class="bg-gradient-to-l from-emerald-50 via-teal-50 to-cyan-50 p-5 md:p-7">
<p class="mb-2 inline-flex items-center rounded-full bg-white px-3 py-1 text-xs font-semibold text-emerald-700">
{{ brandingInfo.title }}
</p>
<span class="block mb-4 text-xl font-bold text-surface-900 md:text-3xl">{{ brandingInfo.fullTitle }}</span>
<p class="mt-3 max-w-2xl text-sm leading-7 text-surface-700 md:text-base">
این نسخه برای استفاده روزانه روی دستگاه های PSP بهینه شده است تا عملیات ثبت و صدور صورتحساب‌‌های مالیاتی با
سرعت بالاتر، پایداری بیشتر و تجربه کاربری ساده تر انجام شود.
</p>
</div>
<div class="grid gap-3 p-4 md:grid-cols-3 md:gap-4 md:p-6">
<!-- <article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
<div class="grid gap-3 p-4 md:grid-cols-3 md:gap-4 md:p-6">
<!-- <article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
<h2 class="mb-2 text-sm font-bold text-surface-900">پایداری در وب ویو</h2>
<p class="text-sm leading-6 text-surface-700">
رفتار رابط کاربری برای محیط WebView تنظیم شده تا روی سخت افزارهای ضعیف تر هم اجرای روان تری داشته باشد.
</p>
</article> -->
<article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
<span class="block mb-4 text-xl font-bold text-surface-900">تمرکز بر سرعت عملیات</span>
<p class="text-sm leading-6 text-surface-700">
مسیرهای کلیدی مانند انتخاب کالا، ورود مقادیر و ثبت نهایی برای کاهش تاخیر و افزایش سرعت کاربر بهینه شده اند.
</p>
</article>
<article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
<span class="block mb-4 text-xl font-bold text-surface-900">تمرکز بر سرعت عملیات</span>
<p class="text-sm leading-6 text-surface-700">
مسیرهای کلیدی مانند انتخاب کالا، ورود مقادیر و ثبت نهایی برای کاهش تاخیر و افزایش سرعت کاربر بهینه شده اند.
</p>
</article>
<article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
<span class="block mb-4 text-xl font-bold text-surface-900">سازگار با سناریوهای فروش</span>
<p class="text-sm leading-6 text-surface-700">
طراحی این نسخه بر مبنای سناریوهای واقعی فروشگاه انجام شده تا اپراتور با کمترین کلیک فرآیند را تکمیل کند.
</p>
</article>
</div>
<article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
<span class="block mb-4 text-xl font-bold text-surface-900">سازگار با سناریوهای فروش</span>
<p class="text-sm leading-6 text-surface-700">
طراحی این نسخه بر مبنای سناریوهای واقعی فروشگاه انجام شده تا اپراتور با کمترین کلیک فرآیند را تکمیل کند.
</p>
</article>
</div>
<!-- <div class="mx-4 mb-4 rounded-xl border border-surface-200 bg-surface-50 p-4 md:mx-6">
<!-- <div class="mx-4 mb-4 rounded-xl border border-surface-200 bg-surface-50 p-4 md:mx-6">
<div class="flex flex-wrap items-center justify-between gap-3">
<div class="text-sm text-surface-700">
نسخه برنامه:
@@ -52,10 +53,11 @@
</div>
</div> -->
<div class="border-t border-surface-200 bg-surface-50 px-4 py-4 md:px-6">
<p class="text-xs leading-6 text-surface-600 md:text-sm">
در صورت نیاز به راهنمایی بیشتر، به صفحه‌ی راهنمای استفاده مراجعه کنید یا با پشتیبانی تماس بگیرید.
</p>
</div>
</section>
</div>
<div class="border-t border-surface-200 bg-surface-50 px-4 py-4 md:px-6">
<p class="text-xs leading-6 text-surface-600 md:text-sm">
در صورت نیاز به راهنمایی بیشتر، به صفحه‌ی راهنمای استفاده مراجعه کنید یا با پشتیبانی تماس بگیرید.
</p>
</div>
</section>
</div>
}
@@ -45,7 +45,6 @@ export class PosConfigPrintFormComponent extends AbstractForm<
override async ngOnInit() {
this.loading.set(true);
const initialValues = await this.service.get();
console.log('initialValues', initialValues);
this.form.patchValue(initialValues);
this.loading.set(false);
@@ -16,7 +16,7 @@
<div class="form-group">
<uikit-field label="تعداد مراحل پرداخت با پایانه" name="pay_by_terminal_steps">
<p-select
[options]="payByTerminalSteps"
[options]="payByTerminalSteps()"
[ngModel]="selectedPayByTerminalStep()"
[ngModelOptions]="{ standalone: true }"
optionLabel="label"
@@ -33,13 +33,14 @@
[label]="$index === 0 ? 'پرداخت با پایانه' : 'پرداخت با پایانه - مرحله ' + ($index + 1)"
type="price"
[max]="terminalsMax()[$index]"
[disabled]="payByTerminalSteps()[$index].payed"
>
<ng-template #suffixTemp>
<button
pButton
size="small"
type="button"
[disabled]="!remainedAmount()"
[disabled]="!remainedAmount() || payByTerminalSteps()[$index].payed"
(click)="fillTerminalRemained($index)"
>
تمامی بدهی باقی‌مانده
@@ -12,7 +12,13 @@ import { FormControl, FormsModule, ReactiveFormsModule, Validators } from '@angu
import { ButtonDirective } from 'primeng/button';
import { Select } from 'primeng/select';
import { catchError, throwError } from 'rxjs';
import { IPayment, IPosOrderResponse, TOrderPaymentTypes } from '../../models';
import {
IPayment,
IPosOrderResponse,
PosPaymentResult,
TerminalSuccessPaymentPayload,
TOrderPaymentTypes,
} from '../../models';
import { PosPaymentBridgeAbstract } from '../../services/payment-bridge.abstract';
import { PosPaymentBridgeService } from '../../services/payment-bridge.service';
import { PosLandingStore } from '../../store/main.store';
@@ -48,25 +54,57 @@ export class PosPaymentFormDialogComponent extends AbstractFormDialog<IPayment,
submitOrderLoading = computed(() => this.store.submitOrderLoading());
payByTerminalSteps = Array.from({ length: 10 }, (_, i) => ({
value: i + 1,
label: `${i + 1} مرحله‌ای`,
}));
payByTerminalSteps = signal(
Array.from({ length: 10 }, (_, i) => ({
value: i + 1,
payed: false,
info: {} as TerminalSuccessPaymentPayload,
label: `${i + 1} مرحله‌ای`,
amount: 0,
})),
);
selectedPayByTerminalStep = signal(1);
payedInTerminal = signal<Array<number>>([]);
private restorePaymentCallback: Maybe<() => void> = null;
private readonly injectedPaymentResultHandler = (payload: unknown) => {
alert('پرداخت با موفقیت انجام شد');
this.toastServices.success({ text: 'شد شد شد شد شد' });
// this.handlePaymentResult(payload);
private readonly injectedPaymentResultHandler = (payload: PosPaymentResult) => {
if (payload.status === 'SUCCESS') {
const paidStepId = Number(payload.id || 0);
this.payByTerminalSteps.update((prev) =>
prev.map((step, index) => {
if (step.value === paidStepId) {
return {
...step,
payed: true,
amount: this.terminalControls[step.value - 1]?.value || 0,
info: {
customer_card_no: payload.data?.customerCardNO || '',
description: payload.message || '',
rrn: payload.data?.rrn || '',
stan: payload.data?.stan || '',
terminal_id: payload.data?.terminalId || '',
transaction_date_time: new Date(payload.data?.transactionDateTime || ''),
},
};
}
return step;
}),
);
const terminalControl = this.terminalControls[paidStepId - 1];
if (terminalControl) {
terminalControl.disable({ onlySelf: true, emitEvent: false });
}
const amount = Number(
terminalControl?.value || this.extractAmountFromPaymentResult(payload) || 0,
);
this.toastServices.success({ text: `پرداخت با موفقیت انجام شد. مبلغ: ${amount}` });
} else {
this.toastServices.error({ text: payload.message || 'پرداخت با دستگاه انجام نشد.' });
}
};
ngAfterViewInit() {
console.log('ngOnViewInit');
this.restorePaymentCallback = this.paymentBridge.registerPaymentResultListener(
this.injectedPaymentResultHandler,
);
@@ -118,7 +156,11 @@ export class PosPaymentFormDialogComponent extends AbstractFormDialog<IPayment,
this.terminalsMax.update((max) => {
const terminalMax = remainedAmount + (terminal.value || 0);
terminal.addValidators([Validators.max(terminalMax)]);
if (terminalMax) {
if (this.isTerminalStepPaid(i + 1)) {
terminal.disable({
onlySelf: true,
});
} else if (terminalMax) {
terminal.enable({
onlySelf: true,
});
@@ -145,7 +187,13 @@ export class PosPaymentFormDialogComponent extends AbstractFormDialog<IPayment,
}
changePayByTerminalSteps(steps: number) {
const normalizedSteps = Math.max(1, Number(steps) || 1);
const minSteps = this.getMinAllowedSteps();
const normalizedSteps = Math.max(minSteps, Number(steps) || 1);
if ((Number(steps) || 1) < minSteps) {
this.toastServices.warn({
text: `حداقل تعداد مراحل به دلیل پرداخت های انجام شده ${minSteps} است.`,
});
}
this.selectedPayByTerminalStep.set(normalizedSteps);
const terminals = this.form.controls.terminals;
@@ -219,10 +267,24 @@ export class PosPaymentFormDialogComponent extends AbstractFormDialog<IPayment,
}
const rawPayment = this.form.getRawValue();
const terminalPayments = this.payByTerminalSteps()
.slice(0, this.selectedPayByTerminalStep())
.filter((step) => step.payed)
.map((step) => ({
amount: Number(this.terminalControls[step.value - 1]?.value || step.amount || 0),
terminal_id: step.info.terminal_id || '',
stan: step.info.stan || '',
rrn: step.info.rrn || '',
response_code: '00',
customer_card_no: step.info.customer_card_no || '',
transaction_date_time: step.info.transaction_date_time || new Date(),
description: step.info.description || '',
}));
const payment: IPayment = {
cash: Number(rawPayment.cash || 0),
set_off: Number(rawPayment.set_off || 0),
terminals: (rawPayment.terminals || []).map((value) => Number(value || 0)),
terminals: terminalPayments,
};
this.store.setPayment(payment);
@@ -230,6 +292,9 @@ export class PosPaymentFormDialogComponent extends AbstractFormDialog<IPayment,
const terminalPaymentIsDone = this.checkTerminalPayments();
if (terminalPaymentIsDone) {
this.toastService.info({
text: `terminalPayments[0].customer_card_no: ${payment.terminals[0]?.customer_card_no || ''}`,
});
this.store
.submitOrder()
.pipe(
@@ -245,23 +310,15 @@ export class PosPaymentFormDialogComponent extends AbstractFormDialog<IPayment,
}
private checkTerminalPayments(): boolean {
this.form.controls.terminals.controls = this.form.controls.terminals.controls.filter(
(control) => control.value,
);
const terminalPayments = this.form.controls.terminals.controls.map(
(terminal) => terminal.value!,
);
this.selectedPayByTerminalStep.set(terminalPayments.length || 1);
if (terminalPayments.length) {
const pendingTerminalPayments = this.getPendingTerminalPayments();
if (pendingTerminalPayments.length) {
if (this.nativeBridgeService.isEnabled()) {
for (let i in terminalPayments) {
const terminal = terminalPayments[i];
this.toastServices.info({ text: 'در حال پردازش پرداخت با دستگاه...', life: 3000 });
this.payByTerminal(parseInt(i), terminal);
break;
}
const nextPending = pendingTerminalPayments[0];
this.payByTerminal(nextPending.stepId, nextPending.amount);
this.toastServices.info({
text: 'پس از تایید پرداخت هر مرحله، برای مرحله بعد دوباره روی ثبت پرداخت بزنید.',
life: 3500,
});
} else {
this.toastServices.error({
text: 'امکان ارتباط با دستگاه پرداخت میسر نیست.',
@@ -278,7 +335,7 @@ export class PosPaymentFormDialogComponent extends AbstractFormDialog<IPayment,
private payByTerminal(id: number, amount: number) {
const payResult = this.nativeBridgeService.pay({
amount,
id: id.toString(),
id: String(id),
});
// if (!payResult.success) {
@@ -288,6 +345,27 @@ export class PosPaymentFormDialogComponent extends AbstractFormDialog<IPayment,
// }
}
private isTerminalStepPaid(stepId: number): boolean {
return this.payByTerminalSteps().some((step) => step.value === stepId && step.payed);
}
private getMinAllowedSteps() {
const paidSteps = this.payByTerminalSteps()
.slice(0, this.selectedPayByTerminalStep())
.filter((step) => step.payed)
.map((step) => step.value);
return paidSteps.length ? Math.max(...paidSteps) : 1;
}
private getPendingTerminalPayments() {
return this.terminalControls
.map((control, index) => ({
stepId: index + 1,
amount: Number(control.value || 0),
}))
.filter(({ stepId, amount }) => amount > 0 && !this.isTerminalStepPaid(stepId));
}
override onSuccess(response: IPosOrderResponse): void {}
private extractAmountFromPaymentResult(payload: unknown): number | null {
@@ -2,4 +2,5 @@ export * from './customer';
export * from './io';
export * from './payload';
export * from './payment';
export * from './posPaymentResult';
export * from './types';
@@ -1,5 +1,5 @@
export interface IPayment {
terminals: number[];
terminals: IPaymentTerminal[];
cash: number;
set_off: number;
}
@@ -0,0 +1,22 @@
export interface PosPaymentResult {
id?: string;
status: 'SUCCESS' | 'FAILURE';
message?: string;
data?: {
terminalId: string;
stan: string;
rrn: string;
responseCode: string;
customerCardNO: string;
transactionDateTime: string;
};
}
export interface TerminalSuccessPaymentPayload {
terminal_id: string;
stan: string;
rrn: string;
transaction_date_time: Date;
customer_card_no: string;
description: string;
}
@@ -1,4 +1,6 @@
import { PosPaymentResult } from '../models';
export abstract class PosPaymentBridgeAbstract {
abstract registerPaymentResultListener(handler: (payload: unknown) => void): () => void;
abstract registerPaymentResultListener(handler: (payload: PosPaymentResult) => void): () => void;
abstract emitPaymentResultForTest(payload: unknown): void;
}
@@ -1,33 +1,51 @@
import { ToastService } from '@/core/services/toast.service';
import { inject, Injectable } from '@angular/core';
import { PosPaymentResult } from '../models';
import { PosPaymentBridgeAbstract } from './payment-bridge.abstract';
@Injectable({ providedIn: 'root' })
export class PosPaymentBridgeService extends PosPaymentBridgeAbstract {
private readonly toastServices = inject(ToastService);
registerPaymentResultListener(handler: (payload: unknown) => void): () => void {
// const w = window as unknown as {
// WebV?: {
// onPaymentResult?: (payload: unknown) => void;
// AndroidBridge?: {
// onPaymentResult?: (payload: unknown) => void;
// };
// };
// };
this.toastServices.error({ text: '@@@@@@@@@@@@@' });
registerPaymentResultListener(handler: (payload: PosPaymentResult) => void): () => void {
// @ts-ignore
window.WebV = {
onPaymentResult: () => {
this.toastServices.error({ text: 'asdasdsadassadasdas' });
onPaymentResult: (payload: PosPaymentResult) => {
try {
// const parsedPayload: PosPaymentResult = JSON.parse(payload);
// this.toastServices.info({ text: payload.data?.customerCardNO || '', life: 10000 });
// this.toastServices.info({
// text: payload.data?.responseCode || 'No response code',
// life: 10000,
// });
// this.toastServices.info({ text: payload.data?.rrn || 'No response code', life: 10000 });
// this.toastServices.info({ text: payload.data?.stan || 'No response code', life: 10000 });
// this.toastServices.info({
// text: payload.data?.terminalId || 'No response code',
// life: 10000,
// });
// this.toastServices.info({
// text: payload.data?.transactionDateTime || 'No response code',
// life: 10000,
// });
handler(payload);
} catch (e) {
this.toastServices.error({ text: 'Failed to parse payment result', life: 10000 });
this.toastServices.error({
text: e instanceof Error ? e.message : String(e),
life: 10000,
});
this.toastServices.error({ text: typeof payload, life: 10000 });
}
},
};
return () => {};
}
emitPaymentResultForTest(payload: unknown): void {
const w = window as unknown as { WebV?: { onPaymentResult?: (payload: unknown) => void } };
emitPaymentResultForTest(payload: PosPaymentResult): void {
const w = window as unknown as {
WebV?: { onPaymentResult?: (payload: PosPaymentResult) => void };
};
w.WebV?.onPaymentResult?.(payload);
}
}
@@ -1,5 +1,6 @@
import { Maybe } from '@/core';
// import { ICustomerResponse } from '@/modules/customers/models';
import { ToastService } from '@/core/services/toast.service';
import { IGoodCategoryResponse, IGoodResponse } from '@/domains/pos/models/good.io';
import { CustomerType } from '@/shared/localEnum/constants/customerTypes';
import { createUUID, JALALI_DATE_FORMATS, nowJalali } from '@/utils';
@@ -55,6 +56,7 @@ export const INITIAL_POS_STATE: IPosLandingState = {
@Injectable({ providedIn: 'any' })
export class PosLandingStore {
private readonly service = inject(PosService);
private readonly toastServices = inject(ToastService);
private state$ = signal<IPosLandingState>({ ...INITIAL_POS_STATE });
@@ -238,6 +240,10 @@ export class PosLandingStore {
total_amount: this.orderPricingInfo().totalAmount,
};
this.toastServices.info({
text: `payment submitted: ${this.payments().terminals[0]?.customer_card_no || ''}`,
});
let res: Maybe<IPosOrderResponse> = null;
return this.service.submitOrder(orderPayload).pipe(
@@ -1,49 +1,51 @@
<div class="w-full min-h-[60svh] p-4 md:p-6">
<section class="mx-auto max-w-3xl overflow-hidden rounded-2xl border border-surface-200 bg-white">
<div class="bg-gradient-to-l from-sky-50 via-cyan-50 to-teal-50 p-5 md:p-7">
<span class="block mb-4 text-xl font-bold text-surface-900 md:text-3xl">پشتیبانی {{ brandingInfo.title }}</span>
<p class="mt-3 max-w-2xl text-sm leading-7 text-surface-700 md:text-base">
در صورت بروز مشکل در ثبت سفارش، صدور صورتحساب یا تنظیمات دستگاه، تیم پشتیبانی آماده پاسخگویی است. لطفا هنگام
تماس، نام پایانه و نام کاربری را همراه داشته باشید.
</p>
</div>
@defer {
<div class="w-full min-h-[60svh] p-4 md:p-6">
<section class="mx-auto max-w-3xl overflow-hidden rounded-2xl border border-surface-200 bg-white">
<div class="bg-gradient-to-l from-sky-50 via-cyan-50 to-teal-50 p-5 md:p-7">
<span class="block mb-4 text-xl font-bold text-surface-900 md:text-3xl">پشتیبانی {{ brandingInfo.title }}</span>
<p class="mt-3 max-w-2xl text-sm leading-7 text-surface-700 md:text-base">
در صورت بروز مشکل در ثبت سفارش، صدور صورتحساب یا تنظیمات دستگاه، تیم پشتیبانی آماده پاسخگویی است. لطفا هنگام
تماس، نام پایانه و نام کاربری را همراه داشته باشید.
</p>
</div>
<div class="grid gap-3 p-4 md:grid-cols-2 md:gap-4 md:p-6">
<article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
<span class="block mb-4 text-xl font-bold text-surface-900">شماره های تماس مستقیم</span>
@if (brandingInfo!.support.phones?.length) {
<ul class="space-y-2 text-sm text-surface-700">
@for (phone of brandingInfo.support.phones!; track $index) {
<li class="flex items-start justify-between gap-2">
<span>{{ phone.title }}</span>
<div class="flex flex-col gap-2">
@for (item of phone.phones; track $index) {
<a class="font-semibold text-primary" href="tel:{{ item }}" dir="ltr">{{ item }}</a>
}
</div>
</li>
}
<div class="grid gap-3 p-4 md:grid-cols-2 md:gap-4 md:p-6">
<article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
<span class="block mb-4 text-xl font-bold text-surface-900">شماره های تماس مستقیم</span>
@if (brandingInfo!.support.phones?.length) {
<ul class="space-y-2 text-sm text-surface-700">
@for (phone of brandingInfo.support.phones!; track $index) {
<li class="flex items-start justify-between gap-2">
<span>{{ phone.title }}</span>
<div class="flex flex-col gap-2">
@for (item of phone.phones; track $index) {
<a class="font-semibold text-primary" href="tel:{{ item }}" dir="ltr">{{ item }}</a>
}
</div>
</li>
}
</ul>
} @else {
<p class="text-sm text-surface-700">در حال حاضر شماره تماس مستقیمی برای پشتیبانی اعلام نشده است.</p>
}
</article>
<article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
<span class="block mb-4 text-xl font-bold text-surface-900">راهنمای سریع قبل از تماس</span>
<ul class="space-y-2 text-sm leading-6 text-surface-700">
<li>اتصال اینترنت دستگاه را بررسی کنید.</li>
<li>یک بار برنامه را ببندید و دوباره اجرا کنید.</li>
<li>در صفحه درباره نرم افزار، نسخه برنامه را اعلام کنید.</li>
<li>در صورت خطا، متن خطا یا تصویر آن را برای پشتیبانی ارسال کنید.</li>
</ul>
} @else {
<p class="text-sm text-surface-700">در حال حاضر شماره تماس مستقیمی برای پشتیبانی اعلام نشده است.</p>
}
</article>
</article>
</div>
<article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
<span class="block mb-4 text-xl font-bold text-surface-900">راهنمای سریع قبل از تماس</span>
<ul class="space-y-2 text-sm leading-6 text-surface-700">
<li>اتصال اینترنت دستگاه را بررسی کنید.</li>
<li>یک بار برنامه را ببندید و دوباره اجرا کنید.</li>
<li>در صفحه درباره نرم افزار، نسخه برنامه را اعلام کنید.</li>
<li>در صورت خطا، متن خطا یا تصویر آن را برای پشتیبانی ارسال کنید.</li>
</ul>
</article>
</div>
<div class="border-t border-surface-200 bg-surface-50 px-4 py-4 md:px-6">
<p class="text-xs leading-6 text-surface-600 md:text-sm">
ساعات پاسخگویی: شنبه تا چهارشنبه 8:30 تا 17:30 و پنجشنبه 8:30 تا 13:00
</p>
</div>
</section>
</div>
<div class="border-t border-surface-200 bg-surface-50 px-4 py-4 md:px-6">
<p class="text-xs leading-6 text-surface-600 md:text-sm">
ساعات پاسخگویی: شنبه تا چهارشنبه 8:30 تا 17:30 و پنجشنبه 8:30 تا 13:00
</p>
</div>
</section>
</div>
}
+2 -2
View File
@@ -1,8 +1,8 @@
// TIS tenant environment configuration
export const environment = {
production: true,
// apiBaseUrl: 'https://psp-api.shift-am.ir',
apiBaseUrl: 'http://192.168.128.73:5002',
apiBaseUrl: 'https://psp-api.shift-am.ir',
// apiBaseUrl: 'http://192.168.128.73:5002',
host: 'localhost',
port: 5000,
enableLogging: false,