Skip to content

Commit

Permalink
feat: #841/update product and variants
Browse files Browse the repository at this point in the history
  • Loading branch information
tsvetelina-e-y committed Apr 29, 2020
1 parent ff9bf28 commit b2fb817
Show file tree
Hide file tree
Showing 25 changed files with 368 additions and 33 deletions.
6 changes: 6 additions & 0 deletions apps/api/src/app/app.module.ts
Expand Up @@ -63,6 +63,7 @@ import { CandidateCvModule } from './candidate-cv/candidate-cv.module';
import { CandidateEducationModule } from './candidate-education/candidate-education.module';
import { CandidateSourceModule } from './candidate_source/candidate_source.module';
import { CandidateExperienceModule } from './candidate-experience/candidate-experience.module';
import { ProductVariantSettingsModule } from './product-settings/product-settings.module';

@Module({
imports: [
Expand Down Expand Up @@ -242,6 +243,10 @@ import { CandidateExperienceModule } from './candidate-experience/candidate-expe
{
path: '/product-variants',
module: ProductVariantModule
},
{
path: '/product-variant-settings',
module: ProductVariantSettingsModule
}
]
}
Expand Down Expand Up @@ -314,6 +319,7 @@ import { CandidateExperienceModule } from './candidate-experience/candidate-expe
IntegrationMapModule,
ProductVariantPriceModule,
ProductVariantModule,
ProductVariantSettingsModule,
IntegrationEntitySettingModule,
IntegrationEntitySettingTiedEntityModule
],
Expand Down
3 changes: 2 additions & 1 deletion apps/api/src/app/product-option/product-option.entity.ts
Expand Up @@ -19,7 +19,8 @@ export class ProductOption extends Base implements IProductOption {

@ManyToOne(
() => Product,
(product) => product.options
(product) => product.options,
{ onUpdate: 'CASCADE', onDelete: 'CASCADE' }
)
@JoinColumn()
product: Product;
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/app/product-option/product-option.service.ts
Expand Up @@ -16,6 +16,6 @@ export class ProductOptionService extends CrudService<ProductOption> {
async createBulk(
productOptionsInput: ProductOption[]
): Promise<ProductOption[]> {
return this.productOptionRepository.create(productOptionsInput);
return this.productOptionRepository.save(productOptionsInput);
}
}
53 changes: 51 additions & 2 deletions apps/api/src/app/product-variant/product-variant.controller.ts
@@ -1,6 +1,15 @@
import { Controller, HttpStatus, Post, Body } from '@nestjs/common';
import {
Controller,
HttpStatus,
Post,
Body,
Get,
HttpCode,
Put,
Param
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { CrudController } from '../core';
import { CrudController, IPagination } from '../core';
import { ProductVariant } from './product-variant.entity';
import { ProductVariantService } from './product-variant.service';
import { ProductVariantCreateCommand } from './commands';
Expand Down Expand Up @@ -36,4 +45,44 @@ export class ProductVariantController extends CrudController<ProductVariant> {
): Promise<ProductVariant[]> {
return this.commandBus.execute(new ProductVariantCreateCommand(entity));
}

@ApiOperation({
summary: 'Find all product variants'
})
@ApiResponse({
status: HttpStatus.OK,
description: 'Found product variants',
type: Product
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Record not found'
})
@Get('all')
async findAllProductVariants(): Promise<IPagination<ProductVariant>> {
return this.productVariantService.findAllProductVariants();
}

@ApiOperation({ summary: 'Update an existing record' })
@ApiResponse({
status: HttpStatus.CREATED,
description: 'The record has been successfully edited.'
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Record not found'
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description:
'Invalid input, The response body may contain clues as to what went wrong'
})
@HttpCode(HttpStatus.ACCEPTED)
@Put(':id')
async update(
@Param('id') id: string,
@Body() productVariant: ProductVariant
): Promise<ProductVariant> {
return this.productVariantService.updateVariant(productVariant);
}
}
15 changes: 12 additions & 3 deletions apps/api/src/app/product-variant/product-variant.entity.ts
Expand Up @@ -61,21 +61,30 @@ export class ProductVariant extends Base implements IProductVariant {

@OneToOne(
() => ProductVariantSettings,
(settings) => settings.productVariant
(settings) => settings.productVariant,
{
eager: true,
onDelete: 'CASCADE'
}
)
@JoinColumn()
settings: ProductVariantSettings;

@OneToOne(
() => ProductVariantPrice,
(variantPrice) => variantPrice.productVariant
(variantPrice) => variantPrice.productVariant,
{
eager: true,
onDelete: 'CASCADE'
}
)
@JoinColumn()
price: ProductVariantPrice;

@ManyToOne(
() => Product,
(product) => product.variants
(product) => product.variants,
{ onDelete: 'CASCADE' }
)
@JoinColumn()
product: Product;
Expand Down
17 changes: 16 additions & 1 deletion apps/api/src/app/product-variant/product-variant.service.ts
@@ -1,5 +1,5 @@
import { Repository } from 'typeorm';
import { CrudService } from '../core';
import { CrudService, IPagination } from '../core';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { ProductVariant } from './product-variant.entity';
Expand All @@ -13,6 +13,15 @@ export class ProductVariantService extends CrudService<ProductVariant> {
super(productVariantRepository);
}

async findAllProductVariants(): Promise<IPagination<ProductVariant>> {
const total = await this.productVariantRepository.count();
const items = await this.productVariantRepository.find({
relations: ['settings', 'price']
});

return { items, total };
}

async createBulk(
productVariants: ProductVariant[]
): Promise<ProductVariant[]> {
Expand All @@ -24,4 +33,10 @@ export class ProductVariantService extends CrudService<ProductVariant> {
): Promise<ProductVariant> {
return this.productVariantRepository.save(productVariant);
}

async updateVariant(
productVariant: ProductVariant
): Promise<ProductVariant> {
return this.productVariantRepository.save(productVariant);
}
}
Expand Up @@ -18,14 +18,15 @@ export class ProductCreateHandler

const product = await this.productService.create(productInput);

const options = productInput.options.map((optionInput) => {
const optionsInput = productInput.options.map((optionInput) => {
const option = new ProductOption();
Object.assign(option, { ...optionInput, product });

return option;
});

product.options = await this.productOptionService.createBulk(options);
await this.productOptionService.createBulk(optionsInput);

return product;
}
}
@@ -0,0 +1,26 @@
import { ICommandHandler, CommandHandler } from '@nestjs/cqrs';
import { ProductService } from '../../../product/product.service';
import { ProductOptionService } from '../../../product-option/product-option.service';
import { Product } from '../../product.entity';
import { ProductUpdateCommand } from '../product.update.command';

@CommandHandler(ProductUpdateCommand)
export class ProductUpdateHandler
implements ICommandHandler<ProductUpdateCommand> {
constructor(
private productOptionService: ProductOptionService,
private productService: ProductService
) {}

public async execute(command?: ProductUpdateCommand): Promise<Product> {
const { productUpdateRequest } = command;

const product = await this.productService.saveProduct(
productUpdateRequest
);

//todo manage options

return product;
}
}
11 changes: 11 additions & 0 deletions apps/api/src/app/product/commands/product.update.command.ts
@@ -0,0 +1,11 @@
import { ICommand } from '@nestjs/cqrs';
import { Product } from '../../product/product.entity';

export class ProductUpdateCommand implements ICommand {
static readonly type = '[Product] Update';

constructor(
public readonly id: string,
public readonly productUpdateRequest: Product
) {}
}
29 changes: 28 additions & 1 deletion apps/api/src/app/product/product.controller.ts
Expand Up @@ -3,7 +3,10 @@ import {
Get,
HttpStatus,
Post,
Body
Body,
Put,
Param,
HttpCode
// UseGuards
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
Expand All @@ -12,6 +15,7 @@ import { ProductService } from './product.service';
import { Product } from './product.entity';
import { CommandBus } from '@nestjs/cqrs';
import { ProductCreateCommand } from './commands/product.create.command';
import { ProductUpdateCommand } from './commands/product.update.command';
// import { PermissionGuard } from '../shared/guards/auth/permission.guard';

@ApiTags('Product')
Expand Down Expand Up @@ -56,4 +60,27 @@ export class ProductController extends CrudController<Product> {
async createProduct(@Body() entity: Product, ...options: any[]) {
return this.commandBus.execute(new ProductCreateCommand(entity));
}

@ApiOperation({ summary: 'Update an existing record' })
@ApiResponse({
status: HttpStatus.CREATED,
description: 'The record has been successfully edited.'
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Record not found'
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description:
'Invalid input, The response body may contain clues as to what went wrong'
})
@HttpCode(HttpStatus.ACCEPTED)
@Put(':id')
async update(
@Param('id') id: string,
@Body() entity: Product
): Promise<any> {
return this.commandBus.execute(new ProductUpdateCommand(id, entity));
}
}
5 changes: 3 additions & 2 deletions apps/api/src/app/product/product.entity.ts
Expand Up @@ -38,7 +38,8 @@ export class Product extends Base implements IProduct {

@OneToMany(
() => ProductVariant,
(productVariant) => productVariant.product
(productVariant) => productVariant.product,
{ onDelete: 'CASCADE' }
)
variants: ProductVariant[];

Expand All @@ -62,5 +63,5 @@ export class Product extends Base implements IProduct {
(type) => ProductOption,
(productOption) => productOption.product
)
options?: ProductOption[];
options: ProductOption[];
}
8 changes: 7 additions & 1 deletion apps/api/src/app/product/product.module.ts
Expand Up @@ -7,11 +7,17 @@ import { ProductOption } from '../product-option/product-option.entity';
import { CqrsModule } from '@nestjs/cqrs';
import { ProductOptionService } from '../product-option/product-option.service';
import { ProductCreateHandler } from './commands/handlers/product.create.handler';
import { ProductUpdateHandler } from './commands/handlers/product.update.handler';

@Module({
imports: [TypeOrmModule.forFeature([Product, ProductOption]), CqrsModule],
controllers: [ProductController],
providers: [ProductService, ProductOptionService, ProductCreateHandler],
providers: [
ProductService,
ProductOptionService,
ProductCreateHandler,
ProductUpdateHandler
],
exports: [ProductService]
})
export class ProductModule {}
4 changes: 4 additions & 0 deletions apps/api/src/app/product/product.service.ts
Expand Up @@ -21,4 +21,8 @@ export class ProductService extends CrudService<Product> {

return { items, total };
}

async saveProduct(productRequest: Product): Promise<Product> {
return await this.productRepository.save(productRequest);
}
}
23 changes: 23 additions & 0 deletions apps/gauzy/src/app/@core/services/product-variant-price.service.ts
@@ -0,0 +1,23 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ProductVariantPrice } from '@gauzy/models';
import { first } from 'rxjs/operators';

@Injectable()
export class ProductVariantPriceService {
PRODUCT_VARIANT_PRICE_URL = '/api/product-variant-prices';

constructor(private http: HttpClient) {}

updateProductVariantPrice(
productVariantPrice: ProductVariantPrice
): Promise<ProductVariantPrice> {
return this.http
.put<ProductVariantPrice>(
`${this.PRODUCT_VARIANT_PRICE_URL}/${productVariantPrice.id}`,
productVariantPrice
)
.pipe(first())
.toPromise();
}
}
@@ -0,0 +1,30 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ProductVariantSettings } from '@gauzy/models';
import { first } from 'rxjs/operators';

@Injectable()
export class ProductVariantSettingsService {
PRODUCT_VARIANT_SETTINGS_URL = '/api/product-variant-settings';

constructor(private http: HttpClient) {}

updateProductVariantSettings(
productVariantSettings: ProductVariantSettings
): Promise<ProductVariantSettings> {
return this.http
.put<ProductVariantSettings>(
`${this.PRODUCT_VARIANT_SETTINGS_URL}/${productVariantSettings.id}`,
productVariantSettings
)
.pipe(first())
.toPromise();
}

getProductVariantSettings(): Promise<ProductVariantSettings[]> {
return this.http
.get<ProductVariantSettings[]>(this.PRODUCT_VARIANT_SETTINGS_URL)
.pipe(first())
.toPromise();
}
}

0 comments on commit b2fb817

Please sign in to comment.