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