@merkaly/api 0.2.4-5 → 0.2.4-7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.DS_Store +0 -0
- package/.bin/deploy.sh +9 -0
- package/.bin/package.sh +7 -0
- package/.docker/Dockerfile +21 -0
- package/.dockerignore +12 -0
- package/.env +21 -0
- package/.eslintignore +8 -0
- package/.eslintrc.js +35 -0
- package/.github/dependabot.yml +17 -0
- package/.github/semantic.yml +5 -0
- package/.github/workflows/pull_request.yml +35 -0
- package/.gitignore +42 -0
- package/.husky/.gitignore +1 -0
- package/.husky/commit-msg +5 -0
- package/.husky/common.sh +8 -0
- package/.husky/pre-commit +5 -0
- package/.husky/pre-push +4 -0
- package/.idea/.gitignore +5 -0
- package/.idea/api.iml +13 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/inspectionProfiles/Project_Default.xml +11 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +12 -0
- package/.idea/workspace.xml +2320 -0
- package/.output/modules/sales/orders/billing/billing.entity.d.ts +8 -6
- package/.output/modules/sales/orders/billing/billing.entity.js +14 -9
- package/.output/modules/sales/orders/billing/billing.types.d.ts +9 -0
- package/.output/modules/sales/orders/billing/billing.types.js +14 -0
- package/.output/modules/sales/orders/billing/billing.validator.d.ts +6 -10
- package/.output/modules/sales/orders/billing/billing.validator.js +10 -15
- package/.output/modules/sales/orders/{address → billing/entities}/address.entity.d.ts +2 -1
- package/.output/modules/sales/orders/{address → billing/entities}/address.entity.js +17 -17
- package/.output/modules/sales/orders/billing/entities/customer.entity.d.ts +5 -0
- package/.output/modules/sales/orders/billing/entities/customer.entity.js +52 -0
- package/.output/modules/sales/orders/billing/entities/status.entity.d.ts +6 -0
- package/.output/modules/sales/orders/billing/entities/status.entity.js +37 -0
- package/.output/modules/sales/orders/{address → billing/validators}/address.validator.d.ts +2 -1
- package/.output/modules/sales/orders/{address → billing/validators}/address.validator.js +12 -14
- package/.output/modules/sales/orders/billing/validators/customer.validator.d.ts +5 -0
- package/.output/modules/sales/orders/billing/validators/customer.validator.js +36 -0
- package/.output/modules/sales/orders/customer/customer.validator.d.ts +1 -1
- package/.output/modules/sales/orders/customer/customer.validator.js +8 -8
- package/.output/modules/sales/orders/order.entity.d.ts +1 -1
- package/.output/modules/sales/orders/order.validator.d.ts +2 -2
- package/.output/modules/sales/orders/order.validator.js +3 -4
- package/.output/modules/sales/orders/shipping/entities/address.entity.d.ts +10 -0
- package/.output/modules/sales/orders/shipping/entities/address.entity.js +68 -0
- package/.output/modules/sales/orders/shipping/entities/customer.entity.d.ts +5 -0
- package/.output/modules/sales/orders/shipping/entities/customer.entity.js +52 -0
- package/.output/modules/sales/orders/shipping/entities/status.entity.d.ts +6 -0
- package/.output/modules/sales/orders/shipping/entities/status.entity.js +37 -0
- package/.output/modules/sales/orders/shipping/shipping.entity.d.ts +8 -6
- package/.output/modules/sales/orders/shipping/shipping.entity.js +14 -9
- package/.output/modules/sales/orders/shipping/shipping.types.d.ts +11 -0
- package/.output/modules/sales/orders/shipping/shipping.types.js +16 -0
- package/.output/modules/sales/orders/shipping/shipping.validator.d.ts +6 -9
- package/.output/modules/sales/orders/shipping/shipping.validator.js +10 -14
- package/.output/modules/sales/orders/shipping/validators/address.validator.d.ts +10 -0
- package/.output/modules/sales/orders/shipping/validators/address.validator.js +56 -0
- package/.output/modules/sales/orders/shipping/validators/customer.validator.d.ts +5 -0
- package/.output/modules/sales/orders/shipping/validators/customer.validator.js +36 -0
- package/authCertificate.pem +19 -0
- package/cloudbuild.yaml +20 -0
- package/commitlint.config.js +3 -0
- package/jest.config.js +14 -0
- package/merkaly-api-0.2.4-6.tgz +0 -0
- package/nest-cli.json +9 -0
- package/package.json +8 -7
- package/serviceAccount.json +7 -0
- package/src/abstract/absctract.listener.ts +2 -0
- package/src/abstract/abstract.controller.ts +27 -0
- package/src/abstract/abstract.entity.ts +19 -0
- package/src/abstract/abstract.exception.ts +56 -0
- package/src/abstract/abstract.fixture.ts +7 -0
- package/src/abstract/abstract.migration.ts +13 -0
- package/src/abstract/abstract.repository.ts +79 -0
- package/src/abstract/abstract.router.ts +7 -0
- package/src/abstract/abstract.validator.ts +62 -0
- package/src/app.config.ts +57 -0
- package/src/app.console.ts +30 -0
- package/src/app.controller.ts +48 -0
- package/src/app.migration.ts +7 -0
- package/src/app.module.ts +92 -0
- package/src/app.strategy.ts +25 -0
- package/src/commands/assets.command.ts +38 -0
- package/src/commands/deploy.command.ts +6 -0
- package/src/commands/fixture.command.ts +11 -0
- package/src/commands/generate.command.ts +286 -0
- package/src/decorators/public.decorator.ts +5 -0
- package/src/decorators/user.decorator.ts +21 -0
- package/src/exceptions/missing-identity.exception.ts +11 -0
- package/src/exceptions/store-not-implemented.exception.ts +13 -0
- package/src/exceptions/store-not-recognized.exception.ts +11 -0
- package/src/guards/auth.guard.ts +43 -0
- package/src/guards/organization.guard.ts +39 -0
- package/src/interceptors/mongo.interceptor.ts +16 -0
- package/src/main.ts +37 -0
- package/src/middlewares/logger.middleware.ts +15 -0
- package/src/middlewares/organization.middleware.ts +76 -0
- package/src/migrations/1667226478717-product_price_enhance.ts +29 -0
- package/src/migrations/1667329249561-product_add_seo_code_dimension.ts +37 -0
- package/src/migrations/1667601099139-product_activve_and_hashtag.ts +35 -0
- package/src/migrations/1668136428972-content_banners-use-as-image.ts +56 -0
- package/src/migrations/1680483744321-order-billing-shipping-status.ts +32 -0
- package/src/modules/assets/asset.controller.ts +33 -0
- package/src/modules/assets/asset.entity.ts +26 -0
- package/src/modules/assets/asset.module.ts +21 -0
- package/src/modules/assets/asset.repository.ts +51 -0
- package/src/modules/assets/asset.schema.ts +4 -0
- package/src/modules/assets/asset.service.ts +41 -0
- package/src/modules/auth/auth.controller.ts +42 -0
- package/src/modules/auth/auth.module.ts +18 -0
- package/src/modules/auth/logout.ts +0 -0
- package/src/modules/command.module.ts +19 -0
- package/src/modules/content/banners/banner.controller.ts +56 -0
- package/src/modules/content/banners/banner.entity.ts +17 -0
- package/src/modules/content/banners/banner.fixture.ts +19 -0
- package/src/modules/content/banners/banner.listener.ts +6 -0
- package/src/modules/content/banners/banner.module.ts +21 -0
- package/src/modules/content/banners/banner.repository.ts +38 -0
- package/src/modules/content/banners/banner.schema.ts +4 -0
- package/src/modules/content/banners/banner.types.ts +7 -0
- package/src/modules/content/banners/banner.validator.ts +19 -0
- package/src/modules/content/content.module.ts +20 -0
- package/src/modules/content/pages/page.controller.ts +53 -0
- package/src/modules/content/pages/page.entity.ts +27 -0
- package/src/modules/content/pages/page.fixture.ts +19 -0
- package/src/modules/content/pages/page.listener.ts +6 -0
- package/src/modules/content/pages/page.module.ts +21 -0
- package/src/modules/content/pages/page.repository.ts +44 -0
- package/src/modules/content/pages/page.schema.ts +4 -0
- package/src/modules/content/pages/page.types.ts +9 -0
- package/src/modules/content/pages/page.validator.ts +29 -0
- package/src/modules/global.module.ts +70 -0
- package/src/modules/insight/controllers/address.controller.ts +29 -0
- package/src/modules/insight/controllers/order.controller.ts +70 -0
- package/src/modules/insight/controllers/products.controller.ts +18 -0
- package/src/modules/insight/insight.module.ts +24 -0
- package/src/modules/insight/validators/order.validator.ts +10 -0
- package/src/modules/inventory/brands/brand.controller.ts +59 -0
- package/src/modules/inventory/brands/brand.entity.ts +14 -0
- package/src/modules/inventory/brands/brand.exception.ts +9 -0
- package/src/modules/inventory/brands/brand.listener.ts +18 -0
- package/src/modules/inventory/brands/brand.module.ts +19 -0
- package/src/modules/inventory/brands/brand.repository.ts +39 -0
- package/src/modules/inventory/brands/brand.schema.ts +4 -0
- package/src/modules/inventory/brands/brand.validator.ts +23 -0
- package/src/modules/inventory/categories/category.controller.ts +59 -0
- package/src/modules/inventory/categories/category.entity.ts +21 -0
- package/src/modules/inventory/categories/category.exception.ts +9 -0
- package/src/modules/inventory/categories/category.fixture.ts +18 -0
- package/src/modules/inventory/categories/category.listener.ts +17 -0
- package/src/modules/inventory/categories/category.module.ts +19 -0
- package/src/modules/inventory/categories/category.repository.ts +40 -0
- package/src/modules/inventory/categories/category.schema.ts +4 -0
- package/src/modules/inventory/categories/category.validator.ts +30 -0
- package/src/modules/inventory/inventory.module.ts +22 -0
- package/src/modules/inventory/products/entities/code.entity.ts +15 -0
- package/src/modules/inventory/products/entities/dimension.entity.ts +18 -0
- package/src/modules/inventory/products/entities/price.entity.ts +12 -0
- package/src/modules/inventory/products/entities/seo.entity.ts +15 -0
- package/src/modules/inventory/products/product.controller.ts +59 -0
- package/src/modules/inventory/products/product.entity.ts +53 -0
- package/src/modules/inventory/products/product.exception.ts +9 -0
- package/src/modules/inventory/products/product.fixture.ts +19 -0
- package/src/modules/inventory/products/product.listener.ts +27 -0
- package/src/modules/inventory/products/product.module.ts +20 -0
- package/src/modules/inventory/products/product.repository.ts +108 -0
- package/src/modules/inventory/products/product.schema.ts +15 -0
- package/src/modules/inventory/products/product.validator.ts +71 -0
- package/src/modules/inventory/products/validators/code.validator.ts +15 -0
- package/src/modules/inventory/products/validators/dimension.validator.ts +19 -0
- package/src/modules/inventory/products/validators/price.validator.ts +10 -0
- package/src/modules/inventory/products/validators/seo.validator.ts +15 -0
- package/src/modules/inventory/properties/property.controller.ts +56 -0
- package/src/modules/inventory/properties/property.entity.ts +18 -0
- package/src/modules/inventory/properties/property.exception.ts +9 -0
- package/src/modules/inventory/properties/property.listener.ts +20 -0
- package/src/modules/inventory/properties/property.module.ts +21 -0
- package/src/modules/inventory/properties/property.repository.ts +23 -0
- package/src/modules/inventory/properties/property.schema.ts +4 -0
- package/src/modules/inventory/properties/property.validator.ts +27 -0
- package/src/modules/sales/clients/client.controller.ts +60 -0
- package/src/modules/sales/clients/client.entity.ts +25 -0
- package/src/modules/sales/clients/client.exception.ts +9 -0
- package/src/modules/sales/clients/client.listener.ts +20 -0
- package/src/modules/sales/clients/client.module.ts +19 -0
- package/src/modules/sales/clients/client.repository.ts +37 -0
- package/src/modules/sales/clients/client.schema.ts +4 -0
- package/src/modules/sales/clients/client.validator.ts +43 -0
- package/src/modules/sales/orders/billing/billing.entity.ts +22 -0
- package/src/modules/sales/orders/billing/billing.types.ts +10 -0
- package/src/modules/sales/orders/billing/billing.validator.ts +21 -0
- package/src/modules/sales/orders/billing/entities/address.entity.ts +27 -0
- package/src/modules/sales/orders/billing/entities/customer.entity.ts +14 -0
- package/src/modules/sales/orders/billing/entities/status.entity.ts +16 -0
- package/src/modules/sales/orders/billing/validators/address.validator.ts +28 -0
- package/src/modules/sales/orders/billing/validators/customer.validator.ts +14 -0
- package/src/modules/sales/orders/customer/customer.entity.ts +14 -0
- package/src/modules/sales/orders/customer/customer.validator.ts +14 -0
- package/src/modules/sales/orders/item/item.entity.ts +21 -0
- package/src/modules/sales/orders/item/item.schema.ts +8 -0
- package/src/modules/sales/orders/item/item.validator.ts +10 -0
- package/src/modules/sales/orders/order.controller.ts +93 -0
- package/src/modules/sales/orders/order.entity.ts +47 -0
- package/src/modules/sales/orders/order.listener.ts +20 -0
- package/src/modules/sales/orders/order.module.ts +19 -0
- package/src/modules/sales/orders/order.repository.ts +189 -0
- package/src/modules/sales/orders/order.schema.ts +35 -0
- package/src/modules/sales/orders/order.validator.ts +72 -0
- package/src/modules/sales/orders/shipping/entities/address.entity.ts +27 -0
- package/src/modules/sales/orders/shipping/entities/customer.entity.ts +14 -0
- package/src/modules/sales/orders/shipping/entities/status.entity.ts +16 -0
- package/src/modules/sales/orders/shipping/shipping.entity.ts +25 -0
- package/src/modules/sales/orders/shipping/shipping.types.ts +12 -0
- package/src/modules/sales/orders/shipping/shipping.validator.ts +25 -0
- package/src/modules/sales/orders/shipping/validators/address.validator.ts +28 -0
- package/src/modules/sales/orders/shipping/validators/customer.validator.ts +14 -0
- package/src/modules/sales/orders/status/status.entity.ts +16 -0
- package/src/modules/sales/orders/status/status.validator.ts +8 -0
- package/src/modules/sales/sales.module.ts +20 -0
- package/src/modules/setting/connections/connection.controller.ts +27 -0
- package/src/modules/setting/connections/connection.module.ts +17 -0
- package/src/modules/setting/connections/connection.validator.ts +15 -0
- package/src/modules/setting/layout/layout.controller.ts +34 -0
- package/src/modules/setting/layout/layout.entity.ts +13 -0
- package/src/modules/setting/layout/layout.listener.ts +7 -0
- package/src/modules/setting/layout/layout.module.ts +21 -0
- package/src/modules/setting/layout/layout.repository.ts +29 -0
- package/src/modules/setting/layout/layout.schema.ts +4 -0
- package/src/modules/setting/members/member.controller.ts +22 -0
- package/src/modules/setting/members/member.module.ts +17 -0
- package/src/modules/setting/members/member.validator.ts +3 -0
- package/src/modules/setting/organization/organization.controller.ts +33 -0
- package/src/modules/setting/organization/organization.entity.ts +27 -0
- package/src/modules/setting/organization/organization.listener.ts +46 -0
- package/src/modules/setting/organization/organization.module.ts +21 -0
- package/src/modules/setting/organization/organization.repository.ts +55 -0
- package/src/modules/setting/organization/organization.types.ts +65 -0
- package/src/modules/setting/organization/organization.validator.ts +56 -0
- package/src/modules/setting/setting.module.ts +23 -0
- package/src/modules/setting/theme/theme.controller.ts +34 -0
- package/src/modules/setting/theme/theme.entity.ts +13 -0
- package/src/modules/setting/theme/theme.listener.ts +6 -0
- package/src/modules/setting/theme/theme.module.ts +21 -0
- package/src/modules/setting/theme/theme.repository.ts +23 -0
- package/src/modules/setting/theme/theme.schema.ts +4 -0
- package/src/modules/users/user.controller.ts +75 -0
- package/src/modules/users/user.module.ts +20 -0
- package/src/modules/users/user.validator.ts +28 -0
- package/src/providers/auth0.provider.ts +36 -0
- package/src/providers/storage.provider.ts +22 -0
- package/src/services/auth0.service.ts +7 -0
- package/src/services/logger.service.ts +33 -0
- package/src/services/mongo.service.ts +44 -0
- package/src/services/storage.service.ts +39 -0
- package/src/types.ts +19 -0
- package/tsconfig.json +40 -0
- package/tsconfig.package.json +20 -0
- package/yarn.lock +8782 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Prop, Schema } from '@nestjs/mongoose';
|
|
2
|
+
import { Schema as MongoSchema, Types } from 'mongoose';
|
|
3
|
+
import { AbstractEntity } from '../../../abstract/abstract.entity';
|
|
4
|
+
import { PropertyEntity } from '../properties/property.entity';
|
|
5
|
+
|
|
6
|
+
@Schema({ timestamps: true })
|
|
7
|
+
export class CategoryEntity extends AbstractEntity {
|
|
8
|
+
public static readonly $index = 'inventory_categories';
|
|
9
|
+
|
|
10
|
+
@Prop({ type: MongoSchema.Types.String, length: 32, unique: true, required: true })
|
|
11
|
+
public name: string;
|
|
12
|
+
|
|
13
|
+
@Prop({ type: MongoSchema.Types.String })
|
|
14
|
+
public description: string;
|
|
15
|
+
|
|
16
|
+
@Prop({ type: MongoSchema.Types.String, length: 32, default: 'tag' })
|
|
17
|
+
public icon: string;
|
|
18
|
+
|
|
19
|
+
@Prop({ type: [{ type: Types.ObjectId, ref: PropertyEntity.$index }] })
|
|
20
|
+
public properties: PropertyEntity[] = [];
|
|
21
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Catch, HttpException } from '@nestjs/common';
|
|
2
|
+
import { AbstractException } from '../../../abstract/abstract.exception';
|
|
3
|
+
|
|
4
|
+
@Catch()
|
|
5
|
+
export class CategoryException extends AbstractException {
|
|
6
|
+
public handleError(exception: HttpException) {
|
|
7
|
+
return exception;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AbstractFixture } from '../../../abstract/abstract.fixture';
|
|
2
|
+
import { CategoryEntity } from "./category.entity";
|
|
3
|
+
|
|
4
|
+
export class CategoryFixture extends AbstractFixture {
|
|
5
|
+
|
|
6
|
+
public normal() {
|
|
7
|
+
const category = new CategoryEntity({
|
|
8
|
+
_id: this.$faker.datatype.uuid(),
|
|
9
|
+
createdAt: this.$faker.date.past(1),
|
|
10
|
+
updatedAt: this.$faker.date.past(1),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
category.name = this.$faker.vehicle.manufacturer();
|
|
14
|
+
category.description = this.$faker.lorem.sentence();
|
|
15
|
+
|
|
16
|
+
return category;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { AbsctractListener } from '../../../abstract/absctract.listener';
|
|
3
|
+
|
|
4
|
+
export enum CategoryEvent {
|
|
5
|
+
PRE_CREATE = 'database.inventory.category.create.pre',
|
|
6
|
+
POST_CREATE = 'database.inventory.category.create.post',
|
|
7
|
+
|
|
8
|
+
PRE_UPDATE = 'database.inventory.category.update.pre',
|
|
9
|
+
POST_UPDATE = 'database.inventory.category.update.post',
|
|
10
|
+
|
|
11
|
+
PRE_DELETE = 'database.inventory.category.delete.pre',
|
|
12
|
+
POST_DELETE = 'database.inventory.category.delete.post',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class CategoryListener extends AbsctractListener {
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Module, ModuleMetadata } from '@nestjs/common';
|
|
2
|
+
import { AbstractRouter } from '../../../abstract/abstract.router';
|
|
3
|
+
import { CategoryController } from './category.controller';
|
|
4
|
+
import { CategoryListener } from './category.listener';
|
|
5
|
+
import { CategoryRepository } from './category.repository';
|
|
6
|
+
|
|
7
|
+
export const metadata: ModuleMetadata = {
|
|
8
|
+
imports: [],
|
|
9
|
+
controllers: [CategoryController],
|
|
10
|
+
providers: [CategoryRepository, CategoryListener],
|
|
11
|
+
exports: [CategoryRepository],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
@Module(metadata)
|
|
15
|
+
export class CategoryModule extends AbstractRouter {
|
|
16
|
+
public static readonly path = '/categories';
|
|
17
|
+
|
|
18
|
+
public static readonly module = CategoryModule;
|
|
19
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { InjectModel } from '@nestjs/mongoose';
|
|
3
|
+
import { Model, UpdateQuery } from 'mongoose';
|
|
4
|
+
import { AbstractRepository } from '../../../abstract/abstract.repository';
|
|
5
|
+
import { CategoryEntity } from './category.entity';
|
|
6
|
+
import { CreateCategoryValidator, UpdateCategoryValidator } from './category.validator';
|
|
7
|
+
|
|
8
|
+
@Injectable()
|
|
9
|
+
export class CategoryRepository extends AbstractRepository<CategoryEntity> {
|
|
10
|
+
@InjectModel(CategoryEntity.$index)
|
|
11
|
+
public readonly $model: Model<CategoryEntity>;
|
|
12
|
+
|
|
13
|
+
public async create(validator: CreateCategoryValidator) {
|
|
14
|
+
const category = new this.$model();
|
|
15
|
+
|
|
16
|
+
category.name = validator.name;
|
|
17
|
+
category.description = validator.description;
|
|
18
|
+
category.icon = validator.icon;
|
|
19
|
+
|
|
20
|
+
return super.$create(category);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public async update(id: string, validator: UpdateCategoryValidator) {
|
|
24
|
+
const category = await this.$model.findById(id);
|
|
25
|
+
|
|
26
|
+
const query: UpdateQuery<CategoryEntity> = {
|
|
27
|
+
$set: {
|
|
28
|
+
name: validator.name || category.name,
|
|
29
|
+
icon: validator.icon,
|
|
30
|
+
description: validator.description || category.description,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return super.$update(id, query);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public async delete(id: string): Promise<void> {
|
|
38
|
+
return super.$delete(id);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { IsOptional, IsString, Length } from 'class-validator';
|
|
2
|
+
import { AbstractValidator } from "../../../abstract/abstract.validator";
|
|
3
|
+
|
|
4
|
+
export class CreateCategoryValidator extends AbstractValidator {
|
|
5
|
+
@IsString()
|
|
6
|
+
@Length(5, 32)
|
|
7
|
+
public name: string;
|
|
8
|
+
|
|
9
|
+
@IsString()
|
|
10
|
+
@IsOptional()
|
|
11
|
+
public description?: string;
|
|
12
|
+
|
|
13
|
+
@IsString()
|
|
14
|
+
@IsOptional()
|
|
15
|
+
public icon = 'tag';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class UpdateCategoryValidator extends AbstractValidator {
|
|
19
|
+
@IsString()
|
|
20
|
+
@IsOptional()
|
|
21
|
+
public name: string;
|
|
22
|
+
|
|
23
|
+
@IsString()
|
|
24
|
+
@IsOptional()
|
|
25
|
+
public description?: string;
|
|
26
|
+
|
|
27
|
+
@IsString()
|
|
28
|
+
@IsOptional()
|
|
29
|
+
public icon = 'tag';
|
|
30
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Module, ModuleMetadata } from '@nestjs/common';
|
|
2
|
+
import { AbstractRouter } from '../../abstract/abstract.router';
|
|
3
|
+
import { BrandModule } from './brands/brand.module';
|
|
4
|
+
import { CategoryModule } from './categories/category.module';
|
|
5
|
+
import { ProductModule } from './products/product.module';
|
|
6
|
+
import { PropertyModule } from './properties/property.module';
|
|
7
|
+
|
|
8
|
+
export const metadata: ModuleMetadata = {
|
|
9
|
+
imports: [BrandModule, CategoryModule, ProductModule, PropertyModule],
|
|
10
|
+
controllers: [],
|
|
11
|
+
providers: [],
|
|
12
|
+
exports: [BrandModule, CategoryModule, ProductModule, PropertyModule],
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
@Module(metadata)
|
|
16
|
+
export class InventoryModule extends AbstractRouter {
|
|
17
|
+
public static readonly path = '/inventory';
|
|
18
|
+
|
|
19
|
+
public static readonly module = InventoryModule;
|
|
20
|
+
|
|
21
|
+
public static readonly children = metadata.imports;
|
|
22
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Prop } from '@nestjs/mongoose';
|
|
2
|
+
import { Schema as Collection } from '@nestjs/mongoose/dist/decorators/schema.decorator';
|
|
3
|
+
import { Schema } from 'mongoose';
|
|
4
|
+
|
|
5
|
+
@Collection()
|
|
6
|
+
export class CodeEntity extends Map {
|
|
7
|
+
@Prop({ type: Schema.Types.String })
|
|
8
|
+
public sku: string;
|
|
9
|
+
|
|
10
|
+
@Prop({ type: Schema.Types.String })
|
|
11
|
+
public gtin: string;
|
|
12
|
+
|
|
13
|
+
@Prop({ type: Schema.Types.String })
|
|
14
|
+
public mpn: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Prop } from '@nestjs/mongoose';
|
|
2
|
+
import { Schema as Collection } from '@nestjs/mongoose/dist/decorators/schema.decorator';
|
|
3
|
+
import { Schema } from 'mongoose';
|
|
4
|
+
|
|
5
|
+
@Collection()
|
|
6
|
+
export class DimensionEntity extends Map {
|
|
7
|
+
@Prop({ type: Schema.Types.Number })
|
|
8
|
+
public weight: number;
|
|
9
|
+
|
|
10
|
+
@Prop({ type: Schema.Types.Number })
|
|
11
|
+
public height: number;
|
|
12
|
+
|
|
13
|
+
@Prop({ type: Schema.Types.Number })
|
|
14
|
+
public width: number;
|
|
15
|
+
|
|
16
|
+
@Prop({ type: Schema.Types.Number })
|
|
17
|
+
public depth: number;
|
|
18
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Prop } from '@nestjs/mongoose';
|
|
2
|
+
import { Schema as Collection } from '@nestjs/mongoose/dist/decorators/schema.decorator';
|
|
3
|
+
import { Schema } from 'mongoose';
|
|
4
|
+
|
|
5
|
+
@Collection()
|
|
6
|
+
export class PriceEntity extends Map {
|
|
7
|
+
@Prop({ type: Schema.Types.Number, required: true })
|
|
8
|
+
public sale: number;
|
|
9
|
+
|
|
10
|
+
@Prop({ type: Schema.Types.Number })
|
|
11
|
+
public purchase: number;
|
|
12
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Prop } from '@nestjs/mongoose';
|
|
2
|
+
import { Schema as Collection } from '@nestjs/mongoose/dist/decorators/schema.decorator';
|
|
3
|
+
import { Schema } from 'mongoose';
|
|
4
|
+
|
|
5
|
+
@Collection()
|
|
6
|
+
export class SeoEntity extends Map {
|
|
7
|
+
@Prop({ type: Schema.Types.String })
|
|
8
|
+
public title: string;
|
|
9
|
+
|
|
10
|
+
@Prop({ type: Schema.Types.String })
|
|
11
|
+
public slug: string;
|
|
12
|
+
|
|
13
|
+
@Prop({ type: Schema.Types.String })
|
|
14
|
+
public description: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Body,
|
|
3
|
+
Controller,
|
|
4
|
+
Delete,
|
|
5
|
+
Get,
|
|
6
|
+
HttpCode,
|
|
7
|
+
HttpStatus,
|
|
8
|
+
Inject,
|
|
9
|
+
Param,
|
|
10
|
+
Patch,
|
|
11
|
+
Post,
|
|
12
|
+
Query,
|
|
13
|
+
UseFilters,
|
|
14
|
+
} from '@nestjs/common';
|
|
15
|
+
import { ApiTags } from '@nestjs/swagger';
|
|
16
|
+
import { AbstractController } from '../../../abstract/abstract.controller';
|
|
17
|
+
import { FindValidator } from '../../../abstract/abstract.validator';
|
|
18
|
+
import { ProductEntity } from './product.entity';
|
|
19
|
+
import { ProductException } from './product.exception';
|
|
20
|
+
import { ProductRepository } from './product.repository';
|
|
21
|
+
import { CreateProductValidator, UpdateProductValidator } from './product.validator';
|
|
22
|
+
import { Public } from "../../../decorators/public.decorator";
|
|
23
|
+
|
|
24
|
+
@Controller()
|
|
25
|
+
@UseFilters(ProductException)
|
|
26
|
+
@ApiTags('inventory')
|
|
27
|
+
export class ProductController extends AbstractController<ProductEntity> {
|
|
28
|
+
@Inject()
|
|
29
|
+
protected readonly $repository: ProductRepository;
|
|
30
|
+
|
|
31
|
+
@Get('/')
|
|
32
|
+
@Public()
|
|
33
|
+
public async find(@Query() validator: FindValidator<ProductEntity>) {
|
|
34
|
+
return super.find(validator);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@Post('/')
|
|
38
|
+
@HttpCode(HttpStatus.CREATED)
|
|
39
|
+
public async create(@Body() validator: CreateProductValidator) {
|
|
40
|
+
return this.$repository.create(validator);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Get('/:id')
|
|
44
|
+
@Public()
|
|
45
|
+
public async read(@Param('id') id: string, @Query() validator: FindValidator<ProductEntity>) {
|
|
46
|
+
return this.$repository.read(id, validator);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@Patch('/:id')
|
|
50
|
+
public async update(@Param('id') id: string, @Body() validator: UpdateProductValidator) {
|
|
51
|
+
return this.$repository.update(id, validator);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@Delete('/:id')
|
|
55
|
+
@HttpCode(HttpStatus.NO_CONTENT)
|
|
56
|
+
public async delete(@Param('id') id: string) {
|
|
57
|
+
return this.$repository.delete(id);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Prop, Schema as Collection } from '@nestjs/mongoose';
|
|
2
|
+
import { Schema } from 'mongoose';
|
|
3
|
+
import { AbstractEntity } from '../../../abstract/abstract.entity';
|
|
4
|
+
import { AssetEntity } from '../../assets/asset.entity';
|
|
5
|
+
import { BrandEntity } from '../brands/brand.entity';
|
|
6
|
+
import { CategoryEntity } from '../categories/category.entity';
|
|
7
|
+
import { CodeEntity } from './entities/code.entity';
|
|
8
|
+
import { DimensionEntity } from './entities/dimension.entity';
|
|
9
|
+
import { PriceEntity } from './entities/price.entity';
|
|
10
|
+
import { SeoEntity } from './entities/seo.entity';
|
|
11
|
+
|
|
12
|
+
@Collection({ timestamps: true, toJSON: { virtuals: true } })
|
|
13
|
+
export class ProductEntity extends AbstractEntity {
|
|
14
|
+
public static readonly $index = 'inventory_products';
|
|
15
|
+
|
|
16
|
+
@Prop({ type: Schema.Types.String, required: true, length: 64 })
|
|
17
|
+
public name: string;
|
|
18
|
+
|
|
19
|
+
@Prop({ type: Schema.Types.String, length: 256 })
|
|
20
|
+
public measurement: string;
|
|
21
|
+
|
|
22
|
+
@Prop({ type: Schema.Types.Boolean, default: true })
|
|
23
|
+
public active = true;
|
|
24
|
+
|
|
25
|
+
@Prop({ type: Schema.Types.String, nullable: true })
|
|
26
|
+
public description: string;
|
|
27
|
+
|
|
28
|
+
@Prop({ type: Schema.Types.Array, default: [] })
|
|
29
|
+
public hashtags: string[] = [];
|
|
30
|
+
|
|
31
|
+
@Prop({ type: Schema.Types.ObjectId, ref: CategoryEntity.$index })
|
|
32
|
+
public category?: CategoryEntity;
|
|
33
|
+
|
|
34
|
+
@Prop({ type: Schema.Types.ObjectId, ref: BrandEntity.$index })
|
|
35
|
+
public brand?: BrandEntity;
|
|
36
|
+
|
|
37
|
+
@Prop({ type: [{ type: Schema.Types.ObjectId, ref: AssetEntity.$index }] })
|
|
38
|
+
public files: AssetEntity[] = [];
|
|
39
|
+
|
|
40
|
+
@Prop({ type: Schema.Types.Map, ref: () => PriceEntity, default: new Map() })
|
|
41
|
+
public price: PriceEntity;
|
|
42
|
+
|
|
43
|
+
@Prop({ type: Schema.Types.Map, ref: () => CodeEntity, default: new Map() })
|
|
44
|
+
public code: CodeEntity;
|
|
45
|
+
|
|
46
|
+
@Prop({ type: Schema.Types.Map, ref: () => DimensionEntity, default: new Map() })
|
|
47
|
+
public dimension: DimensionEntity;
|
|
48
|
+
|
|
49
|
+
@Prop({ type: Schema.Types.Map, ref: () => SeoEntity, default: new Map() })
|
|
50
|
+
public seo: SeoEntity;
|
|
51
|
+
|
|
52
|
+
public readonly picture: string
|
|
53
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Catch, HttpException } from '@nestjs/common';
|
|
2
|
+
import { AbstractException } from '../../../abstract/abstract.exception';
|
|
3
|
+
|
|
4
|
+
@Catch()
|
|
5
|
+
export class ProductException extends AbstractException {
|
|
6
|
+
public handleError(exception: HttpException) {
|
|
7
|
+
return exception;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AbstractFixture } from '../../../abstract/abstract.fixture';
|
|
2
|
+
import { ProductEntity } from "./product.entity";
|
|
3
|
+
|
|
4
|
+
export class ProductFixture extends AbstractFixture {
|
|
5
|
+
|
|
6
|
+
public normal() {
|
|
7
|
+
const product = new ProductEntity({
|
|
8
|
+
_id: this.$faker.datatype.uuid(),
|
|
9
|
+
createdAt: this.$faker.date.past(1),
|
|
10
|
+
updatedAt: this.$faker.date.past(1),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
product.name = this.$faker.vehicle.vehicle();
|
|
14
|
+
product.description = this.$faker.commerce.productDescription();
|
|
15
|
+
product.price.sale = Number(this.$faker.commerce.price(1000, 10000, 2));
|
|
16
|
+
|
|
17
|
+
return product;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Inject, Injectable } from '@nestjs/common';
|
|
2
|
+
import { OnEvent } from '@nestjs/event-emitter';
|
|
3
|
+
import { AbsctractListener } from '../../../abstract/absctract.listener';
|
|
4
|
+
import { AssetService } from '../../assets/asset.service';
|
|
5
|
+
import { ProductEntity } from './product.entity';
|
|
6
|
+
|
|
7
|
+
export enum ProductEvent {
|
|
8
|
+
LINK_FILES = 'database.inventory.product.link-files',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@Injectable()
|
|
12
|
+
export class ProductListener extends AbsctractListener {
|
|
13
|
+
|
|
14
|
+
@Inject()
|
|
15
|
+
protected $assets: AssetService;
|
|
16
|
+
|
|
17
|
+
@OnEvent(ProductEvent.LINK_FILES)
|
|
18
|
+
protected async linkAssets(product: ProductEntity) {
|
|
19
|
+
await product.populate('files');
|
|
20
|
+
|
|
21
|
+
const { _id, db: { name } } = product;
|
|
22
|
+
|
|
23
|
+
await this.$assets.removeAssetsWeakness(product.files, `${name}/products/${_id}`);
|
|
24
|
+
|
|
25
|
+
return product;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Module, ModuleMetadata } from '@nestjs/common';
|
|
2
|
+
import { AbstractRouter } from '../../../abstract/abstract.router';
|
|
3
|
+
import { AssetService } from '../../assets/asset.service';
|
|
4
|
+
import { ProductController } from './product.controller';
|
|
5
|
+
import { ProductListener } from './product.listener';
|
|
6
|
+
import { ProductRepository } from './product.repository';
|
|
7
|
+
|
|
8
|
+
export const metadata: ModuleMetadata = {
|
|
9
|
+
imports: [],
|
|
10
|
+
controllers: [ProductController],
|
|
11
|
+
providers: [ProductRepository, ProductListener, AssetService],
|
|
12
|
+
exports: [ProductRepository],
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
@Module(metadata)
|
|
16
|
+
export class ProductModule extends AbstractRouter {
|
|
17
|
+
public static readonly path = '/products';
|
|
18
|
+
|
|
19
|
+
public static readonly module = ProductModule;
|
|
20
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { InjectModel } from '@nestjs/mongoose';
|
|
3
|
+
import { Model, Types } from 'mongoose';
|
|
4
|
+
import { AbstractRepository } from '../../../abstract/abstract.repository';
|
|
5
|
+
import { AssetEntity } from '../../assets/asset.entity';
|
|
6
|
+
import { BrandEntity } from '../brands/brand.entity';
|
|
7
|
+
import { CategoryEntity } from '../categories/category.entity';
|
|
8
|
+
import { ProductEntity } from './product.entity';
|
|
9
|
+
import { ProductEvent } from './product.listener';
|
|
10
|
+
import { CreateProductValidator, UpdateProductValidator } from './product.validator';
|
|
11
|
+
import { FindValidator } from "../../../abstract/abstract.validator";
|
|
12
|
+
|
|
13
|
+
@Injectable()
|
|
14
|
+
export class ProductRepository extends AbstractRepository<ProductEntity> {
|
|
15
|
+
@InjectModel(ProductEntity.$index)
|
|
16
|
+
public readonly $model: Model<ProductEntity>;
|
|
17
|
+
|
|
18
|
+
@InjectModel(AssetEntity.$index)
|
|
19
|
+
public readonly $asset: Model<AssetEntity>;
|
|
20
|
+
|
|
21
|
+
@InjectModel(BrandEntity.$index)
|
|
22
|
+
public readonly $brand: Model<BrandEntity>;
|
|
23
|
+
|
|
24
|
+
@InjectModel(CategoryEntity.$index)
|
|
25
|
+
public readonly $category: Model<CategoryEntity>;
|
|
26
|
+
|
|
27
|
+
public async create(validator: CreateProductValidator) {
|
|
28
|
+
const product: ProductEntity = new this.$model();
|
|
29
|
+
|
|
30
|
+
product.name = validator.name;
|
|
31
|
+
product.measurement = validator.measurement;
|
|
32
|
+
product.description = validator.description;
|
|
33
|
+
product.hashtags = validator.hashtags;
|
|
34
|
+
product.active = validator.active;
|
|
35
|
+
product.files = validator.files.map<AssetEntity>(file => new Types.ObjectId(file) as any);
|
|
36
|
+
|
|
37
|
+
product.brand = (validator.brand ? new Types.ObjectId(validator.brand) : product.brand) as any;
|
|
38
|
+
product.category = (validator.category ? new Types.ObjectId(validator.category) : product.category) as any;
|
|
39
|
+
|
|
40
|
+
product.price.set('sale', validator.price.sale);
|
|
41
|
+
product.price.set('purchase', validator.price.purchase);
|
|
42
|
+
|
|
43
|
+
product.seo.set('slug', validator.seo.slug);
|
|
44
|
+
product.seo.set('title', validator.seo.title);
|
|
45
|
+
product.seo.set('description', validator.seo.description);
|
|
46
|
+
|
|
47
|
+
product.code.set('gtin', validator.code.gtin);
|
|
48
|
+
product.code.set('sku', validator.code.sku);
|
|
49
|
+
product.code.set('mpn', validator.code.mpn);
|
|
50
|
+
|
|
51
|
+
product.dimension.set('depth', validator.dimension.depth);
|
|
52
|
+
product.dimension.set('height', validator.dimension.height);
|
|
53
|
+
product.dimension.set('weight', validator.dimension.weight);
|
|
54
|
+
product.dimension.set('width', validator.dimension.width);
|
|
55
|
+
|
|
56
|
+
await this.$model.create(product);
|
|
57
|
+
|
|
58
|
+
await this.$event.emitAsync(ProductEvent.LINK_FILES, product);
|
|
59
|
+
|
|
60
|
+
return product;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public async read(id: string, params: FindValidator<ProductEntity>): Promise<ProductEntity> {
|
|
64
|
+
return this.$model
|
|
65
|
+
.findOne({ [Types.ObjectId.isValid(id) ? '_id' : 'seo.slug']: id })
|
|
66
|
+
.populate(params.join)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public async update(id: string, validator: UpdateProductValidator) {
|
|
70
|
+
const product: ProductEntity = await this.$model.findById(id);
|
|
71
|
+
|
|
72
|
+
product.name = validator.name || product.name;
|
|
73
|
+
product.measurement = validator.measurement || product.measurement;
|
|
74
|
+
product.description = validator.description || product.description;
|
|
75
|
+
product.hashtags = validator.hashtags ?? product.hashtags;
|
|
76
|
+
product.active = validator.active ?? product.active;
|
|
77
|
+
product.files = validator.files.map<AssetEntity>(file => new Types.ObjectId(file) as any);
|
|
78
|
+
|
|
79
|
+
product.brand = (validator.brand ? new Types.ObjectId(validator.brand) : product.brand) as any;
|
|
80
|
+
product.category = (validator.category ? new Types.ObjectId(validator.category) : product.category) as any;
|
|
81
|
+
|
|
82
|
+
product.price.set('sale', validator.price.sale || product.price.get('sale'));
|
|
83
|
+
product.price.set('purchase', validator.price.purchase || product.price.get('purchase'));
|
|
84
|
+
|
|
85
|
+
product.seo.set('slug', validator.seo.slug ?? product.seo.slug);
|
|
86
|
+
product.seo.set('title', validator.seo.title ?? product.seo.title);
|
|
87
|
+
product.seo.set('description', validator.seo.description ?? product.seo.description);
|
|
88
|
+
|
|
89
|
+
product.code.set('gtin', validator.code.gtin ?? product.code.gtin);
|
|
90
|
+
product.code.set('sku', validator.code.sku ?? product.code.sku);
|
|
91
|
+
product.code.set('mpn', validator.code.mpn ?? product.code.mpn);
|
|
92
|
+
|
|
93
|
+
product.dimension.set('depth', validator.dimension.depth ?? product.dimension.depth);
|
|
94
|
+
product.dimension.set('height', validator.dimension.height ?? product.dimension.height);
|
|
95
|
+
product.dimension.set('weight', validator.dimension.weight ?? product.dimension.weight);
|
|
96
|
+
product.dimension.set('width', validator.dimension.width ?? product.dimension.width);
|
|
97
|
+
|
|
98
|
+
await this.$event.emitAsync(ProductEvent.LINK_FILES, product);
|
|
99
|
+
|
|
100
|
+
await product.save();
|
|
101
|
+
|
|
102
|
+
return product;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public async delete(id: string) {
|
|
106
|
+
return this.$delete(id);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SchemaFactory } from '@nestjs/mongoose';
|
|
2
|
+
import { ProductEntity } from './product.entity';
|
|
3
|
+
|
|
4
|
+
export const ProductSchema = SchemaFactory.createForClass(ProductEntity);
|
|
5
|
+
|
|
6
|
+
ProductSchema.virtual('picture').get<ProductEntity>(function () {
|
|
7
|
+
const [first] = this.files
|
|
8
|
+
|
|
9
|
+
return first?.url;
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
ProductSchema.index({
|
|
13
|
+
name: 'text',
|
|
14
|
+
description: 'text',
|
|
15
|
+
})
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Type } from 'class-transformer';
|
|
2
|
+
import {
|
|
3
|
+
IsBoolean,
|
|
4
|
+
IsMongoId,
|
|
5
|
+
IsNotEmpty,
|
|
6
|
+
IsNotEmptyObject,
|
|
7
|
+
IsOptional,
|
|
8
|
+
IsString,
|
|
9
|
+
ValidateNested
|
|
10
|
+
} from 'class-validator';
|
|
11
|
+
import 'reflect-metadata';
|
|
12
|
+
import { ProductCodeValidator } from './validators/code.validator';
|
|
13
|
+
import { ProductDimensionValidator } from './validators/dimension.validator';
|
|
14
|
+
import { ProductPriceValidator } from './validators/price.validator';
|
|
15
|
+
import { ProductSeoValidator } from './validators/seo.validator';
|
|
16
|
+
import { AbstractValidator } from "../../../abstract/abstract.validator";
|
|
17
|
+
|
|
18
|
+
export class CreateProductValidator extends AbstractValidator {
|
|
19
|
+
@IsString()
|
|
20
|
+
@IsNotEmpty()
|
|
21
|
+
public name = String();
|
|
22
|
+
|
|
23
|
+
@IsString()
|
|
24
|
+
@IsOptional()
|
|
25
|
+
public description = String();
|
|
26
|
+
|
|
27
|
+
@IsString()
|
|
28
|
+
public measurement = String();
|
|
29
|
+
|
|
30
|
+
@IsBoolean()
|
|
31
|
+
@IsOptional()
|
|
32
|
+
public active = Boolean(1);
|
|
33
|
+
|
|
34
|
+
@IsOptional()
|
|
35
|
+
@IsMongoId()
|
|
36
|
+
public category?: string = null;
|
|
37
|
+
|
|
38
|
+
@IsOptional()
|
|
39
|
+
@IsMongoId()
|
|
40
|
+
public brand?: string = null;
|
|
41
|
+
|
|
42
|
+
@IsMongoId({ each: true })
|
|
43
|
+
@IsOptional()
|
|
44
|
+
public files: string[] = [];
|
|
45
|
+
|
|
46
|
+
@IsString({ each: true })
|
|
47
|
+
public hashtags: string[] = [];
|
|
48
|
+
|
|
49
|
+
@ValidateNested()
|
|
50
|
+
@IsNotEmptyObject()
|
|
51
|
+
@Type(() => ProductPriceValidator)
|
|
52
|
+
public price = new ProductPriceValidator();
|
|
53
|
+
|
|
54
|
+
@ValidateNested()
|
|
55
|
+
@Type(() => ProductSeoValidator)
|
|
56
|
+
public seo = new ProductSeoValidator();
|
|
57
|
+
|
|
58
|
+
@ValidateNested()
|
|
59
|
+
@Type(() => ProductDimensionValidator)
|
|
60
|
+
public dimension = new ProductDimensionValidator();
|
|
61
|
+
|
|
62
|
+
@ValidateNested()
|
|
63
|
+
@Type(() => ProductCodeValidator)
|
|
64
|
+
public code = new ProductCodeValidator();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export class UpdateProductValidator extends CreateProductValidator {
|
|
68
|
+
@IsString()
|
|
69
|
+
@IsOptional()
|
|
70
|
+
public name: string;
|
|
71
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IsOptional, IsString } from 'class-validator';
|
|
2
|
+
|
|
3
|
+
export class ProductCodeValidator {
|
|
4
|
+
@IsString()
|
|
5
|
+
@IsOptional()
|
|
6
|
+
public sku? = String();
|
|
7
|
+
|
|
8
|
+
@IsString()
|
|
9
|
+
@IsOptional()
|
|
10
|
+
public gtin? = String();
|
|
11
|
+
|
|
12
|
+
@IsString()
|
|
13
|
+
@IsOptional()
|
|
14
|
+
public mpn? = String();
|
|
15
|
+
}
|