diff --git a/public/favicon.ico b/public/favicon.ico index 2c7668f..f1e7fc0 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon/apple-touch-icon.png b/public/favicon/apple-touch-icon.png index 4643ac1..3cf7591 100644 Binary files a/public/favicon/apple-touch-icon.png and b/public/favicon/apple-touch-icon.png differ diff --git a/public/favicon/favicon-96x96.png b/public/favicon/favicon-96x96.png index e7a5c10..d71a799 100644 Binary files a/public/favicon/favicon-96x96.png and b/public/favicon/favicon-96x96.png differ diff --git a/public/favicon/favicon.ico b/public/favicon/favicon.ico index 2c7668f..f1e7fc0 100644 Binary files a/public/favicon/favicon.ico and b/public/favicon/favicon.ico differ diff --git a/public/favicon/favicon.svg b/public/favicon/favicon.svg index 6a2ff69..208dbc1 100644 --- a/public/favicon/favicon.svg +++ b/public/favicon/favicon.svg @@ -1 +1 @@ -RealFaviconGeneratorhttps://realfavicongenerator.net \ No newline at end of file +RealFaviconGeneratorhttps://realfavicongenerator.net \ No newline at end of file diff --git a/public/favicon/web-app-manifest-192x192.png b/public/favicon/web-app-manifest-192x192.png index ad1364f..bc01bc9 100644 Binary files a/public/favicon/web-app-manifest-192x192.png and b/public/favicon/web-app-manifest-192x192.png differ diff --git a/public/favicon/web-app-manifest-512x512.png b/public/favicon/web-app-manifest-512x512.png index c2d28ce..cb02437 100644 Binary files a/public/favicon/web-app-manifest-512x512.png and b/public/favicon/web-app-manifest-512x512.png differ diff --git a/src/app/domains/pos/modules/configs/components/sendToFiscalActivation/services/main.service.ts b/src/app/domains/pos/modules/configs/components/sendToFiscalActivation/services/main.service.ts index b932355..c1a0b85 100644 --- a/src/app/domains/pos/modules/configs/components/sendToFiscalActivation/services/main.service.ts +++ b/src/app/domains/pos/modules/configs/components/sendToFiscalActivation/services/main.service.ts @@ -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) { diff --git a/src/app/domains/pos/modules/saleInvoices/models/correction.ts b/src/app/domains/pos/modules/saleInvoices/models/correction.ts index 0e70634..c807cf2 100644 --- a/src/app/domains/pos/modules/saleInvoices/models/correction.ts +++ b/src/app/domains/pos/modules/saleInvoices/models/correction.ts @@ -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 {} diff --git a/src/app/domains/pos/modules/saleInvoices/models/returnFromSale.ts b/src/app/domains/pos/modules/saleInvoices/models/returnFromSale.ts index 3cff702..52151bc 100644 --- a/src/app/domains/pos/modules/saleInvoices/models/returnFromSale.ts +++ b/src/app/domains/pos/modules/saleInvoices/models/returnFromSale.ts @@ -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; } diff --git a/src/app/domains/pos/modules/saleInvoices/services/main.service.ts b/src/app/domains/pos/modules/saleInvoices/services/main.service.ts index 888b4ed..e0cc1b4 100644 --- a/src/app/domains/pos/modules/saleInvoices/services/main.service.ts +++ b/src/app/domains/pos/modules/saleInvoices/services/main.service.ts @@ -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 { + returnFromSale( + data: IPosReturnFromSaleRequest, + invoiceId: string + ): Observable { return this.http.post( this.apiRoutes.tsp.returnFromSale(invoiceId), data diff --git a/src/app/domains/pos/modules/shop/services/main.service.ts b/src/app/domains/pos/modules/shop/services/main.service.ts index 134ca5e..2eceab5 100644 --- a/src/app/domains/pos/modules/shop/services/main.service.ts +++ b/src/app/domains/pos/modules/shop/services/main.service.ts @@ -44,11 +44,14 @@ export class PosService { getGoodCategories(): Observable> { return this.http.get>( - this.apiRoutes.goodCategories(), + this.apiRoutes.goodCategories() ); } - submitOrder(payload: IPosOrderRequest): Observable { - return this.http.post(this.apiRoutes.submitOrder(), payload); + submitOrder(payload: IPosOrderRequest, send_to_tsp: boolean): Observable { + return this.http.post(this.apiRoutes.submitOrder(), { + ...payload, + send_to_tsp, + }); } } diff --git a/src/app/domains/pos/modules/shop/store/main.store.ts b/src/app/domains/pos/modules/shop/store/main.store.ts index c50a63c..29c9faa 100644 --- a/src/app/domains/pos/modules/shop/store/main.store.ts +++ b/src/app/domains/pos/modules/shop/store/main.store.ts @@ -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({ ...INITIAL_POS_STATE }); @@ -295,31 +299,33 @@ export class PosLandingStore { let res: Maybe = null; - return this.service.submitOrder(orderPayload).pipe( - finalize(() => { - this.setState({ submitOrderLoading: false }); - }), - catchError((error) => throwError(() => error)), + return this.service + .submitOrder(orderPayload, this.posConfigSendToFiscalActivationService.get()) + .pipe( + finalize(() => { + this.setState({ submitOrderLoading: false }); + }), + catchError((error) => throwError(() => error)), - map((_res) => { - if (_res) { - this.setState({ - inOrderGoods: [], - customerDetails: { - type: CustomerType.UNKNOWN, - }, - invoiceDate: _res.invoice_date, - payments: { - cash: 0, - set_off: 0, - terminals: [], - }, - orderNote: '', - }); - } + map((_res) => { + if (_res) { + this.setState({ + inOrderGoods: [], + customerDetails: { + type: CustomerType.UNKNOWN, + }, + invoiceDate: _res.invoice_date, + payments: { + cash: 0, + set_off: 0, + terminals: [], + }, + orderNote: '', + }); + } - return _res; - }) - ); + return _res; + }) + ); } } diff --git a/src/app/shared/catalog/invoiceTypes/invoice-type-tag.component.ts b/src/app/shared/catalog/invoiceTypes/invoice-type-tag.component.ts index 8715e79..b3b3554 100644 --- a/src/app/shared/catalog/invoiceTypes/invoice-type-tag.component.ts +++ b/src/app/shared/catalog/invoiceTypes/invoice-type-tag.component.ts @@ -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 'ابطالی'; } diff --git a/src/app/shared/catalog/invoiceTypes/type.ts b/src/app/shared/catalog/invoiceTypes/type.ts index 801b332..3715371 100644 --- a/src/app/shared/catalog/invoiceTypes/type.ts +++ b/src/app/shared/catalog/invoiceTypes/type.ts @@ -1,6 +1,7 @@ export const InvoiceTypes = { ORIGINAL: 'ORIGINAL', CORRECTION: 'CORRECTION', + RETURN: 'RETURN', REVOKE: 'REVOKE', } as const; diff --git a/src/app/shared/components/invoices/correctionForm/form.component.html b/src/app/shared/components/invoices/correctionForm/form.component.html index 30563b0..8c9984b 100644 --- a/src/app/shared/components/invoices/correctionForm/form.component.html +++ b/src/app/shared/components/invoices/correctionForm/form.component.html @@ -43,7 +43,7 @@ - + & { @@ -18,4 +18,5 @@ export interface ICorrectionRequest { invoice_date: string; items: IPosOrderItem[]; notes?: string; + payments?: IPayment; } diff --git a/src/app/shared/components/invoices/payment/form-dialog.component.html b/src/app/shared/components/invoices/payment/form-dialog.component.html index 5126282..c042437 100644 --- a/src/app/shared/components/invoices/payment/form-dialog.component.html +++ b/src/app/shared/components/invoices/payment/form-dialog.component.html @@ -25,8 +25,6 @@ } - amount:{{ payByTerminalSteps()[0]?.amount || '' }} - terminalId: - {{ payByTerminalSteps()[0]?.info?.terminal_id || '' }}- payed:{{ payByTerminalSteps()[0]?.payed || '' }} - + diff --git a/src/app/shared/components/invoices/returnForm/form.component.ts b/src/app/shared/components/invoices/returnForm/form.component.ts index bb83181..84e2df3 100644 --- a/src/app/shared/components/invoices/returnForm/form.component.ts +++ b/src/app/shared/components/invoices/returnForm/form.component.ts @@ -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({ diff --git a/src/app/shared/components/invoices/sale-invoice-full-response.model.ts b/src/app/shared/components/invoices/sale-invoice-full-response.model.ts index 8d65558..84230b9 100644 --- a/src/app/shared/components/invoices/sale-invoice-full-response.model.ts +++ b/src/app/shared/components/invoices/sale-invoice-full-response.model.ts @@ -23,8 +23,8 @@ export interface ISaleInvoiceFullRawResponse { status: IEnumTranslate; main_id: Maybe; tax_id: Maybe; - reference_invoice: Maybe; - refrence_by: Maybe; + reference_invoice: Maybe; + referenced_by: Maybe; notes: Maybe; settlement_type: IEnumTranslate; } @@ -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; diff --git a/src/app/shared/components/invoices/sale-invoice-single-info-card.component.html b/src/app/shared/components/invoices/sale-invoice-single-info-card.component.html index 8870c50..3dbd6ce 100644 --- a/src/app/shared/components/invoices/sale-invoice-single-info-card.component.html +++ b/src/app/shared/components/invoices/sale-invoice-single-info-card.component.html @@ -1,6 +1,25 @@ @if (invoice) {
+ @if (invoice.referenced_by) { + + این صورت‌حساب، مرجع صورت‌حساب شماره‌ی + + {{ invoice.referenced_by.invoice_number }} + + می‌باشد. + + } + @if (invoice.reference_invoice) { + + صورت‌حساب مرجع به شماره‌ی + + {{ invoice.reference_invoice.invoice_number }} + + می‌باشد. + + } +
@@ -41,7 +60,7 @@ - @if (invoice.consumer_account?.account?.username) { + @if (invoice.consumer_account.account.username) { }
diff --git a/src/app/shared/components/invoices/sale-invoice-single-info-card.component.ts b/src/app/shared/components/invoices/sale-invoice-single-info-card.component.ts index ff6cdeb..dccacd0 100644 --- a/src/app/shared/components/invoices/sale-invoice-single-info-card.component.ts +++ b/src/app/shared/components/invoices/sale-invoice-single-info-card.component.ts @@ -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; @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('/')}`; + }); } diff --git a/src/app/shared/components/invoices/sale-invoice-single-view.component.html b/src/app/shared/components/invoices/sale-invoice-single-view.component.html index 2159363..ac20984 100644 --- a/src/app/shared/components/invoices/sale-invoice-single-view.component.html +++ b/src/app/shared/components/invoices/sale-invoice-single-view.component.html @@ -7,7 +7,7 @@ - @if (!isApplication) { + @if (!isApplication && canDoActionOnInvoice()) { @@ -18,7 +18,7 @@
- @if (isApplication && moreActionMenuItems().length) { + @if (isApplication && moreActionMenuItems().length && canDoActionOnInvoice()) {
@for (action of moreActionMenuItems(); track action.label || $index) { @@ -35,39 +35,44 @@
} - - - - - - - -
- - برای امکان دسترسی به صورت‌حساب به صورت آنلاین، کد QR را اسکن کنید. - - - - -
-
- - @if (showCorrectionPaymentDialog()) { - + @if (canDoActionOnInvoice()) { + + + + + + + @if (showCorrectionPaymentDialog()) { + + } } } + + +
+ + برای امکان دسترسی به صورت‌حساب به صورت آنلاین، کد QR را اسکن کنید. + + + + +
+
diff --git a/src/app/shared/components/invoices/sale-invoice-single-view.component.ts b/src/app/shared/components/invoices/sale-invoice-single-view.component.ts index 6ceec44..ed6ba97 100644 --- a/src/app/shared/components/invoices/sale-invoice-single-view.component.ts +++ b/src/app/shared/components/invoices/sale-invoice-single-view.component.ts @@ -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; @Output() onRefresh = new EventEmitter(); @@ -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), }; } diff --git a/src/assets/customize.scss b/src/assets/customize.scss index 62ba38b..4ccaaf7 100644 --- a/src/assets/customize.scss +++ b/src/assets/customize.scss @@ -16,3 +16,6 @@ @apply w-full; } } +.p-component.p-overlay.ng-star-inserted { + max-width: 100%; +} diff --git a/src/assets/images/favicon.ico b/src/assets/images/favicon.ico new file mode 100644 index 0000000..f1e7fc0 Binary files /dev/null and b/src/assets/images/favicon.ico differ diff --git a/src/assets/images/logo.png b/src/assets/images/logo.png index b038004..2015066 100644 Binary files a/src/assets/images/logo.png and b/src/assets/images/logo.png differ diff --git a/src/assets/layout/_core.scss b/src/assets/layout/_core.scss index f0cd43a..3c2ce94 100644 --- a/src/assets/layout/_core.scss +++ b/src/assets/layout/_core.scss @@ -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; diff --git a/src/environments/environment.tis.ts b/src/environments/environment.tis.ts index 612d694..f1e2553 100644 --- a/src/environments/environment.tis.ts +++ b/src/environments/environment.tis.ts @@ -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, diff --git a/src/tenants/default/app.routes.ts b/src/tenants/default/app.routes.ts index dbe888e..49e75f4 100644 --- a/src/tenants/default/app.routes.ts +++ b/src/tenants/default/app.routes.ts @@ -15,7 +15,10 @@ export const appRoutes: Routes = [ CONSUMER_ROUTES, PROVIDER_ROUTES, PARTNER_ROUTES, - ...POS_ROUTES.children!, + { + path: 'pos', + children: [...POS_ROUTES.children!], + }, ], },