add salesInvoice in pos of consumer domain

This commit is contained in:
2026-03-30 13:17:34 +03:30
parent c10623bc3f
commit 44097fe1ac
35 changed files with 855 additions and 122 deletions
@@ -8,13 +8,6 @@
>
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
<app-input label="عنوان" [control]="form.controls.name" name="name" />
<app-input label="سریال دستگاه" [control]="form.controls.serial" name="serial" />
<!-- <app-input label="مدل دستگاه" [control]="form.controls.model" name="model" /> -->
<app-enum-select [control]="form.controls.pos_type" type="posType" name="pos_type" />
@if (form.controls.pos_type.value === "PSP") {
<catalog-device-select [control]="form.controls.device_id" />
<catalog-provider-select [control]="form.controls.provider_id" />
}
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" />
</form>
</p-dialog>
@@ -34,35 +34,8 @@ export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IP
initForm = () => {
const form = this.fb.group({
name: [this.initialValues?.name || '', [Validators.required]],
serial: [this.initialValues?.serial || '', [Validators.required]],
// model: [this.initialValues?.model || '', [Validators.required]],
pos_type: [this.initialValues?.pos_type || '', [Validators.required]],
device_id: [this.initialValues?.device?.id || ''],
provider_id: [this.initialValues?.provider?.id || ''],
});
form.controls.pos_type.valueChanges.subscribe((value) => {
if (value === 'PSP') {
form.addControl(
'device_id',
this.fb.control<string>(this.initialValues?.device?.id ?? '', {
nonNullable: true,
validators: [Validators.required],
}),
);
form.addControl(
'provider_id',
this.fb.control<string>(this.initialValues?.provider?.id ?? '', {
nonNullable: true,
validators: [Validators.required],
}),
);
} else {
// @ts-ignore
form.removeControl('device_id');
// @ts-ignore
form.removeControl('provider_id');
}
});
return form;
};
@@ -0,0 +1,8 @@
<app-page-data-list
pageTitle="لیست فاکتور‌های صادر شده"
[columns]="columns"
emptyPlaceholderTitle="تا به حال فاکتور فروشی توسط این پایانه ایجاد نشده است."
[items]="items()"
[loading]="loading()"
>
</app-page-data-list>
@@ -0,0 +1,47 @@
// import { CatalogRoleTagComponent } from '@/shared/catalog/roles';
import { AbstractList } from '@/shared/abstractClasses/abstract-list';
import {
IColumn,
PageDataListComponent,
} from '@/shared/components/pageDataList/page-data-list.component';
import { Component, inject, Input } from '@angular/core';
import { ISalesInvoicesResponse } from '../../models';
import { ConsumerSalesInvoicesService } from '../../services/invoices.service';
@Component({
selector: 'consumer-salesInvoices-list',
templateUrl: './list.component.html',
imports: [PageDataListComponent],
})
export class ConsumerSalesInvoicesComponent extends AbstractList<ISalesInvoicesResponse> {
@Input({ required: true }) complexId!: string;
@Input({ required: true }) posId!: string;
@Input() fullHeight?: boolean;
@Input() header: IColumn[] = [
{ field: 'id', header: 'شناسه', type: 'id' },
{ field: 'code', header: 'کد رهگیری' },
{ field: 'total_amount', header: 'مبلغ کل', type: 'price' },
{
field: 'items_count',
header: 'تعداد کالاها',
customDataModel(item) {
return `${item.items.length} عدد`;
},
},
{
field: 'invoice_date',
header: 'تاریخ',
type: 'date',
},
];
private readonly service = inject(ConsumerSalesInvoicesService);
override setColumns(): void {
this.columns = this.header;
}
override getDataRequest() {
return this.service.getAll(this.complexId, this.posId);
}
}
@@ -0,0 +1,8 @@
const baseUrl = (complexId: string, posId: string) =>
`/api/v1/consumer/complexes/${complexId}/poses/${posId}/sales_invoices`;
export const POS_SALES_INVOICES_API_ROUTES = {
list: (complexId: string, posId: string) => `${baseUrl(complexId, posId)}`,
single: (complexId: string, posId: string, invoiceId: string) =>
`${baseUrl(complexId, posId)}/${invoiceId}`,
};
@@ -1,3 +1,4 @@
export * from './complexes_io';
export * from './io';
export * from './poses_io';
export * from './salesInvoices_io';
@@ -15,10 +15,4 @@ export interface IPosResponse extends IPosRawResponse {}
export interface IPosRequest {
name: string;
serial: string;
model?: string;
status: string;
pos_type: string;
device_id: string;
provider_id: string;
}
@@ -0,0 +1,51 @@
import ISummary from '@/core/models/summary';
import { TCustomerInfo, TPosOrderGoodPayload } from '@/domains/pos/modules/landing/models';
import { UnitType } from '@/utils';
export interface ISalesInvoicesRawResponse {
id: string;
code: string;
invoice_date: string;
total_amount: string;
items: Item[];
payments: Payment[];
customer?: TCustomerInfo;
notes?: string;
unknown_customer?: UnknownCustomer;
}
export interface ISalesInvoicesResponse extends ISalesInvoicesRawResponse {}
export interface ISalesInvoicesRequest {}
interface UnknownCustomer {
name?: string;
national_code?: string;
}
interface Payment {
amount: string;
paid_at: string;
payment_method: string;
}
interface Item {
unit_type: UnitType;
discount: string;
quantity: string;
total_amount: string;
unit_price: string;
payload: TPosOrderGoodPayload;
good: Good;
notes?: string;
}
interface Good {
id: string;
name: string;
sku: string;
barcode: null;
local_sku: null;
pricing_model: string;
unit_type: string;
category: ISummary;
}
@@ -0,0 +1,28 @@
import { IPaginatedResponse } from '@/core/models/service.model';
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { POS_SALES_INVOICES_API_ROUTES } from '../constants/apiRoutes/posSalesInvoices';
import { ISalesInvoicesRawResponse, ISalesInvoicesResponse } from '../models';
@Injectable({ providedIn: 'root' })
export class ConsumerSalesInvoicesService {
constructor(private http: HttpClient) {}
private apiRoutes = POS_SALES_INVOICES_API_ROUTES;
getAll(complexId: string, posId: string): Observable<IPaginatedResponse<ISalesInvoicesResponse>> {
return this.http.get<IPaginatedResponse<ISalesInvoicesRawResponse>>(
this.apiRoutes.list(complexId, posId),
);
}
getSingle(
complexId: string,
posId: string,
invoiceId: string,
): Observable<ISalesInvoicesResponse> {
return this.http.get<ISalesInvoicesRawResponse>(
this.apiRoutes.single(complexId, posId, invoiceId),
);
}
}
@@ -6,10 +6,17 @@
<div class="flex flex-col gap-4">
<div class="grid grid-cols-3 gap-4 items-center">
<app-key-value label="عنوان" [value]="pos()?.name" />
<app-key-value label="شماره سریال" [value]="pos()?.serial" />
<app-key-value label="نوع پایانه" [value]="pos()?.pos_type" />
<app-key-value label="نوع دستگاه" [value]="pos()?.device?.name" />
<app-key-value label="مدل دستگاه" [value]="pos()?.model" />
<app-key-value label="ارایه‌دهنده" [value]="pos()?.provider?.name" />
</div>
</div>
</app-card-data>
<consumer-salesInvoices-list [complexId]="complexId()" [posId]="posId()" />
<consumer-pos-form
[(visible)]="editMode"
[editMode]="true"
@@ -6,6 +6,7 @@ import { ActivatedRoute } from '@angular/router';
import { CookieService } from 'ngx-cookie-service';
import { Button } from 'primeng/button';
import { ConsumerPosFormComponent } from '../../components/poses/form.component';
import { ConsumerSalesInvoicesComponent } from '../../components/salesInvoices/list.component';
import { BusinessActivityStore } from '../../store/businessActivity.store';
import { ConsumerComplexStore } from '../../store/complex.store';
import { PosStore } from '../../store/pos.store';
@@ -13,7 +14,13 @@ import { PosStore } from '../../store/pos.store';
@Component({
selector: 'superAdmin-user-pos',
templateUrl: './single.component.html',
imports: [AppCardComponent, KeyValueComponent, ConsumerPosFormComponent, Button],
imports: [
AppCardComponent,
KeyValueComponent,
ConsumerPosFormComponent,
Button,
ConsumerSalesInvoicesComponent,
],
})
export class SuperAdminUserPosComponent {
private readonly businessStore = inject(BusinessActivityStore);