fix ui issues and upload image for guild good
This commit is contained in:
@@ -31,7 +31,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" />
|
||||
<app-key-value label="ایجاد کننده" [value]="invoice()?.account?.account?.username" />
|
||||
<app-key-value label="ایجاد کننده" [value]="invoice()?.consumer_account?.account?.username" />
|
||||
</div>
|
||||
|
||||
@if (variant !== "customer") {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
|
||||
import { KeyValueComponent } from '@/shared/components';
|
||||
import { licenseStatus } from '@/shared/localEnum/constants/licenseStatus';
|
||||
import { getLicenseStatus } from '@/utils';
|
||||
import { Component, computed, inject } from '@angular/core';
|
||||
import { Dialog } from 'primeng/dialog';
|
||||
import { Message } from 'primeng/message';
|
||||
@@ -14,15 +14,7 @@ import { ConsumerStore } from '../store/main.store';
|
||||
export class ConsumerLicenseInfoDialogComponent extends AbstractDialog {
|
||||
private readonly store = inject(ConsumerStore);
|
||||
|
||||
license = computed(() => this.store.entity()?.license);
|
||||
license = computed(() => this.store.entity()?.license_info);
|
||||
|
||||
licenseStatus = computed(() => {
|
||||
if (!this.store.entity()?.license?.expires_at) {
|
||||
return null;
|
||||
}
|
||||
if (new Date().getTime() > new Date(this.store.entity()?.license?.expires_at || '').getTime()) {
|
||||
return licenseStatus.EXPIRED;
|
||||
}
|
||||
return licenseStatus.ACTIVE;
|
||||
});
|
||||
licenseStatus = computed(() => getLicenseStatus(getLicenseStatus(this.license()?.expires_at)));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayoutService } from '@/layout/service/layout.service';
|
||||
import { licenseStatus } from '@/shared/localEnum/constants/licenseStatus';
|
||||
import { getLicenseStatus } from '@/utils';
|
||||
import { Component, computed, inject, signal, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { Button, ButtonIcon } from 'primeng/button';
|
||||
@@ -20,15 +20,9 @@ export class LayoutComponent {
|
||||
|
||||
visibleLicenseInfo = signal(false);
|
||||
|
||||
licenseStatus = computed(() => {
|
||||
if (!this.store.entity()?.license?.expires_at) {
|
||||
return null;
|
||||
}
|
||||
if (new Date().getTime() > new Date(this.store.entity()?.license?.expires_at || '').getTime()) {
|
||||
return licenseStatus.EXPIRED;
|
||||
}
|
||||
return licenseStatus.ACTIVE;
|
||||
});
|
||||
licenseStatus = computed(() =>
|
||||
getLicenseStatus(getLicenseStatus(this.store.entity()?.license_info?.expires_at)),
|
||||
);
|
||||
|
||||
ngOnInit() {
|
||||
this.layoutService.setMenuItems(CONSUMER_MENU_ITEMS);
|
||||
|
||||
+12
-10
@@ -1,17 +1,19 @@
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { TLicenseStatus } from '@/shared/localEnum/constants/licenseStatus';
|
||||
|
||||
export interface IConsumerInfoRawResponse {
|
||||
id: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
full_name: string;
|
||||
mobile_number: string;
|
||||
license: {
|
||||
starts_at: string;
|
||||
expires_at: string;
|
||||
status: TLicenseStatus;
|
||||
partner?: ISummary;
|
||||
};
|
||||
status: string;
|
||||
fullname: string;
|
||||
license_info: LicenseInfo;
|
||||
}
|
||||
export interface IConsumerInfoResponse extends IConsumerInfoRawResponse {}
|
||||
|
||||
interface LicenseInfo {
|
||||
id: string;
|
||||
starts_at: string;
|
||||
expires_at: string;
|
||||
partner: {
|
||||
name: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { CustomerType } from '@/shared/localEnum/constants/customerTypes';
|
||||
import { CustomerIndividual, CustomerLegal } from './io';
|
||||
|
||||
export interface ICustomerSaleInvoicesRawResponse {
|
||||
id: string;
|
||||
code: string;
|
||||
invoice_date: string;
|
||||
notes?: string;
|
||||
total_amount: string;
|
||||
invoice_date: string;
|
||||
consumer_account: ConsumerAccount;
|
||||
pos: Pos;
|
||||
account: ConsumerAccount;
|
||||
items: SaleInvoiceItem[];
|
||||
payments: Payment[];
|
||||
unknown_customer?: UnknownCustomer;
|
||||
customer?: Customer;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
items_count: number;
|
||||
payments: Payments[];
|
||||
}
|
||||
export interface ICustomerSaleInvoicesResponse extends ICustomerSaleInvoicesRawResponse {}
|
||||
|
||||
interface ConsumerAccount {
|
||||
role: string;
|
||||
user: User;
|
||||
account: Account;
|
||||
}
|
||||
|
||||
@@ -24,11 +27,6 @@ interface Account {
|
||||
username: string;
|
||||
}
|
||||
|
||||
interface User {
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
}
|
||||
|
||||
interface Pos extends ISummary {
|
||||
complex: Complex;
|
||||
}
|
||||
@@ -37,8 +35,36 @@ interface Complex extends ISummary {
|
||||
business_activity: ISummary;
|
||||
}
|
||||
|
||||
interface Payments {
|
||||
interface Payment {
|
||||
amount: string;
|
||||
paid_at: string;
|
||||
payment_method: string;
|
||||
}
|
||||
|
||||
interface SaleInvoiceItem {
|
||||
id: string;
|
||||
good: ISummary;
|
||||
}
|
||||
|
||||
interface Customer {
|
||||
id: string;
|
||||
type: CustomerType;
|
||||
customer_legal?: CustomerLegal;
|
||||
customer_individual?: CustomerIndividual;
|
||||
}
|
||||
|
||||
// interface CustomerIndividual {
|
||||
// id: string;
|
||||
// first_name: string;
|
||||
// last_name: string;
|
||||
// }
|
||||
|
||||
// interface CustomerLegal {
|
||||
// id: string;
|
||||
// name: string;
|
||||
// }
|
||||
|
||||
interface UnknownCustomer {
|
||||
name: string;
|
||||
national_id: string;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,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" />
|
||||
<app-key-value label="ایجاد کننده" [value]="invoice()?.account?.account?.username" />
|
||||
<app-key-value label="ایجاد کننده" [value]="invoice()?.consumer_account?.account?.username" />
|
||||
</div>
|
||||
</div>
|
||||
</app-card-data>
|
||||
|
||||
+4
@@ -10,4 +10,8 @@
|
||||
<ng-template #moreActions>
|
||||
<a routerLink pButton [routerLink]="invoicesPageRoute" outlined>تمامی فاکتورها</a>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #status let-item>
|
||||
<p-badge value="ارسال نشده" severity="danger" />
|
||||
</ng-template>
|
||||
</app-page-data-list>
|
||||
|
||||
+6
-7
@@ -1,8 +1,9 @@
|
||||
import { consumerSaleInvoicesNamedRoutes } from '@/domains/consumer/modules/saleInvoices/constants';
|
||||
import { AbstractList } from '@/shared/abstractClasses';
|
||||
import { PageDataListComponent } from '@/shared/components/pageDataList/page-data-list.component';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { Component, inject, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { Router, RouterLink } from '@angular/router';
|
||||
import { Badge } from 'primeng/badge';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { IStatisticsSaleInvoicesResponse } from '../../../models';
|
||||
import { CustomerStatisticsService } from '../../../services/main.service';
|
||||
@@ -10,9 +11,11 @@ import { CustomerStatisticsService } from '../../../services/main.service';
|
||||
@Component({
|
||||
selector: 'consumer-statistics-latest-Invoices',
|
||||
templateUrl: './latest-Invoices.component.html',
|
||||
imports: [PageDataListComponent, ButtonDirective, RouterLink],
|
||||
imports: [PageDataListComponent, ButtonDirective, RouterLink, Badge],
|
||||
})
|
||||
export class ConsumerStatisticsLatestInvoicesComponent extends AbstractList<IStatisticsSaleInvoicesResponse> {
|
||||
@ViewChild('status', { static: true }) status!: TemplateRef<any>;
|
||||
|
||||
private readonly service = inject(CustomerStatisticsService);
|
||||
private readonly router = inject(Router);
|
||||
|
||||
@@ -22,11 +25,7 @@ export class ConsumerStatisticsLatestInvoicesComponent extends AbstractList<ISta
|
||||
this.columns = [
|
||||
{ field: 'code', header: 'کد پیگیری' },
|
||||
{ field: 'total_amount', header: 'مجموع قیمت', type: 'price' },
|
||||
{
|
||||
field: 'created_at',
|
||||
header: 'تاریخ ایجاد',
|
||||
type: 'date',
|
||||
},
|
||||
{ field: 'status', header: 'وضعیت صدور', customDataModel: this.status },
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ export interface IGoodRawResponse {
|
||||
unit_type: UnitType;
|
||||
pricing_model: string;
|
||||
description?: string;
|
||||
image_url: string;
|
||||
is_default_guild_good: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
} @else {
|
||||
@for (good of goods(); track good.id) {
|
||||
<div class="flex-1 bg-surface-card rounded-lg p-1 shadow-xs">
|
||||
<img [src]="goodPlaceholder" class="w-full aspect-[1.3] object-cover rounded-md" />
|
||||
<img [src]="good.image_url || goodPlaceholder" class="w-full aspect-[1.3] object-cover rounded-md" />
|
||||
<div class="mt-2">
|
||||
<span class="text-lg font-bold">
|
||||
{{ good.name }}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
@for (good of goods(); track good.id) {
|
||||
<div class="flex items-center bg-surface-card rounded-lg p-1 shadow-xs gap-2">
|
||||
<div class="grow flex items-center gap-2">
|
||||
<img [src]="goodPlaceholder" class="w-12 h-12 object-cover rounded-md" />
|
||||
<img [src]="good.image_url || goodPlaceholder" class="w-12 h-12 object-cover rounded-md" />
|
||||
<div class="flex flex-col gap-2">
|
||||
<span class="text-lg font-bold">
|
||||
{{ good.name }}
|
||||
|
||||
+29
-17
@@ -1,11 +1,33 @@
|
||||
<div class="border border-surface-border rounded-xl p-2 shadow-sm">
|
||||
<div class="flex gap-3 items-stretch">
|
||||
<img [src]="placeholderImage" class="w-24 h-24 rounded-md bg-surface-100 object-cover shrink-0" />
|
||||
<div class="flex flex-col grow justify-between">
|
||||
<div class="flex items-center">
|
||||
<div class="flex flex-col grow">
|
||||
<span class="font-bold text-lg">{{ inOrderGood.good.name }}</span>
|
||||
<span class="text-sm text-muted-color">{{ inOrderGood.good.sku }}</span>
|
||||
<div class="flex gap-3 items-center">
|
||||
<img
|
||||
[src]="inOrderGood.good.image_url || placeholderImage"
|
||||
class="w-24 h-24 rounded-md bg-surface-100 object-cover shrink-0 border border-surface-border"
|
||||
/>
|
||||
<div class="flex flex-col grow justify-between overflow-hidden">
|
||||
<div class="flex items-stretch grow gap-4">
|
||||
<div class="flex flex-col justify-between gap-2 grow overflow-hidden py-1">
|
||||
<div class="shrink-0 flex flex-col w-full overflow-hidden">
|
||||
<div class="flex w-full overflow-hidden gap-1 items-center">
|
||||
<span class="font-bold text-lg text-ellipsis text-nowrap overflow-hidden">
|
||||
{{ inOrderGood.good.name }}
|
||||
</span>
|
||||
<div class="grow">
|
||||
<span class="text-sm text-muted-color">({{ inOrderGood.good.sku }})</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-sm text-ellipsis text-nowrap overflow-hidden">
|
||||
{{ inOrderGood.quantity }} {{ enumTranslator(inOrderGood.good.unit_type) }}
|
||||
</span>
|
||||
</div>
|
||||
@if (!inOrderGood.discount_amount) {
|
||||
<span [appPriceMask]="inOrderGood.total_amount"></span>
|
||||
} @else {
|
||||
<div class="flex flex-col">
|
||||
<span class="line-through text-muted-color text-xs" [appPriceMask]="inOrderGood.base_total_amount"></span>
|
||||
<span [appPriceMask]="inOrderGood.base_total_amount - inOrderGood.discount_amount"></span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="flex shrink-0 gap-1">
|
||||
<button
|
||||
@@ -28,16 +50,6 @@
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mt-auto">
|
||||
<div class="ms-auto shrink-0">
|
||||
<!-- <app-uikit-counter
|
||||
[min]="1"
|
||||
[max]="inOrderGood.maxQuantity"
|
||||
[value]="inOrderGood.count"
|
||||
(valueChange)="updateInOrderGoodQuantity(inOrderGood.goodId, $event)"
|
||||
></app-uikit-counter> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+4
-1
@@ -1,3 +1,5 @@
|
||||
import { PriceMaskDirective } from '@/shared/directives';
|
||||
import { enumTranslator } from '@/utils';
|
||||
import { Component, inject, Input, signal } from '@angular/core';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import images from 'src/assets/images';
|
||||
@@ -8,7 +10,7 @@ import { PayloadFormDialogComponent } from '../payload-form.component';
|
||||
@Component({
|
||||
selector: 'pos-order-card-template',
|
||||
templateUrl: './order-card-template.component.html',
|
||||
imports: [ButtonDirective, PayloadFormDialogComponent],
|
||||
imports: [ButtonDirective, PayloadFormDialogComponent, PriceMaskDirective],
|
||||
})
|
||||
export class OrderCardTemplateComponent {
|
||||
@Input({ required: true }) inOrderGood!: IPosInOrderGood;
|
||||
@@ -18,6 +20,7 @@ export class OrderCardTemplateComponent {
|
||||
visible = signal(false);
|
||||
|
||||
placeholderImage = images.placeholders.default;
|
||||
enumTranslator = (key: string) => enumTranslator(key);
|
||||
|
||||
removeGoodFromOrder() {
|
||||
this.store.removeFromInOrderGoods(this.inOrderGood.id);
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
[percentageControl]="form.controls.payload.controls.wages_percentage"
|
||||
[amountControl]="form.controls.payload.controls.wages_amount"
|
||||
[baseAmount]="unitWithQuantity()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="unitWithQuantity()"
|
||||
name="wages"
|
||||
label="اجرت"
|
||||
/>
|
||||
@@ -14,6 +16,8 @@
|
||||
[percentageControl]="form.controls.payload.controls.commission_percentage"
|
||||
[amountControl]="form.controls.payload.controls.commission_amount"
|
||||
[baseAmount]="unitWithQuantity()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="unitWithQuantity()"
|
||||
name="commission"
|
||||
label="حقالعمل"
|
||||
/>
|
||||
@@ -21,6 +25,8 @@
|
||||
[percentageControl]="form.controls.payload.controls.profit_percentage"
|
||||
[amountControl]="form.controls.payload.controls.profit_amount"
|
||||
[baseAmount]="totalAmountBeforeProfit()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="totalAmountBeforeProfit()"
|
||||
name="profit"
|
||||
label="سود"
|
||||
/>
|
||||
@@ -29,6 +35,8 @@
|
||||
[percentageControl]="form.controls.discount_percentage"
|
||||
[amountControl]="form.controls.discount_amount"
|
||||
[baseAmount]="baseTotalAmount()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="baseTotalAmount()"
|
||||
name="discount"
|
||||
label="تخفیف"
|
||||
/>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { InputComponent } from '@/shared/components';
|
||||
import { AmountPercentageInputComponent } from '@/shared/components/amountPercentageInput/amount-percentage-input.component';
|
||||
import { TGoldKarat } from '@/shared/localEnum/constants/goldKarat';
|
||||
import { formatWithCurrency } from '@/utils';
|
||||
import { Component, computed, EventEmitter, Output } from '@angular/core';
|
||||
import { Component, EventEmitter, Output, signal } from '@angular/core';
|
||||
import { ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { Button } from 'primeng/button';
|
||||
import { IGoldPayload, IPosOrderItem } from '../../../models';
|
||||
@@ -29,30 +29,54 @@ export class PosGoldPayloadFormComponent extends AbstractForm<
|
||||
@Output() onSubmitForm = new EventEmitter<IGoldPayload>();
|
||||
@Output() onChangeTotalAmount = new EventEmitter<number>();
|
||||
|
||||
unitWithQuantity = signal<number>(0);
|
||||
totalAmountBeforeProfit = signal<number>(0);
|
||||
baseTotalAmount = signal<number>(0);
|
||||
taxAmount = signal<number>(0);
|
||||
totalAmount = signal<number>(0);
|
||||
|
||||
private readonly initialForm = () => {
|
||||
const form = this.fb.group({
|
||||
unit_price: [this.initialValues?.unit_price || 200_000_000, [Validators.required]],
|
||||
quantity: [this.initialValues?.quantity || 2, [Validators.required]],
|
||||
unit_price: [this.initialValues?.unit_price || 0, [Validators.required]],
|
||||
quantity: [this.initialValues?.quantity || 0, [Validators.required]],
|
||||
discount_amount: [this.initialValues?.discount || 0],
|
||||
discount_percentage: [this.initialValues?.discount || 0],
|
||||
discount_percentage: [0, [Validators.max(100), Validators.min(0)]],
|
||||
payload: this.fb.group({
|
||||
commission_amount: [this.initialValues?.payload?.commission || 0, [Validators.required]],
|
||||
commission_percentage: [
|
||||
this.initialValues?.payload?.commission || 10,
|
||||
[Validators.required],
|
||||
],
|
||||
commission_percentage: [0, [Validators.required, Validators.max(100), Validators.min(0)]],
|
||||
wages_amount: [this.initialValues?.payload?.wages || 0, [Validators.required]],
|
||||
wages_percentage: [this.initialValues?.payload?.wages || 10, [Validators.required]],
|
||||
wages_percentage: [0, [Validators.required, Validators.max(100), Validators.min(0)]],
|
||||
profit_amount: [this.initialValues?.payload?.profit || 0, [Validators.required]],
|
||||
profit_percentage: [this.initialValues?.payload?.profit || 10, [Validators.required]],
|
||||
profit_percentage: [0, [Validators.required, Validators.max(100), Validators.min(0)]],
|
||||
karat: [this.initialValues?.payload?.karat || '', [Validators.required]],
|
||||
}),
|
||||
});
|
||||
|
||||
form.valueChanges.subscribe((value) => {
|
||||
this.updateCalculateAmount(value as any);
|
||||
});
|
||||
|
||||
form.setValue({
|
||||
unit_price: 200_000_000,
|
||||
quantity: 2,
|
||||
discount_amount: 0,
|
||||
discount_percentage: 0,
|
||||
payload: {
|
||||
commission_amount: 0,
|
||||
commission_percentage: 10,
|
||||
wages_amount: 0,
|
||||
wages_percentage: 10,
|
||||
profit_amount: 0,
|
||||
profit_percentage: 10,
|
||||
karat: '18',
|
||||
},
|
||||
});
|
||||
|
||||
return form;
|
||||
};
|
||||
|
||||
form = this.initialForm();
|
||||
|
||||
override submitForm(payload: IPosOrderItem) {
|
||||
this.onSubmit.emit({
|
||||
...payload,
|
||||
@@ -68,36 +92,28 @@ export class PosGoldPayloadFormComponent extends AbstractForm<
|
||||
});
|
||||
}
|
||||
|
||||
unitWithQuantity = computed(
|
||||
() => (this.form.value.unit_price ?? 0) * (this.form.value.quantity ?? 0),
|
||||
);
|
||||
updateCalculateAmount(payload: Partial<IPosOrderItem<any>>) {
|
||||
const commissionAmount = Number(payload.payload?.commission_amount ?? '0');
|
||||
const wageAmount = Number(payload.payload?.wages ?? '0');
|
||||
const discountAmount = Number(payload.discount_amount ?? '0');
|
||||
const profitAmount = Number(payload.payload?.profit_amount ?? '0');
|
||||
const unitPrice = Number(payload.unit_price ?? '0');
|
||||
const quantity = Number(payload.quantity ?? '0');
|
||||
|
||||
totalAmountBeforeProfit = computed(() => {
|
||||
const commissionAmount = Number(this.form.value.payload?.commission_amount ?? '0');
|
||||
const wageAmount = Number(this.form.value.payload?.wages_amount ?? '0');
|
||||
return this.unitWithQuantity() + wageAmount + commissionAmount;
|
||||
});
|
||||
const unitWithQuantity = unitPrice * quantity;
|
||||
const totalAmountBeforeProfit = unitWithQuantity + wageAmount + commissionAmount;
|
||||
const baseTotalAmount = totalAmountBeforeProfit + profitAmount;
|
||||
const taxAmount = (profitAmount + commissionAmount + wageAmount - discountAmount) * 0.1;
|
||||
const totalAmount = baseTotalAmount - discountAmount + taxAmount;
|
||||
|
||||
baseTotalAmount = computed(() => {
|
||||
const commissionAmount = Number(this.form.value.payload?.commission_amount ?? '0');
|
||||
const wageAmount = Number(this.form.value.payload?.wages_amount ?? '0');
|
||||
const profitAmount = Number(this.form.value.payload?.profit_amount ?? '0');
|
||||
this.unitWithQuantity.set(unitWithQuantity);
|
||||
this.totalAmountBeforeProfit.set(totalAmountBeforeProfit);
|
||||
this.baseTotalAmount.set(baseTotalAmount);
|
||||
this.taxAmount.set(taxAmount);
|
||||
this.totalAmount.set(totalAmount);
|
||||
|
||||
return this.unitWithQuantity() + profitAmount + commissionAmount + wageAmount;
|
||||
});
|
||||
|
||||
taxAmount = computed(() => {
|
||||
const commissionAmount = Number(this.form.value.payload?.commission_amount ?? '0');
|
||||
const wageAmount = Number(this.form.value.payload?.wages_amount ?? '0');
|
||||
const profitAmount = Number(this.form.value.payload?.profit_amount ?? '0');
|
||||
const discountAmount = Number(this.form.value.discount_amount ?? '0');
|
||||
return (profitAmount + commissionAmount + wageAmount - discountAmount) * 0.1;
|
||||
});
|
||||
|
||||
totalAmount = computed(() => {
|
||||
const discountAmount = Number(this.form.value.discount_amount ?? '0');
|
||||
return this.baseTotalAmount() - discountAmount + this.taxAmount();
|
||||
});
|
||||
this.onChangeTotalAmount.emit(totalAmount);
|
||||
}
|
||||
|
||||
toAmountFormat(amount: number) {
|
||||
if (!amount) {
|
||||
|
||||
+7
-6
@@ -9,15 +9,16 @@
|
||||
[min]="0"
|
||||
/>
|
||||
|
||||
<app-input
|
||||
[control]="form.controls.discount"
|
||||
<app-amount-percentage-input
|
||||
[percentageControl]="form.controls.discount_percentage"
|
||||
[amountControl]="form.controls.discount_amount"
|
||||
[baseAmount]="baseTotalAmount()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="baseTotalAmount()"
|
||||
name="discount"
|
||||
label="تخفیف"
|
||||
type="number"
|
||||
suffix="درصد"
|
||||
[min]="0"
|
||||
[max]="100"
|
||||
/>
|
||||
|
||||
<hr />
|
||||
<div class="flex flex-col gap-4 justify-center w-full">
|
||||
<pos-form-dialog-amount-card-template
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { AbstractForm } from '@/shared/abstractClasses';
|
||||
import { InputComponent } from '@/shared/components';
|
||||
import { AmountPercentageInputComponent } from '@/shared/components/amountPercentageInput/amount-percentage-input.component';
|
||||
import { formatWithCurrency, getGoodUnitTypeProperties, UnitType } from '@/utils';
|
||||
import { Component, computed, EventEmitter, Input, Output, signal } from '@angular/core';
|
||||
import { ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
@@ -10,7 +11,13 @@ import { PosFormDialogAmountCardTemplateComponent } from '../form-dialog-amount-
|
||||
@Component({
|
||||
selector: 'pos-standard-payload-form',
|
||||
templateUrl: './form.component.html',
|
||||
imports: [ReactiveFormsModule, InputComponent, Button, PosFormDialogAmountCardTemplateComponent],
|
||||
imports: [
|
||||
ReactiveFormsModule,
|
||||
InputComponent,
|
||||
Button,
|
||||
PosFormDialogAmountCardTemplateComponent,
|
||||
AmountPercentageInputComponent,
|
||||
],
|
||||
})
|
||||
export class PosStandardPayloadFormComponent extends AbstractForm<
|
||||
IPosOrderItem<IStandardPayload>,
|
||||
@@ -23,7 +30,8 @@ export class PosStandardPayloadFormComponent extends AbstractForm<
|
||||
const form = this.fb.group({
|
||||
unit_price: [this.initialValues?.unit_price || 0, [Validators.required]],
|
||||
quantity: [this.initialValues?.quantity || 0, [Validators.required]],
|
||||
discount: [this.initialValues?.discount || ''],
|
||||
discount_amount: [this.initialValues?.discount || 0, [Validators.min(0)]],
|
||||
discount_percentage: [0, [Validators.min(0), Validators.max(100)]],
|
||||
});
|
||||
|
||||
form.valueChanges.subscribe((value) => {
|
||||
@@ -60,7 +68,7 @@ export class PosStandardPayloadFormComponent extends AbstractForm<
|
||||
|
||||
updateCalculateAmount(value: Partial<IPosOrderItem<IStandardPayload>>) {
|
||||
const baseTotalAmount = (value.unit_price ?? 0) * (value.quantity ?? 0);
|
||||
const discountAmount = (baseTotalAmount * Number(value.discount || '0')) / 100;
|
||||
const discountAmount = Number(value.discount_amount ?? '0');
|
||||
const baseTotalAmountWithoutTax = baseTotalAmount - discountAmount;
|
||||
const taxAmount = baseTotalAmountWithoutTax * 0.1;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ export interface IPosOrderItem<T = TPosOrderGoodPayload> {
|
||||
good_id?: string;
|
||||
service_id?: string;
|
||||
notes?: string;
|
||||
image_url?: string;
|
||||
payload: T;
|
||||
|
||||
base_total_amount: number;
|
||||
|
||||
@@ -233,19 +233,22 @@ export class PosLandingStore {
|
||||
}),
|
||||
|
||||
map((_res) => {
|
||||
// this.setState({
|
||||
// inOrderGoods: [],
|
||||
// customerDetails: {
|
||||
// type: CustomerType.UNKNOWN,
|
||||
// },
|
||||
// invoiceDate: nowJalali(JALALI_DATE_FORMATS.NUMERIC),
|
||||
// payments: {
|
||||
// cash: 0,
|
||||
// set_off: 0,
|
||||
// terminal: 0,
|
||||
// },
|
||||
// orderNote: '',
|
||||
// });
|
||||
if (_res) {
|
||||
this.setState({
|
||||
inOrderGoods: [],
|
||||
customerDetails: {
|
||||
type: CustomerType.UNKNOWN,
|
||||
},
|
||||
invoiceDate: nowJalali(JALALI_DATE_FORMATS.NUMERIC),
|
||||
payments: {
|
||||
cash: 0,
|
||||
set_off: 0,
|
||||
terminal: 0,
|
||||
},
|
||||
orderNote: '',
|
||||
});
|
||||
}
|
||||
|
||||
return _res;
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BreadcrumbService } from '@/core/services';
|
||||
import { AppCardComponent, KeyValueComponent } from '@/shared/components';
|
||||
import { JalaliDateDirective } from '@/shared/directives';
|
||||
import { licenseStatus } from '@/shared/localEnum/constants/licenseStatus';
|
||||
import { getLicenseStatus } from '@/utils';
|
||||
import { Component, computed, effect, inject, signal } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Button } from 'primeng/button';
|
||||
@@ -38,19 +38,9 @@ export class ConsumerComponent {
|
||||
readonly loading = computed(() => this.store.loading());
|
||||
readonly consumer = computed(() => this.store.entity());
|
||||
readonly license = computed(() => this.store.entity()?.license_info);
|
||||
readonly licenseStatus = computed(() => {
|
||||
console.log(this.store.entity()?.license_info?.expires_at);
|
||||
|
||||
if (!this.store.entity()?.license_info?.expires_at) {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
new Date().getTime() > new Date(this.store.entity()?.license_info?.expires_at || '').getTime()
|
||||
) {
|
||||
return licenseStatus.EXPIRED;
|
||||
}
|
||||
return licenseStatus.ACTIVE;
|
||||
});
|
||||
readonly licenseStatus = computed(() =>
|
||||
getLicenseStatus(this.store.entity()?.license_info?.expires_at),
|
||||
);
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<p-dialog [header]="preparedTitle" [(visible)]="visible" [modal]="true" [style]="{ width: '500px' }" [closable]="true">
|
||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
||||
<app-shared-upload-file accept="image/*" name="image" (onSelect)="changeFile($event)" />
|
||||
<app-input label="عنوان" [control]="form.controls.name" name="name" />
|
||||
<app-input label="شناسه عمومی" [control]="form.controls.sku" name="sku" />
|
||||
<admin-guild-categories-select
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import { AbstractFormDialog } from '@/shared/abstractClasses';
|
||||
import { InputComponent } from '@/shared/components';
|
||||
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
||||
import { Component, inject, Input } from '@angular/core';
|
||||
import { Component, inject, Input, signal } from '@angular/core';
|
||||
import { ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { Dialog } from 'primeng/dialog';
|
||||
|
||||
import { Maybe } from '@/core';
|
||||
import { EnumSelectComponent } from '@/shared/apiEnum/select.component';
|
||||
import { onSelectFileArgs } from '@/shared/components/uploadFile/model';
|
||||
import { SharedUploadFileComponent } from '@/shared/components/uploadFile/upload-file.component';
|
||||
import { buildFormData } from '@/utils';
|
||||
import { IGuildGoodRequest, IGuildGoodsResponse } from '../../models';
|
||||
import { GuildGoodsService } from '../../services/goods.service';
|
||||
import { GuildCategoriesSelectComponent } from '../categories/select.component';
|
||||
@@ -20,6 +24,7 @@ import { GuildCategoriesSelectComponent } from '../categories/select.component';
|
||||
FormFooterActionsComponent,
|
||||
EnumSelectComponent,
|
||||
GuildCategoriesSelectComponent,
|
||||
SharedUploadFileComponent,
|
||||
],
|
||||
})
|
||||
export class GuildGoodFormComponent extends AbstractFormDialog<
|
||||
@@ -31,6 +36,8 @@ export class GuildGoodFormComponent extends AbstractFormDialog<
|
||||
|
||||
private service = inject(GuildGoodsService);
|
||||
|
||||
goodImage = signal<Maybe<File>>(null);
|
||||
|
||||
form = this.fb.group({
|
||||
name: [this.initialValues?.name || '', [Validators.required]],
|
||||
sku: [this.initialValues?.sku || '', [Validators.required]],
|
||||
@@ -44,10 +51,20 @@ export class GuildGoodFormComponent extends AbstractFormDialog<
|
||||
return `${this.editMode ? 'ویرایش' : 'ایجاد'} کالا`;
|
||||
}
|
||||
|
||||
changeFile(payload: onSelectFileArgs) {
|
||||
this.goodImage.set(payload.file);
|
||||
}
|
||||
|
||||
override ngOnChanges(): void {
|
||||
this.form.patchValue(this.initialValues || {});
|
||||
this.form.controls.category_id.setValue(this.initialValues?.category.id || '');
|
||||
}
|
||||
|
||||
override submitForm(payload: IGuildGoodRequest) {
|
||||
const formData = buildFormData(this.form, { image: this.goodImage() });
|
||||
if (this.editMode) {
|
||||
return this.service.update(this.guildId, this.categoryId!, payload);
|
||||
return this.service.update(this.guildId, this.categoryId!, formData);
|
||||
}
|
||||
return this.service.create(this.guildId, payload);
|
||||
return this.service.create(this.guildId, formData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { GUILD_GOODS_API_ROUTES } from '../constants/apiRoutes/goods';
|
||||
import { IGuildGoodRequest, IGuildGoodsRawResponse, IGuildGoodsResponse } from '../models';
|
||||
import { IGuildGoodsRawResponse, IGuildGoodsResponse } from '../models';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class GuildGoodsService {
|
||||
@@ -18,11 +18,11 @@ export class GuildGoodsService {
|
||||
return this.http.get<IGuildGoodsRawResponse>(this.apiRoutes.single(guildId, id));
|
||||
}
|
||||
|
||||
create(guildId: string, data: IGuildGoodRequest): Observable<IGuildGoodsResponse> {
|
||||
create(guildId: string, data: FormData): Observable<IGuildGoodsResponse> {
|
||||
return this.http.post<IGuildGoodsResponse>(this.apiRoutes.list(guildId), data);
|
||||
}
|
||||
|
||||
update(guildId: string, id: string, data: IGuildGoodRequest): Observable<IGuildGoodsResponse> {
|
||||
update(guildId: string, id: string, data: FormData): Observable<IGuildGoodsResponse> {
|
||||
return this.http.patch<IGuildGoodsResponse>(this.apiRoutes.single(guildId, id), data);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user