.
This commit is contained in:
parent
fc18ec9fac
commit
e4d403472d
@ -43,7 +43,7 @@ export class ListArticlesUseCase
|
||||
}
|
||||
|
||||
async execute(
|
||||
params: Partial<IListArticlesParams>
|
||||
params: Partial<IListArticlesParams>,
|
||||
): Promise<ListArticlesResult> {
|
||||
const { queryCriteria } = params;
|
||||
|
||||
@ -58,12 +58,11 @@ export class ListArticlesUseCase
|
||||
let products: ICollection<Article> = new Collection();
|
||||
|
||||
try {
|
||||
transaction.complete(async (t) => {
|
||||
await transaction.complete(async (t) => {
|
||||
products = await productRepoBuilder({ transaction: t }).findAll(
|
||||
queryCriteria
|
||||
queryCriteria,
|
||||
);
|
||||
});
|
||||
|
||||
return Result.ok(products);
|
||||
} catch (error: unknown) {
|
||||
const _error = error as IInfrastructureError;
|
||||
@ -71,8 +70,8 @@ export class ListArticlesUseCase
|
||||
handleUseCaseError(
|
||||
UseCaseError.REPOSITORY_ERROR,
|
||||
"Error al listar el catálogo",
|
||||
_error
|
||||
)
|
||||
_error,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,10 +8,11 @@ import {
|
||||
UniqueID,
|
||||
UnitPrice,
|
||||
} from "@shared/contexts";
|
||||
import { ArticleIdentifier } from "./ArticleIdentifier";
|
||||
|
||||
export interface IArticleProps {
|
||||
catalog_name: Slug;
|
||||
id_article: Description;
|
||||
id_article: ArticleIdentifier;
|
||||
reference: Slug;
|
||||
family: Description;
|
||||
subfamily: Description;
|
||||
@ -23,7 +24,7 @@ export interface IArticleProps {
|
||||
export interface IArticle {
|
||||
id: UniqueID;
|
||||
catalog_name: Slug;
|
||||
id_article: Description;
|
||||
id_article: ArticleIdentifier;
|
||||
reference: Slug;
|
||||
family: Description;
|
||||
subfamily: Description;
|
||||
@ -35,7 +36,7 @@ export interface IArticle {
|
||||
export class Article extends AggregateRoot<IArticleProps> implements IArticle {
|
||||
public static create(
|
||||
props: IArticleProps,
|
||||
id?: UniqueID
|
||||
id?: UniqueID,
|
||||
): Result<Article, IDomainError> {
|
||||
//const isNew = !!id === false;
|
||||
|
||||
@ -54,14 +55,14 @@ export class Article extends AggregateRoot<IArticleProps> implements IArticle {
|
||||
}
|
||||
|
||||
get id(): UniqueID {
|
||||
return this.id;
|
||||
return this._id;
|
||||
}
|
||||
|
||||
get catalog_name(): Slug {
|
||||
return this.props.catalog_name;
|
||||
}
|
||||
|
||||
get id_article(): Description {
|
||||
get id_article(): ArticleIdentifier {
|
||||
return this.props.id_article;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,98 @@
|
||||
import {
|
||||
INullableValueObjectOptions,
|
||||
NullableValueObject,
|
||||
Result,
|
||||
RuleValidator,
|
||||
} from "@shared/contexts";
|
||||
import { NullOr } from "@shared/utilities";
|
||||
import Joi from "joi";
|
||||
|
||||
export interface IArticleIdentifierOptions
|
||||
extends INullableValueObjectOptions {}
|
||||
|
||||
export class ArticleIdentifier extends NullableValueObject<number> {
|
||||
protected static validate(
|
||||
value: NullOr<number | string>,
|
||||
options: IArticleIdentifierOptions = {},
|
||||
) {
|
||||
const ruleNull = RuleValidator.RULE_ALLOW_NULL_OR_UNDEFINED.default(null);
|
||||
|
||||
const ruleNumber = RuleValidator.RULE_IS_TYPE_NUMBER.label(
|
||||
options.label ? options.label : "ArticleIdentifier",
|
||||
);
|
||||
|
||||
const ruleString = RuleValidator.RULE_IS_TYPE_STRING.regex(
|
||||
/^[-]?\d+$/,
|
||||
).label(options.label ? options.label : "ArticleIdentifier");
|
||||
|
||||
const rules = Joi.alternatives(ruleNull, ruleNumber, ruleString);
|
||||
|
||||
return RuleValidator.validate<NullOr<number>>(rules, value);
|
||||
}
|
||||
|
||||
public static create(
|
||||
value: NullOr<number | string>,
|
||||
options: IArticleIdentifierOptions = {},
|
||||
) {
|
||||
const _options = {
|
||||
label: "ArticleIdentifier",
|
||||
...options,
|
||||
};
|
||||
|
||||
const validationResult = ArticleIdentifier.validate(value, _options);
|
||||
|
||||
if (validationResult.isFailure) {
|
||||
return Result.fail(validationResult.error);
|
||||
}
|
||||
|
||||
let _value: NullOr<number> = null;
|
||||
|
||||
if (typeof validationResult.object === "string") {
|
||||
_value = parseInt(validationResult.object, 10);
|
||||
} else {
|
||||
_value = validationResult.object;
|
||||
}
|
||||
|
||||
return Result.ok<ArticleIdentifier>(new ArticleIdentifier(_value));
|
||||
}
|
||||
|
||||
public toNumber(): number {
|
||||
return this.isNull() ? 0 : Number(this.value);
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return this.isNull() ? "" : String(this.value);
|
||||
}
|
||||
|
||||
public toPrimitive(): number {
|
||||
return this.toNumber();
|
||||
}
|
||||
|
||||
public increment(amount: number = 1) {
|
||||
const validationResult = ArticleIdentifier.validate(amount);
|
||||
|
||||
if (validationResult.isFailure) {
|
||||
return Result.fail(validationResult.error);
|
||||
}
|
||||
|
||||
if (this.value === null) {
|
||||
return ArticleIdentifier.create(amount);
|
||||
}
|
||||
|
||||
return ArticleIdentifier.create(this.value + amount);
|
||||
}
|
||||
|
||||
public decrement(amount: number = 1) {
|
||||
const validationResult = ArticleIdentifier.validate(amount);
|
||||
|
||||
if (validationResult.isFailure) {
|
||||
return Result.fail(validationResult.error);
|
||||
}
|
||||
|
||||
if (this.value === null) {
|
||||
return ArticleIdentifier.create(amount);
|
||||
}
|
||||
|
||||
return ArticleIdentifier.create(this.value - amount);
|
||||
}
|
||||
}
|
||||
@ -1 +1,2 @@
|
||||
export * from "./Article";
|
||||
export * from "./ArticleIdentifier";
|
||||
|
||||
@ -10,7 +10,11 @@ import {
|
||||
UnitPrice,
|
||||
} from "@shared/contexts";
|
||||
import { ICatalogContext } from "..";
|
||||
import { Article, IArticleProps } from "../../domain/entities";
|
||||
import {
|
||||
Article,
|
||||
ArticleIdentifier,
|
||||
IArticleProps,
|
||||
} from "../../domain/entities";
|
||||
import {
|
||||
Article_Model,
|
||||
TCreationArticle_Attributes,
|
||||
@ -34,14 +38,18 @@ class ArticleMapper
|
||||
protected toDomainMappingImpl(source: Article_Model, params: any): Article {
|
||||
const props: IArticleProps = {
|
||||
catalog_name: this.mapsValue(source, "catalog_name", Slug.create),
|
||||
id_article: this.mapsValue(source, "id_article", Description.create),
|
||||
id_article: this.mapsValue(
|
||||
source,
|
||||
"id_article",
|
||||
ArticleIdentifier.create,
|
||||
),
|
||||
reference: this.mapsValue(source, "reference", Slug.create),
|
||||
family: this.mapsValue(source, "family", Description.create),
|
||||
subfamily: this.mapsValue(source, "subfamily", Description.create),
|
||||
description: this.mapsValue(source, "description", Description.create),
|
||||
points: this.mapsValue(source, "points", Quantity.create),
|
||||
retail_price: this.mapsValue(source, "retail_price", (value: any) =>
|
||||
UnitPrice.create({ amount: value, precision: 4 })
|
||||
UnitPrice.create({ amount: value, precision: 4 }),
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
@ -0,0 +1 @@
|
||||
export * from "./article.mapper";
|
||||
@ -4,6 +4,7 @@ import {
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
Model,
|
||||
Op,
|
||||
Sequelize,
|
||||
} from "sequelize";
|
||||
|
||||
@ -41,13 +42,22 @@ export default (sequelize: Sequelize) => {
|
||||
primaryKey: true,
|
||||
},
|
||||
|
||||
catalog_name: DataTypes.STRING(),
|
||||
id_article: DataTypes.STRING(),
|
||||
catalog_name: {
|
||||
type: DataTypes.STRING(),
|
||||
allowNull: false,
|
||||
},
|
||||
id_article: {
|
||||
type: DataTypes.BIGINT().UNSIGNED,
|
||||
allowNull: false,
|
||||
},
|
||||
reference: DataTypes.STRING(),
|
||||
family: DataTypes.STRING(),
|
||||
subfamily: DataTypes.STRING(),
|
||||
description: DataTypes.STRING(),
|
||||
points: DataTypes.SMALLINT().UNSIGNED,
|
||||
points: {
|
||||
type: DataTypes.SMALLINT().UNSIGNED,
|
||||
defaultValue: 0,
|
||||
},
|
||||
retail_price: DataTypes.BIGINT(),
|
||||
},
|
||||
{
|
||||
@ -69,7 +79,38 @@ export default (sequelize: Sequelize) => {
|
||||
{ name: "family_subfamily_idx", fields: ["family", "subfamily"] },
|
||||
{ name: "updated_at_idx", fields: ["updated_at"] },
|
||||
],
|
||||
}
|
||||
|
||||
scopes: {
|
||||
quickSearch(value) {
|
||||
return {
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{
|
||||
reference: {
|
||||
[Op.like]: `%${value}%`,
|
||||
},
|
||||
},
|
||||
{
|
||||
family: {
|
||||
[Op.like]: `%${value}%`,
|
||||
},
|
||||
},
|
||||
{
|
||||
subfamily: {
|
||||
[Op.like]: `%${value}%`,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: {
|
||||
[Op.like]: `%${value}%`,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return Article_Model;
|
||||
|
||||
@ -0,0 +1 @@
|
||||
export * from "./article.model";
|
||||
@ -15,18 +15,18 @@ export interface IQueryCriteriaServiceProps {
|
||||
sort_by: string;
|
||||
fields: string;
|
||||
filters: string;
|
||||
quick_search: string;
|
||||
q: string;
|
||||
}
|
||||
|
||||
export class QueryCriteriaService extends ApplicationService {
|
||||
public static parse(
|
||||
params: Partial<IQueryCriteriaServiceProps>
|
||||
params: Partial<IQueryCriteriaServiceProps>,
|
||||
): IQueryCriteria {
|
||||
const {
|
||||
page = undefined,
|
||||
limit = undefined,
|
||||
sort_by = undefined,
|
||||
quick_search = undefined,
|
||||
q = undefined,
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
fields = null, // fields / select
|
||||
@ -43,7 +43,7 @@ export class QueryCriteriaService extends ApplicationService {
|
||||
const _order: OrderCriteria = QueryCriteriaService.parseOrder(sort_by);
|
||||
|
||||
const _quickSearch: QuickSearchCriteria =
|
||||
QueryCriteriaService.parseQuickSearch(quick_search);
|
||||
QueryCriteriaService.parseQuickSearch(q);
|
||||
|
||||
return QueryCriteria.create({
|
||||
pagination: _pagination,
|
||||
@ -59,9 +59,10 @@ export class QueryCriteriaService extends ApplicationService {
|
||||
}
|
||||
|
||||
const paginationOrError = OffsetPaging.create({
|
||||
offset: String(page),
|
||||
limit: String(limit),
|
||||
offset: page,
|
||||
limit,
|
||||
});
|
||||
|
||||
if (paginationOrError.isFailure) {
|
||||
throw paginationOrError.error;
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ export class SequelizeQueryBuilder implements ISequelizeQueryBuilder {
|
||||
|
||||
private applyQuickSearch(
|
||||
model: ModelDefined<any, any>,
|
||||
quickSearchCriteria: QuickSearchCriteria
|
||||
quickSearchCriteria: QuickSearchCriteria,
|
||||
): any {
|
||||
let _model = model;
|
||||
if (!quickSearchCriteria.isEmpty()) {
|
||||
|
||||
@ -4,8 +4,8 @@ import { Result } from "../../Result";
|
||||
import { ValueObject } from "../../ValueObject";
|
||||
|
||||
export interface IOffsetPagingProps {
|
||||
offset: number | string;
|
||||
limit: number | string;
|
||||
offset: number | string | undefined;
|
||||
limit: number | string | undefined;
|
||||
}
|
||||
|
||||
export interface IOffsetPaging {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user