@merkaly/api 0.2.4-6 → 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/order.entity.d.ts +1 -1
- package/.output/modules/sales/orders/order.validator.js +2 -3
- 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,39 @@
|
|
|
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 { BrandEntity } from './brand.entity';
|
|
6
|
+
import { CreateBrandValidator, UpdateBrandValidator } from './brand.validator';
|
|
7
|
+
import { CategoryEntity } from "../categories/category.entity";
|
|
8
|
+
|
|
9
|
+
@Injectable()
|
|
10
|
+
export class BrandRepository extends AbstractRepository<BrandEntity> {
|
|
11
|
+
@InjectModel(BrandEntity.$index)
|
|
12
|
+
public readonly $model: Model<BrandEntity>;
|
|
13
|
+
|
|
14
|
+
public async create(validator: CreateBrandValidator) {
|
|
15
|
+
const brand = new this.$model();
|
|
16
|
+
|
|
17
|
+
brand.name = validator.name;
|
|
18
|
+
brand.description = validator.description;
|
|
19
|
+
|
|
20
|
+
return super.$create(brand);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public async update(id: string, validator: UpdateBrandValidator) {
|
|
24
|
+
const category: CategoryEntity = await this.$model.findById(id);
|
|
25
|
+
|
|
26
|
+
const query: UpdateQuery<BrandEntity> = {
|
|
27
|
+
$set: {
|
|
28
|
+
name: validator.name || category.name,
|
|
29
|
+
description: validator.description || category.description,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return super.$update(id, query);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public async delete(id: string): Promise<void> {
|
|
37
|
+
return super.$delete(id);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { IsOptional, IsString, Length } from 'class-validator';
|
|
2
|
+
import { AbstractValidator } from "../../../abstract/abstract.validator";
|
|
3
|
+
|
|
4
|
+
export class CreateBrandValidator extends AbstractValidator {
|
|
5
|
+
@IsString()
|
|
6
|
+
@Length(2, 32)
|
|
7
|
+
public name: string;
|
|
8
|
+
|
|
9
|
+
@IsString()
|
|
10
|
+
@IsOptional()
|
|
11
|
+
public description?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class UpdateBrandValidator extends AbstractValidator {
|
|
15
|
+
@IsString()
|
|
16
|
+
@Length(2, 32)
|
|
17
|
+
@IsOptional()
|
|
18
|
+
public name?: string;
|
|
19
|
+
|
|
20
|
+
@IsString()
|
|
21
|
+
@IsOptional()
|
|
22
|
+
public description?: string;
|
|
23
|
+
}
|
|
@@ -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 { CategoryEntity } from './category.entity';
|
|
19
|
+
import { CategoryException } from './category.exception';
|
|
20
|
+
import { CategoryRepository } from './category.repository';
|
|
21
|
+
import { CreateCategoryValidator, UpdateCategoryValidator } from './category.validator';
|
|
22
|
+
import { Public } from "../../../decorators/public.decorator";
|
|
23
|
+
|
|
24
|
+
@Controller()
|
|
25
|
+
@UseFilters(CategoryException)
|
|
26
|
+
@ApiTags('inventory')
|
|
27
|
+
export class CategoryController extends AbstractController<CategoryEntity> {
|
|
28
|
+
@Inject()
|
|
29
|
+
protected readonly $repository: CategoryRepository;
|
|
30
|
+
|
|
31
|
+
@Get('/')
|
|
32
|
+
@Public()
|
|
33
|
+
public async find(@Query() validator: FindValidator<CategoryEntity>) {
|
|
34
|
+
return super.find(validator);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@Get('/:id')
|
|
38
|
+
@Public()
|
|
39
|
+
public async read(@Param('id') id: string) {
|
|
40
|
+
return this.$repository.read(id);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Post('/')
|
|
44
|
+
@HttpCode(HttpStatus.CREATED)
|
|
45
|
+
public async create(@Body() validator: CreateCategoryValidator) {
|
|
46
|
+
return this.$repository.create(validator);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@Patch('/:id')
|
|
50
|
+
public async update(@Param('id') id: string, @Body() validator: UpdateCategoryValidator) {
|
|
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): Promise<void> {
|
|
57
|
+
return this.$repository.delete(id);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -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
|
+
}
|