This commit is contained in:
David Arranz 2024-07-18 12:02:59 +02:00
parent 47802ab932
commit 23cfe70578
10 changed files with 67 additions and 45 deletions

View File

@ -128,6 +128,7 @@ export const QuoteEdit = () => {
const onSubmit: SubmitHandler<QuoteDataForm> = async (data) => {
// Transformación del form -> typo de request
console.log(data);
mutate(data, {
onError: (error) => {
console.debug(error);
@ -163,19 +164,17 @@ export const QuoteEdit = () => {
if (name === "items") {
const { items } = value;
let quoteSubtotal = MoneyValue.create().object;
let quoteSubtotal = MoneyValue.create({
amount: 0,
scale: 4,
}).object;
// Recálculo líneas
items &&
items.map((item, index) => {
const itemTotals = calculateItemTotals(item);
if (itemTotals === null) {
return;
}
quoteSubtotal = quoteSubtotal.add(itemTotals.totalPrice);
setValue(`items.${index}.subtotal_price`, itemTotals.subtotalPrice.toObject());
setValue(`items.${index}.total_price`, itemTotals.totalPrice.toObject());
});
@ -186,15 +185,11 @@ export const QuoteEdit = () => {
if (name.endsWith("quantity") || name.endsWith("unit_price") || name.endsWith("discount")) {
const { items } = value;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [, indexString, fieldName] = String(name).split(".");
const index = parseInt(indexString);
const itemTotals = calculateItemTotals(items[index]);
if (itemTotals === null) {
return;
}
setValue(`items.${index}.subtotal_price`, itemTotals.subtotalPrice.toObject());
setValue(`items.${index}.total_price`, itemTotals.totalPrice.toObject());
@ -206,7 +201,7 @@ export const QuoteEdit = () => {
}, [watch, getValues, setValue]);
if (isSubmitting) {
return <LoadingOverlay />;
return <LoadingOverlay title='Guardando cotización' />;
}
if (status === "error") {

View File

@ -1,13 +1,32 @@
import { MoneyValue, Percentage, Quantity } from "@shared/contexts";
export const calculateItemTotals = (item: any) => {
console.log(item);
const { quantity: quantity_dto, unit_price: unit_price_dto, discount: discount_dto } = item;
/*if (quantity_dto.amount === null || unit_price_dto.amount === null) {
return null;
}*/
if (quantity_dto.amount === null || unit_price_dto.amount === null) {
return {
quantity: Quantity.create({
amount: quantity_dto.amount,
scale: 0,
}).object,
unitPrice: MoneyValue.create({
amount: unit_price_dto.amount,
scale: 4,
}).object,
subtotalPrice: MoneyValue.create({
amount: null,
scale: 4,
}).object,
discount: Percentage.create({
amount: discount_dto.amount,
scale: 2,
}).object,
totalPrice: MoneyValue.create({
amount: null,
scale: 4,
}).object,
};
}
const quantityOrError = Quantity.create(quantity_dto);
if (quantityOrError.isFailure) {

View File

@ -16,6 +16,8 @@ export class ArticleIdentifier extends NullableValueObject<number> {
) {
const ruleNull = RuleValidator.RULE_ALLOW_NULL_OR_UNDEFINED.default(null);
const ruleEmpty = RuleValidator.RULE_ALLOW_EMPTY.default(null);
const ruleNumber = RuleValidator.RULE_IS_TYPE_NUMBER.label(
options.label ? options.label : "ArticleIdentifier"
);
@ -24,11 +26,15 @@ export class ArticleIdentifier extends NullableValueObject<number> {
options.label ? options.label : "ArticleIdentifier"
);
const rules = Joi.alternatives(ruleNull, ruleNumber, ruleString);
const rules = Joi.alternatives(ruleNull, ruleEmpty, ruleNumber, ruleString);
return RuleValidator.validate<NullOr<number>>(rules, value);
}
private static sanitize(value: NullOr<number | string>): NullOr<number> {
return value ? Number(value) : null;
}
public static create(value: NullOr<number | string>, options: IArticleIdentifierOptions = {}) {
const _options = {
label: "ArticleIdentifier",
@ -49,7 +55,7 @@ export class ArticleIdentifier extends NullableValueObject<number> {
_value = validationResult.object;
}
return Result.ok<ArticleIdentifier>(new ArticleIdentifier(_value));
return Result.ok<ArticleIdentifier>(new ArticleIdentifier(ArticleIdentifier.sanitize(_value)));
}
public toNumber(): number {

View File

@ -117,7 +117,6 @@ export class UpdateQuoteUseCase
try {
await transaction.complete(async (t) => {
console.log(t);
quoteRepo = quoteRepository({ transaction: t });
await quoteRepo.update(quote);
});

View File

@ -53,7 +53,9 @@ export class QuoteItem extends Entity<IQuoteItemProps> implements IQuoteItem {
}
get subtotalPrice(): MoneyValue {
return this.unitPrice.multiply(this.quantity.toNumber());
return this.quantity.isNull() || this.unitPrice.isNull()
? MoneyValue.create({ amount: null, scale: 4 }).object
: this.unitPrice.multiply(this.quantity.toNumber());
}
get discount(): Percentage {
@ -61,6 +63,8 @@ export class QuoteItem extends Entity<IQuoteItemProps> implements IQuoteItem {
}
get totalPrice(): MoneyValue {
return this.subtotalPrice.subtract(this.subtotalPrice.percentage(this.discount.toNumber()));
return this.subtotalPrice.isNull()
? MoneyValue.create({ amount: null, scale: 4 }).object
: this.subtotalPrice.subtract(this.subtotalPrice.percentage(this.discount.toNumber()));
}
}

View File

@ -43,7 +43,7 @@ const quoteItemPresenter = (
): IGetQuote_QuoteItem_Response_DTO[] =>
items.totalCount > 0
? items.items.map((item: QuoteItem) => ({
article_id: item.articleId ?? "",
article_id: item.articleId.toString(),
description: item.description.toString(),
quantity: item.quantity.toObject(),
unit_price: item.unitPrice.toObject(),

View File

@ -36,7 +36,7 @@ export const UpdateQuotePresenter: IUpdateQuotePresenter = {
const quoteItemPresenter = (items: ICollection<QuoteItem>, context: ISalesContext) =>
items.totalCount > 0
? items.items.map((item: QuoteItem) => ({
article_id: item.articleId ?? "",
article_id: item.articleId.toString(),
description: item.description.toString(),
quantity: item.quantity.toObject(),
unit_price: item.unitPrice.toObject(),

View File

@ -3,7 +3,7 @@ import DineroFactory, { Currency, Dinero } from "dinero.js";
import Joi from "joi";
import { isNull } from "lodash";
import { NullOr, UndefinedOr } from "../../../../utilities";
import { NullOr } from "../../../../utilities";
import { DomainError, handleDomainError } from "../errors";
import { RuleValidator } from "../RuleValidator";
import { CurrencyData } from "./CurrencyData";
@ -11,12 +11,10 @@ import { Result } from "./Result";
import { IValueObjectOptions, ValueObject } from "./ValueObject";
export interface IMoneyValueOptions extends IValueObjectOptions {
defaultValue?: number;
locale: string;
}
export const defaultMoneyValueOptions: IMoneyValueOptions = {
defaultValue: 0,
locale: "es-ES",
};
@ -50,7 +48,7 @@ const defaultMoneyValueProps = {
};
interface IMoneyValue {
toPrimitive(): UndefinedOr<number>;
toPrimitive(): NullOr<number>;
toPrimitives(): MoneyValueObject;
isEmpty(): boolean;
toString(): string;
@ -92,9 +90,6 @@ export class MoneyValue extends ValueObject<Dinero> implements IMoneyValue {
public static readonly DEFAULT_SCALE = defaultMoneyValueProps.scale;
public static readonly DEFAULT_CURRENCY_CODE = defaultMoneyValueProps.currencyCode;
private static readonly MIN_VALUE = Number.MIN_VALUE;
private static readonly MAX_VALUE = Number.MAX_VALUE;
private readonly _isNull: boolean;
private readonly _options: IMoneyValueOptions;
@ -103,12 +98,7 @@ export class MoneyValue extends ValueObject<Dinero> implements IMoneyValue {
.optional() // <- undefined
.valid(null); // <- null
const ruleNumber = Joi.number()
.optional()
.default(0)
.min(-1000)
.max(this.MAX_VALUE)
.label(options.label ? options.label : "amount");
const ruleNumber = Joi.number().label(options.label ? options.label : "amount");
const rules = Joi.alternatives(ruleNull, ruleNumber);
@ -154,7 +144,7 @@ export class MoneyValue extends ValueObject<Dinero> implements IMoneyValue {
const _currency = CurrencyData.createFromCode(currencyCode).object.code;
const prop = DineroFactory({
amount: !isNull(_amount) ? Number(_amount) : options.defaultValue,
amount: Number(_amount),
currency: _currency as Currency,
precision: scale,
}).setLocale(options.locale);
@ -287,8 +277,8 @@ export class MoneyValue extends ValueObject<Dinero> implements IMoneyValue {
return this._isNull ? {} : this.props?.toJSON();
}
public toPrimitive(): UndefinedOr<number> {
return this._isNull ? undefined : Number(this.props?.getAmount());
public toPrimitive(): NullOr<number> {
return this._isNull ? null : Number(this.props?.getAmount());
}
public toPrimitives(): MoneyValueObject {
@ -308,7 +298,16 @@ export class MoneyValue extends ValueObject<Dinero> implements IMoneyValue {
}
public convertScale(newScale: number, roundingMode: RoundingMode = "HALF_UP"): MoneyValue {
return MoneyValue.createFromDinero(this.props.convertPrecision(newScale, roundingMode)).object;
if (this._isNull) {
return MoneyValue.create({
amount: null,
scale: newScale,
currencyCode: this.getCurrency().code,
}).object;
} else {
return MoneyValue.createFromDinero(this.props.convertPrecision(newScale, roundingMode))
.object;
}
}
public getCurrency(): CurrencyData {

View File

@ -22,7 +22,7 @@ interface IPercentage {
}
export interface PercentageObject {
amount: number;
amount: number | null;
scale: number;
}
@ -259,7 +259,7 @@ export class Percentage extends NullableValueObject<IPercentage> {
public toObject(): PercentageObject {
return {
amount: this.isNull() ? 0 : Number(this.amount),
amount: this.amount,
scale: this.scale,
};
}

View File

@ -195,7 +195,7 @@ export class Quantity extends NullableValueObject<IQuantity> {
}
get scale(): number {
return this.isNull() ? 0 : Number(this.props?.scale);
return Number(this.props?.scale);
}
public getAmount(): NullOr<number> {