transform pos payload forms to shared
This commit is contained in:
-24
@@ -1,24 +0,0 @@
|
||||
<p-card class="border-none w-full">
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex justify-between items-center">
|
||||
<span>جمع قیمت</span>
|
||||
@if (!discountAmount) {
|
||||
<span [appPriceMask]="baseTotalAmount"></span>
|
||||
} @else {
|
||||
<div class="flex flex-col items-end">
|
||||
<span class="line-through text-muted-color text-xs" [appPriceMask]="baseTotalAmount"></span>
|
||||
<span [appPriceMask]="baseTotalAmount - discountAmount"></span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="flex justify-between items-center">
|
||||
<span>ارزش افزوده</span>
|
||||
<span [appPriceMask]="taxAmount"></span>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="flex justify-between items-center font-bold text-lg">
|
||||
<span>مجموع کل</span>
|
||||
<span [appPriceMask]="totalAmount"></span>
|
||||
</div>
|
||||
</div>
|
||||
</p-card>
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
import { PriceMaskDirective } from '@/shared/directives';
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Card } from 'primeng/card';
|
||||
|
||||
@Component({
|
||||
selector: 'pos-form-dialog-amount-card-template',
|
||||
templateUrl: './form-dialog-amount-card-template.component.html',
|
||||
imports: [Card, PriceMaskDirective],
|
||||
})
|
||||
export class PosFormDialogAmountCardTemplateComponent {
|
||||
@Input({ required: true }) baseTotalAmount!: number;
|
||||
@Input({ required: true }) totalAmount!: number;
|
||||
@Input({ required: true }) discountAmount!: number;
|
||||
@Input({ required: true }) taxAmount!: number;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
<div class="form-group">
|
||||
<form [formGroup]="form">
|
||||
<app-input [control]="form.controls.unit_price" name="unit_price" label="مبلغ واحد" type="price" />
|
||||
<app-input [control]="form.controls.quantity" name="quantity" label="مقدار" type="number" suffix="گرم" />
|
||||
<app-enum-select [control]="form.controls.payload.controls.karat" type="goldKarat" name="karat" />
|
||||
|
||||
<app-amount-percentage-input
|
||||
[percentageControl]="form.controls.payload.controls.wages_percentage"
|
||||
[amountControl]="form.controls.payload.controls.wages"
|
||||
[baseAmount]="unitWithQuantity()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="unitWithQuantity()"
|
||||
name="wages"
|
||||
label="اجرت" />
|
||||
|
||||
<app-amount-percentage-input
|
||||
[percentageControl]="form.controls.payload.controls.commission_percentage"
|
||||
[amountControl]="form.controls.payload.controls.commission"
|
||||
[baseAmount]="unitWithQuantity()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="unitWithQuantity()"
|
||||
name="commission"
|
||||
label="حقالعمل" />
|
||||
<app-amount-percentage-input
|
||||
[percentageControl]="form.controls.payload.controls.profit_percentage"
|
||||
[amountControl]="form.controls.payload.controls.profit"
|
||||
[baseAmount]="totalAmountBeforeProfit()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="totalAmountBeforeProfit()"
|
||||
name="profit"
|
||||
label="سود" />
|
||||
</form>
|
||||
|
||||
<app-amount-percentage-input
|
||||
[percentageControl]="form.controls.discount_percentage"
|
||||
[amountControl]="form.controls.discount_amount"
|
||||
[baseAmount]="baseAmountForDiscountCalculation()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="baseAmountForDiscountCalculation()"
|
||||
name="discount_amount"
|
||||
label="تخفیف">
|
||||
<ng-template #labelSuffix>
|
||||
<p-selectButton
|
||||
[options]="discountTypeItems"
|
||||
[(ngModel)]="discountType"
|
||||
[allowEmpty]="false"
|
||||
optionLabel="label"
|
||||
optionValue="value"
|
||||
(onChange)="changeDiscountCalculation($event)" />
|
||||
</ng-template>
|
||||
</app-amount-percentage-input>
|
||||
|
||||
<hr />
|
||||
<div class="flex w-full flex-col justify-center gap-4">
|
||||
<pos-form-dialog-amount-card-template
|
||||
[totalAmount]="totalAmount()"
|
||||
[baseTotalAmount]="baseTotalAmount()"
|
||||
[discountAmount]="form.controls.discount_amount.value || 0"
|
||||
[taxAmount]="taxAmount()" />
|
||||
<button pButton class="w-full sm:w-auto" (click)="submit()">{{ preparedCTAText() }}</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,184 +0,0 @@
|
||||
import { greaterThanValidator } from '@/core/validators/greater.validator';
|
||||
import { PosConfigGoldPriceService } from '@/domains/pos/modules/configs/components/goldPrice/services/main.service';
|
||||
import { AbstractForm } from '@/shared/abstractClasses';
|
||||
import { EnumSelectComponent } from '@/shared/apiEnum/select.component';
|
||||
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, inject, Input, Output, signal } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { SelectButton, SelectButtonChangeEvent } from 'primeng/selectbutton';
|
||||
import { IGoldPayload, IPosOrderItem } from '../../../models';
|
||||
import { PosFormDialogAmountCardTemplateComponent } from '../form-dialog-amount-card-template.component';
|
||||
|
||||
@Component({
|
||||
selector: 'pos-gold-payload-form',
|
||||
templateUrl: './form.component.html',
|
||||
imports: [
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
InputComponent,
|
||||
EnumSelectComponent,
|
||||
PosFormDialogAmountCardTemplateComponent,
|
||||
SelectButton,
|
||||
AmountPercentageInputComponent,
|
||||
ButtonDirective,
|
||||
],
|
||||
})
|
||||
export class PosGoldPayloadFormComponent extends AbstractForm<
|
||||
IPosOrderItem<IGoldPayload>,
|
||||
IPosOrderItem<IGoldPayload>
|
||||
> {
|
||||
override defaultValues: Partial<IPosOrderItem<IGoldPayload>> = {
|
||||
// unit_price: 200_000_000,
|
||||
// quantity: 2,
|
||||
payload: {
|
||||
// commission: 10_000,
|
||||
// wages: 10_000,
|
||||
// profit: 10_000,
|
||||
karat: 'KARAT_18' as TGoldKarat,
|
||||
} as any,
|
||||
};
|
||||
|
||||
@Input({ required: true }) vatPercentage!: number;
|
||||
@Input() isRapidInvoice!: boolean;
|
||||
|
||||
@Output() onSubmitForm = new EventEmitter<IGoldPayload>();
|
||||
@Output() onChangeTotalAmount = new EventEmitter<number>();
|
||||
|
||||
private readonly posGoldConfig = inject(PosConfigGoldPriceService);
|
||||
|
||||
readonly discountTypeItems = [
|
||||
{
|
||||
label: 'از سود',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: 'از کل',
|
||||
value: 2,
|
||||
},
|
||||
];
|
||||
|
||||
discountType = signal<number>(1);
|
||||
unitWithQuantity = signal<number>(0);
|
||||
totalAmountBeforeProfit = signal<number>(0);
|
||||
baseTotalAmount = signal<number>(0);
|
||||
baseAmountForDiscountCalculation = signal<number>(0);
|
||||
taxAmount = signal<number>(0);
|
||||
discountAmount = signal<number>(0);
|
||||
totalAmount = signal<number>(0);
|
||||
|
||||
goldDefaultUnitPrice = signal<number>(0);
|
||||
|
||||
preparedCTAText = computed(() =>
|
||||
this.editMode ? 'اعمال ویرایش' : this.isRapidInvoice ? 'ثبت و پرداخت' : 'افزودن به لیست خرید'
|
||||
);
|
||||
|
||||
private readonly initialForm = () => {
|
||||
const defaultPrice = this.posGoldConfig.get();
|
||||
|
||||
this.goldDefaultUnitPrice.set(defaultPrice);
|
||||
|
||||
const form = this.fb.group({
|
||||
unit_price: [
|
||||
this.initialValues?.unit_price || this.goldDefaultUnitPrice() || 0,
|
||||
[Validators.required, greaterThanValidator(0)],
|
||||
],
|
||||
quantity: [this.initialValues?.quantity || 0, [Validators.required, greaterThanValidator(0)]],
|
||||
discount_amount: [this.initialValues?.discount_amount || 0],
|
||||
discount_percentage: [0, [Validators.max(100), Validators.min(0)]],
|
||||
payload: this.fb.group({
|
||||
commission: [this.initialValues?.payload?.commission || 0, [Validators.required]],
|
||||
commission_percentage: [0, [Validators.required, Validators.max(100), Validators.min(0)]],
|
||||
wages: [this.initialValues?.payload?.wages || 0, [Validators.required]],
|
||||
wages_percentage: [0, [Validators.required, Validators.max(100), Validators.min(0)]],
|
||||
profit: [this.initialValues?.payload?.profit || 0, [Validators.required]],
|
||||
profit_percentage: [0, [Validators.required, Validators.max(100), Validators.min(0)]],
|
||||
karat: [this.initialValues?.payload?.karat || '', [Validators.required]],
|
||||
}),
|
||||
});
|
||||
|
||||
form.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
||||
this.updateCalculateAmount(value as any);
|
||||
});
|
||||
|
||||
form.controls.payload.controls.profit.valueChanges.pipe(takeUntilDestroyed()).subscribe(() => {
|
||||
// if ((form.controls.discount_amount.value || 0) > (value || 0)) {
|
||||
form.controls.discount_amount.setValue(0, { emitEvent: false });
|
||||
// }
|
||||
});
|
||||
form.controls.payload.controls.profit_percentage.valueChanges
|
||||
.pipe(takeUntilDestroyed())
|
||||
.subscribe(() => {
|
||||
form.controls.discount_amount.setValue(0, { emitEvent: false });
|
||||
});
|
||||
|
||||
return form;
|
||||
};
|
||||
|
||||
form = this.initialForm();
|
||||
|
||||
override submitForm(payload: IPosOrderItem) {
|
||||
this.onSubmit.emit({
|
||||
...payload,
|
||||
total_amount: this.totalAmount(),
|
||||
base_total_amount: this.baseTotalAmount(),
|
||||
tax_amount: this.taxAmount(),
|
||||
discount_amount: this.form.value.discount_amount || 0,
|
||||
payload: {
|
||||
commission: this.form.controls.payload.controls.commission.value || 0,
|
||||
karat: this.form.controls.payload.controls.karat.value as TGoldKarat,
|
||||
profit: this.form.controls.payload.controls.profit.value || 0,
|
||||
wages: this.form.controls.payload.controls.wages.value || 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
updateCalculateAmount(payload: Partial<IPosOrderItem<any>>) {
|
||||
const commissionAmount = Number(payload.payload?.commission ?? '0');
|
||||
const wageAmount = Number(payload.payload?.wages ?? '0');
|
||||
const discountAmount = Number(payload.discount_amount ?? '0');
|
||||
const profitAmount = Number(payload.payload?.profit ?? '0');
|
||||
const unitPrice = Number(payload.unit_price ?? '0');
|
||||
const quantity = Number(payload.quantity ?? '0');
|
||||
|
||||
const unitWithQuantity = unitPrice * quantity;
|
||||
const totalAmountBeforeProfit = unitWithQuantity + wageAmount + commissionAmount;
|
||||
const baseTotalAmount = totalAmountBeforeProfit + profitAmount;
|
||||
const baseAmountForDiscountCalculation =
|
||||
this.discountType() === 1 ? profitAmount : unitWithQuantity;
|
||||
|
||||
const taxAmount =
|
||||
(profitAmount +
|
||||
commissionAmount +
|
||||
wageAmount -
|
||||
(this.discountType() === 1 ? discountAmount : 0)) *
|
||||
0.1;
|
||||
const totalAmount = baseTotalAmount - discountAmount + taxAmount;
|
||||
|
||||
this.unitWithQuantity.set(unitWithQuantity);
|
||||
this.totalAmountBeforeProfit.set(totalAmountBeforeProfit);
|
||||
this.baseTotalAmount.set(baseTotalAmount);
|
||||
this.taxAmount.set(taxAmount);
|
||||
this.totalAmount.set(totalAmount);
|
||||
this.baseAmountForDiscountCalculation.set(baseAmountForDiscountCalculation);
|
||||
|
||||
this.onChangeTotalAmount.emit(totalAmount);
|
||||
}
|
||||
|
||||
toAmountFormat(amount: number) {
|
||||
if (!amount) {
|
||||
return '';
|
||||
}
|
||||
return `(${formatWithCurrency(amount)})`;
|
||||
}
|
||||
|
||||
changeDiscountCalculation($event: SelectButtonChangeEvent) {
|
||||
this.discountType.set($event.value);
|
||||
|
||||
this.updateCalculateAmount(this.form.value as any);
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,14 @@
|
||||
(onHide)="close()">
|
||||
@if (good) {
|
||||
@if (isGoldMode()) {
|
||||
<pos-gold-payload-form
|
||||
<shared-gold-payload-form
|
||||
[initialValues]="goldPayload()"
|
||||
[vatPercentage]="vatPercentage()"
|
||||
[editMode]="editMode()"
|
||||
[isRapidInvoice]="isRapidInvoice()"
|
||||
(onSubmit)="submit($event)" />
|
||||
} @else if (isStandardMode()) {
|
||||
<pos-standard-payload-form
|
||||
<shared-standard-payload-form
|
||||
[initialValues]="standardPayload()"
|
||||
[vatPercentage]="vatPercentage()"
|
||||
[measureUnit]="good.measure_unit"
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import { IGoodResponse } from '@/domains/pos/models/good.io';
|
||||
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
|
||||
import { SharedLightBottomsheetComponent } from '@/shared/components/dialog/light-bottomsheet.component';
|
||||
import {
|
||||
SharedGoldPayloadFormComponent,
|
||||
SharedLightBottomsheetComponent,
|
||||
SharedStandardPayloadFormComponent,
|
||||
} from '@/shared/components';
|
||||
import { IGoldPayload, IStandardPayload } from '@/shared/models';
|
||||
import { Component, computed, EventEmitter, inject, Input, Output, signal } from '@angular/core';
|
||||
import { PosConfigRapidInvoiceService } from '../../../configs/components/rapidInvoice/services/main.service';
|
||||
import { IGoldPayload, IPosOrderItem, IStandardPayload } from '../../models';
|
||||
import { IPosOrderItem } from '../../models';
|
||||
import { PosLandingStore } from '../../store/main.store';
|
||||
import { PosGoldPayloadFormComponent } from './gold/form.component';
|
||||
import { PosStandardPayloadFormComponent } from './standard/form.component';
|
||||
|
||||
@Component({
|
||||
selector: 'pos-payload-form-dialog',
|
||||
templateUrl: './payload-form.component.html',
|
||||
imports: [
|
||||
PosGoldPayloadFormComponent,
|
||||
SharedGoldPayloadFormComponent,
|
||||
SharedStandardPayloadFormComponent,
|
||||
SharedLightBottomsheetComponent,
|
||||
PosStandardPayloadFormComponent,
|
||||
],
|
||||
})
|
||||
export class PayloadFormDialogComponent extends AbstractDialog {
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
<form [formGroup]="form" (submit)="submit()">
|
||||
<app-input [control]="form.controls.unit_price" name="unit_price" label="مبلغ واحد" type="price" />
|
||||
<app-input
|
||||
[control]="form.controls.quantity"
|
||||
name="quantity"
|
||||
[label]="measureUnit.name"
|
||||
type="number"
|
||||
[suffix]="measureUnit.name"
|
||||
[min]="0" />
|
||||
|
||||
<app-amount-percentage-input
|
||||
[percentageControl]="form.controls.discount_percentage"
|
||||
[amountControl]="form.controls.discount_amount"
|
||||
[baseAmount]="baseTotalAmount()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="baseTotalAmount()"
|
||||
name="discount"
|
||||
label="تخفیف" />
|
||||
|
||||
<hr />
|
||||
<div class="flex w-full flex-col justify-center gap-4">
|
||||
<pos-form-dialog-amount-card-template
|
||||
[totalAmount]="totalAmount()"
|
||||
[baseTotalAmount]="baseTotalAmount()"
|
||||
[discountAmount]="discountAmount()"
|
||||
[taxAmount]="taxAmount()" />
|
||||
<button pButton class="w-full sm:w-auto" (onClick)="submit()">{{ preparedCTAText() }}</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1,90 +0,0 @@
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { greaterThanValidator } from '@/core/validators';
|
||||
import { AbstractForm } from '@/shared/abstractClasses';
|
||||
import { InputComponent } from '@/shared/components';
|
||||
import { AmountPercentageInputComponent } from '@/shared/components/amountPercentageInput/amount-percentage-input.component';
|
||||
import { formatWithCurrency } from '@/utils';
|
||||
import { Component, computed, EventEmitter, Input, Output, signal } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { IPosOrderItem, IStandardPayload } from '../../../models';
|
||||
import { PosFormDialogAmountCardTemplateComponent } from '../form-dialog-amount-card-template.component';
|
||||
|
||||
@Component({
|
||||
selector: 'pos-standard-payload-form',
|
||||
templateUrl: './form.component.html',
|
||||
imports: [
|
||||
ReactiveFormsModule,
|
||||
InputComponent,
|
||||
PosFormDialogAmountCardTemplateComponent,
|
||||
AmountPercentageInputComponent,
|
||||
ButtonDirective,
|
||||
],
|
||||
})
|
||||
export class PosStandardPayloadFormComponent extends AbstractForm<
|
||||
IPosOrderItem<IStandardPayload>,
|
||||
IPosOrderItem<IStandardPayload>
|
||||
> {
|
||||
@Input({ required: true }) measureUnit!: ISummary;
|
||||
@Input({ required: true }) vatPercentage!: number;
|
||||
@Input() isRapidInvoice!: boolean;
|
||||
@Output() onChangeTotalAmount = new EventEmitter<number>();
|
||||
|
||||
private readonly initialForm = () => {
|
||||
const form = this.fb.group({
|
||||
unit_price: [
|
||||
this.initialValues?.unit_price || 0,
|
||||
[Validators.required, greaterThanValidator(0)],
|
||||
],
|
||||
quantity: [this.initialValues?.quantity || 0, [Validators.required, greaterThanValidator(0)]],
|
||||
discount_amount: [this.initialValues?.discount_amount || 0, [Validators.min(0)]],
|
||||
discount_percentage: [0, [Validators.min(0), Validators.max(100)]],
|
||||
});
|
||||
|
||||
form.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
||||
this.updateCalculateAmount(value as Partial<IPosOrderItem<IStandardPayload>>);
|
||||
});
|
||||
|
||||
return form;
|
||||
};
|
||||
|
||||
form = this.initialForm();
|
||||
override submitForm(payload: IPosOrderItem<IStandardPayload>) {
|
||||
this.onSubmit.emit({
|
||||
...payload,
|
||||
total_amount: this.totalAmount(),
|
||||
discount_amount: this.discountAmount(),
|
||||
tax_amount: this.taxAmount(),
|
||||
base_total_amount: this.baseTotalAmount(),
|
||||
});
|
||||
}
|
||||
|
||||
baseTotalAmount = signal<number>(0);
|
||||
totalAmount = signal<number>(0);
|
||||
discountAmount = signal<number>(0);
|
||||
taxAmount = signal<number>(0);
|
||||
|
||||
preparedCTAText = computed(() =>
|
||||
this.editMode ? 'اعمال ویرایش' : this.isRapidInvoice ? 'ثبت و پرداخت' : 'افزودن به لیست خرید'
|
||||
);
|
||||
|
||||
toPriceFormat(amount: number) {
|
||||
if (!amount) {
|
||||
return '';
|
||||
}
|
||||
return `(${formatWithCurrency(amount)})`;
|
||||
}
|
||||
|
||||
updateCalculateAmount(value: Partial<IPosOrderItem<IStandardPayload>>) {
|
||||
const baseTotalAmount = (value.unit_price ?? 0) * (value.quantity ?? 0);
|
||||
const discountAmount = Number(value.discount_amount ?? '0');
|
||||
const baseTotalAmountWithoutTax = baseTotalAmount - discountAmount;
|
||||
const taxAmount = baseTotalAmountWithoutTax * this.vatPercentage;
|
||||
|
||||
this.baseTotalAmount.set(baseTotalAmount);
|
||||
this.discountAmount.set(discountAmount);
|
||||
this.taxAmount.set(taxAmount);
|
||||
this.totalAmount.set(baseTotalAmountWithoutTax + taxAmount);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
export * from './customer';
|
||||
export * from './io';
|
||||
export * from './payload';
|
||||
export * from './payment';
|
||||
export * from './posPaymentResult';
|
||||
export * from './types';
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { TGoldKarat } from '@/shared/localEnum/constants/goldKarat';
|
||||
|
||||
export interface IGoldPayload {
|
||||
karat: TGoldKarat;
|
||||
wages: number;
|
||||
profit: number;
|
||||
commission: number;
|
||||
}
|
||||
|
||||
export interface IStandardPayload {}
|
||||
|
||||
export type TPosOrderGoodPayload = IGoldPayload | IStandardPayload;
|
||||
@@ -1,6 +1,6 @@
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { IGoodResponse } from '@/domains/pos/models/good.io';
|
||||
import { TPosOrderGoodPayload } from './payload';
|
||||
import { TPosOrderGoodPayload } from '@/shared/models';
|
||||
|
||||
export interface IPosOrderItem<T = TPosOrderGoodPayload> {
|
||||
unit_price: number;
|
||||
|
||||
Reference in New Issue
Block a user