diff --git a/api/migrations/1622379534005-ProductWeight.ts b/api/migrations/1622379534005-ProductWeight.ts new file mode 100644 index 0000000..78e8a05 --- /dev/null +++ b/api/migrations/1622379534005-ProductWeight.ts @@ -0,0 +1,16 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class ProductWeight1622379534005 implements MigrationInterface { + name = 'ProductWeight1622379534005' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "shipping_cost" RENAME COLUMN "grams" TO "weight"`); + await queryRunner.query(`ALTER TABLE "product" ADD "weight" integer NOT NULL DEFAULT 0`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "product" DROP COLUMN "weight"`); + await queryRunner.query(`ALTER TABLE "shipping_cost" RENAME COLUMN "weight" TO "grams"`); + } + +} diff --git a/api/src/Application/Order/Command/ShippingCost/CreateShippingCostCommand.ts b/api/src/Application/Order/Command/ShippingCost/CreateShippingCostCommand.ts index d35e946..8d47694 100644 --- a/api/src/Application/Order/Command/ShippingCost/CreateShippingCostCommand.ts +++ b/api/src/Application/Order/Command/ShippingCost/CreateShippingCostCommand.ts @@ -2,7 +2,7 @@ import { ICommand } from 'src/Application/ICommand'; export class CreateShippingCostCommand implements ICommand { constructor( - public readonly grams: number, + public readonly weight: number, public readonly price: number ) {} } diff --git a/api/src/Application/Order/Command/ShippingCost/CreateShippingCostCommandHandler.ts b/api/src/Application/Order/Command/ShippingCost/CreateShippingCostCommandHandler.ts index 588f75b..ac28a23 100644 --- a/api/src/Application/Order/Command/ShippingCost/CreateShippingCostCommandHandler.ts +++ b/api/src/Application/Order/Command/ShippingCost/CreateShippingCostCommandHandler.ts @@ -15,14 +15,14 @@ export class CreateShippingCostCommandHandler { ) {} public async execute(command: CreateShippingCostCommand): Promise { - const { grams, price } = command; + const { weight, price } = command; - if (true === (await this.isShippingCostAlreadyExist.isSatisfiedBy(grams))) { + if (true === (await this.isShippingCostAlreadyExist.isSatisfiedBy(weight))) { throw new ShippingCostAlreadyExistException(); } const shippingCost = await this.shippingcostRepository.save( - new ShippingCost(grams, Math.round(price * 100)) + new ShippingCost(weight, Math.round(price * 100)) ); return shippingCost.getId(); diff --git a/api/src/Application/Order/Command/ShippingCost/UpdateShippingCostCommand.ts b/api/src/Application/Order/Command/ShippingCost/UpdateShippingCostCommand.ts index 236a58d..c725255 100644 --- a/api/src/Application/Order/Command/ShippingCost/UpdateShippingCostCommand.ts +++ b/api/src/Application/Order/Command/ShippingCost/UpdateShippingCostCommand.ts @@ -3,7 +3,7 @@ import { ICommand } from 'src/Application/ICommand'; export class UpdateShippingCostCommand implements ICommand { constructor( public readonly id: string, - public readonly grams: number, + public readonly weight: number, public readonly price: number ) {} } diff --git a/api/src/Application/Order/Command/ShippingCost/UpdateShippingCostCommandHandler.spec.ts b/api/src/Application/Order/Command/ShippingCost/UpdateShippingCostCommandHandler.spec.ts index 4722ebb..8a0de59 100644 --- a/api/src/Application/Order/Command/ShippingCost/UpdateShippingCostCommandHandler.spec.ts +++ b/api/src/Application/Order/Command/ShippingCost/UpdateShippingCostCommandHandler.spec.ts @@ -51,7 +51,7 @@ describe('UpdateShippingCostCommandHandler', () => { }); it('testShippingCostAlreadyExist', async () => { - when(shippingcost.getGrams()).thenReturn(100); + when(shippingcost.getWeight()).thenReturn(100); when( shippingcostRepository.findOneById('8a9df044-94a7-4e6c-abd1-ecdd69d788d5') ).thenResolve(instance(shippingcost)); @@ -77,7 +77,7 @@ describe('UpdateShippingCostCommandHandler', () => { it('testSuccessfullyUpdated', async () => { when(shippingcost.getId()).thenReturn('8a9df044-94a7-4e6c-abd1-ecdd69d788d5'); - when(shippingcost.getGrams()).thenReturn(1000); + when(shippingcost.getWeight()).thenReturn(1000); when( shippingcostRepository.findOneById('8a9df044-94a7-4e6c-abd1-ecdd69d788d5') ).thenResolve(instance(shippingcost)); diff --git a/api/src/Application/Order/Command/ShippingCost/UpdateShippingCostCommandHandler.ts b/api/src/Application/Order/Command/ShippingCost/UpdateShippingCostCommandHandler.ts index 497af02..08c0cc6 100644 --- a/api/src/Application/Order/Command/ShippingCost/UpdateShippingCostCommandHandler.ts +++ b/api/src/Application/Order/Command/ShippingCost/UpdateShippingCostCommandHandler.ts @@ -15,7 +15,7 @@ export class UpdateShippingCostCommandHandler { ) {} public async execute(command: UpdateShippingCostCommand): Promise { - const { id, grams, price } = command; + const { id, weight, price } = command; const shippingCost = await this.shippingcostRepository.findOneById(id); if (!shippingCost) { @@ -23,13 +23,13 @@ export class UpdateShippingCostCommandHandler { } if ( - grams !== shippingCost.getGrams() && - true === (await this.isShippingCostAlreadyExist.isSatisfiedBy(grams)) + weight !== shippingCost.getWeight() && + true === (await this.isShippingCostAlreadyExist.isSatisfiedBy(weight)) ) { throw new ShippingCostAlreadyExistException(); } - shippingCost.update(grams, Math.round(price * 100)); + shippingCost.update(weight, Math.round(price * 100)); await this.shippingcostRepository.save(shippingCost); diff --git a/api/src/Application/Order/Query/ShippingCost/GetShippingCostByIdQueryHandler.spec.ts b/api/src/Application/Order/Query/ShippingCost/GetShippingCostByIdQueryHandler.spec.ts index 9591d70..250f666 100644 --- a/api/src/Application/Order/Query/ShippingCost/GetShippingCostByIdQueryHandler.spec.ts +++ b/api/src/Application/Order/Query/ShippingCost/GetShippingCostByIdQueryHandler.spec.ts @@ -20,7 +20,7 @@ describe('GetShippingCostByIdQueryHandler', () => { const shippingcost = mock(ShippingCost); when(shippingcost.getId()).thenReturn('eb9e1d9b-dce2-48a9-b64f-f0872f3157d2'); - when(shippingcost.getGrams()).thenReturn(1000); + when(shippingcost.getWeight()).thenReturn(1000); when(shippingcost.getPriceFromCents()).thenReturn(9.99); when( shippingcostRepository.findOneById('eb9e1d9b-dce2-48a9-b64f-f0872f3157d2') diff --git a/api/src/Application/Order/Query/ShippingCost/GetShippingCostByIdQueryHandler.ts b/api/src/Application/Order/Query/ShippingCost/GetShippingCostByIdQueryHandler.ts index 05722e1..ed41afd 100644 --- a/api/src/Application/Order/Query/ShippingCost/GetShippingCostByIdQueryHandler.ts +++ b/api/src/Application/Order/Query/ShippingCost/GetShippingCostByIdQueryHandler.ts @@ -21,7 +21,7 @@ export class GetShippingCostByIdQueryHandler { return new ShippingCostView( shippingCost.getId(), - shippingCost.getGrams(), + shippingCost.getWeight(), shippingCost.getPriceFromCents(), ); } diff --git a/api/src/Application/Order/Query/ShippingCost/GetShippingCostsQueryHandler.spec.ts b/api/src/Application/Order/Query/ShippingCost/GetShippingCostsQueryHandler.spec.ts index dd7cf03..8ac1f62 100644 --- a/api/src/Application/Order/Query/ShippingCost/GetShippingCostsQueryHandler.spec.ts +++ b/api/src/Application/Order/Query/ShippingCost/GetShippingCostsQueryHandler.spec.ts @@ -12,12 +12,12 @@ describe('GetShippingCostsQueryHandler', () => { const shippingcost1 = mock(ShippingCost); when(shippingcost1.getId()).thenReturn('eb9e1d9b-dce2-48a9-b64f-f0872f3157d2'); when(shippingcost1.getPriceFromCents()).thenReturn(9.99); - when(shippingcost1.getGrams()).thenReturn(1000); + when(shippingcost1.getWeight()).thenReturn(1000); const shippingcost2 = mock(ShippingCost); when(shippingcost2.getId()).thenReturn('d54f15d6-1a1d-47e8-8672-9f46018f9960'); when(shippingcost2.getPriceFromCents()).thenReturn(3.99); - when(shippingcost2.getGrams()).thenReturn(500); + when(shippingcost2.getWeight()).thenReturn(500); when(shippingcostRepository.findShippingCosts()).thenResolve([ instance(shippingcost2), instance(shippingcost1) diff --git a/api/src/Application/Order/Query/ShippingCost/GetShippingCostsQueryHandler.ts b/api/src/Application/Order/Query/ShippingCost/GetShippingCostsQueryHandler.ts index b077284..4ccddb7 100644 --- a/api/src/Application/Order/Query/ShippingCost/GetShippingCostsQueryHandler.ts +++ b/api/src/Application/Order/Query/ShippingCost/GetShippingCostsQueryHandler.ts @@ -19,7 +19,7 @@ export class GetShippingCostsQueryHandler { shippingcostViews.push( new ShippingCostView( shippingCost.getId(), - shippingCost.getGrams(), + shippingCost.getWeight(), shippingCost.getPriceFromCents(), ) ); diff --git a/api/src/Application/Order/View/ShippingCostView.ts b/api/src/Application/Order/View/ShippingCostView.ts index 795b81a..8b88781 100644 --- a/api/src/Application/Order/View/ShippingCostView.ts +++ b/api/src/Application/Order/View/ShippingCostView.ts @@ -1,7 +1,7 @@ export class ShippingCostView { constructor( public readonly id: string, - public readonly grams: number, + public readonly weight: number, public readonly price: number, ) {} } diff --git a/api/src/Application/Product/Command/CreateProductCommand.ts b/api/src/Application/Product/Command/CreateProductCommand.ts index 00a9057..57ff303 100644 --- a/api/src/Application/Product/Command/CreateProductCommand.ts +++ b/api/src/Application/Product/Command/CreateProductCommand.ts @@ -4,6 +4,7 @@ export class CreateProductCommand implements ICommand { constructor( public readonly title: string, public readonly description: string, - public readonly unitPrice: number + public readonly unitPrice: number, + public readonly weight: number ) {} } diff --git a/api/src/Application/Product/Command/CreateProductCommandHandler.spec.ts b/api/src/Application/Product/Command/CreateProductCommandHandler.spec.ts index e9cfd92..7fd11e1 100644 --- a/api/src/Application/Product/Command/CreateProductCommandHandler.spec.ts +++ b/api/src/Application/Product/Command/CreateProductCommandHandler.spec.ts @@ -16,6 +16,7 @@ describe('CreateProductCommandHandler', () => { 'Mug', 'Mug portrait enfant', 9.99, + 1000 ); beforeEach(() => { @@ -41,6 +42,7 @@ describe('CreateProductCommandHandler', () => { 'Mug', 'Mug portrait enfant', 999, + 1000 ) ) ) @@ -58,6 +60,7 @@ describe('CreateProductCommandHandler', () => { 'Mug', 'Mug portrait enfant', 999, + 1000 ) ) ) diff --git a/api/src/Application/Product/Command/CreateProductCommandHandler.ts b/api/src/Application/Product/Command/CreateProductCommandHandler.ts index 582bea5..e1aca77 100644 --- a/api/src/Application/Product/Command/CreateProductCommandHandler.ts +++ b/api/src/Application/Product/Command/CreateProductCommandHandler.ts @@ -15,14 +15,14 @@ export class CreateProductCommandHandler { ) {} public async execute(command: CreateProductCommand): Promise { - const { title, description, unitPrice } = command; + const { title, description, unitPrice, weight } = command; if (true === (await this.isProductAlreadyExist.isSatisfiedBy(title))) { throw new ProductAlreadyExistException(); } const product = await this.productRepository.save( - new Product(title, description, Math.round(unitPrice * 100)) + new Product(title, description, Math.round(unitPrice * 100), weight) ); return product.getId(); diff --git a/api/src/Application/Product/Command/UpdateProductCommand.ts b/api/src/Application/Product/Command/UpdateProductCommand.ts index df9b9e0..f3eda2f 100644 --- a/api/src/Application/Product/Command/UpdateProductCommand.ts +++ b/api/src/Application/Product/Command/UpdateProductCommand.ts @@ -5,6 +5,7 @@ export class UpdateProductCommand implements ICommand { public readonly id: string, public readonly title: string, public readonly unitPrice: number, + public readonly weight: number, public readonly description?: string ) {} } diff --git a/api/src/Application/Product/Command/UpdateProductCommandHandler.spec.ts b/api/src/Application/Product/Command/UpdateProductCommandHandler.spec.ts index 3230f78..4c761ab 100644 --- a/api/src/Application/Product/Command/UpdateProductCommandHandler.spec.ts +++ b/api/src/Application/Product/Command/UpdateProductCommandHandler.spec.ts @@ -18,6 +18,7 @@ describe('UpdateProductCommandHandler', () => { '8a9df044-94a7-4e6c-abd1-ecdd69d788d5', 'Mug', 9.99, + 1000, 'Mug portrait' ); @@ -46,7 +47,7 @@ describe('UpdateProductCommandHandler', () => { verify(isProductAlreadyExist.isSatisfiedBy(anything())).never(); verify(productRepository.save(anything())).never(); verify( - product.update(anything(), anything(), anything()) + product.update(anything(), anything(), anything(), anything()) ).never(); } }); @@ -70,7 +71,7 @@ describe('UpdateProductCommandHandler', () => { isProductAlreadyExist.isSatisfiedBy('Mug') ).once(); verify( - product.update(anything(), anything(), anything()) + product.update(anything(), anything(), anything(), anything()) ).never(); verify(productRepository.save(anything())).never(); } @@ -92,7 +93,8 @@ describe('UpdateProductCommandHandler', () => { product.update( 'Mug', 'Mug portrait', - 999 + 999, + 1000 ) ).calledBefore(productRepository.save(instance(product))); verify(productRepository.save(instance(product))).once(); diff --git a/api/src/Application/Product/Command/UpdateProductCommandHandler.ts b/api/src/Application/Product/Command/UpdateProductCommandHandler.ts index ade7176..2ef5c83 100644 --- a/api/src/Application/Product/Command/UpdateProductCommandHandler.ts +++ b/api/src/Application/Product/Command/UpdateProductCommandHandler.ts @@ -15,7 +15,7 @@ export class UpdateProductCommandHandler { ) {} public async execute(command: UpdateProductCommand): Promise { - const { id, title, description, unitPrice } = command; + const { id, title, description, unitPrice, weight } = command; const product = await this.productRepository.findOneById(id); if (!product) { @@ -29,7 +29,7 @@ export class UpdateProductCommandHandler { throw new ProductAlreadyExistException(); } - product.update(title, description, Math.round(unitPrice * 100)); + product.update(title, description, Math.round(unitPrice * 100), weight); await this.productRepository.save(product); diff --git a/api/src/Application/Product/Query/GetProductByIdQueryHandler.spec.ts b/api/src/Application/Product/Query/GetProductByIdQueryHandler.spec.ts index 417706b..1efd2b2 100644 --- a/api/src/Application/Product/Query/GetProductByIdQueryHandler.spec.ts +++ b/api/src/Application/Product/Query/GetProductByIdQueryHandler.spec.ts @@ -16,6 +16,7 @@ describe('GetProductByIdQueryHandler', () => { 'eb9e1d9b-dce2-48a9-b64f-f0872f3157d2', 'Mug', 9.99, + 1000, 'Mug portrait enfant' ); @@ -23,6 +24,7 @@ describe('GetProductByIdQueryHandler', () => { when(product.getId()).thenReturn('eb9e1d9b-dce2-48a9-b64f-f0872f3157d2'); when(product.getTitle()).thenReturn('Mug'); when(product.getDescription()).thenReturn('Mug portrait enfant'); + when(product.getWeight()).thenReturn(1000); when(product.getPriceFromCents()).thenReturn(9.99); when( productRepository.findOneById('eb9e1d9b-dce2-48a9-b64f-f0872f3157d2') diff --git a/api/src/Application/Product/Query/GetProductByIdQueryHandler.ts b/api/src/Application/Product/Query/GetProductByIdQueryHandler.ts index c8d7077..3b58201 100644 --- a/api/src/Application/Product/Query/GetProductByIdQueryHandler.ts +++ b/api/src/Application/Product/Query/GetProductByIdQueryHandler.ts @@ -23,6 +23,7 @@ export class GetProductByIdQueryHandler { product.getId(), product.getTitle(), product.getPriceFromCents(), + product.getWeight(), product.getDescription() ); } diff --git a/api/src/Application/Product/Query/GetProductsQueryHandler.spec.ts b/api/src/Application/Product/Query/GetProductsQueryHandler.spec.ts index cf45035..f116a38 100644 --- a/api/src/Application/Product/Query/GetProductsQueryHandler.spec.ts +++ b/api/src/Application/Product/Query/GetProductsQueryHandler.spec.ts @@ -14,11 +14,13 @@ describe('GetProductsQueryHandler', () => { when(product1.getId()).thenReturn('eb9e1d9b-dce2-48a9-b64f-f0872f3157d2'); when(product1.getTitle()).thenReturn('Mug'); when(product1.getDescription()).thenReturn('Mug portrait enfant'); + when(product1.getWeight()).thenReturn(1000); when(product1.getPriceFromCents()).thenReturn(9.99); const product2 = mock(Product); when(product2.getId()).thenReturn('d54f15d6-1a1d-47e8-8672-9f46018f9960'); when(product2.getTitle()).thenReturn('Porte clef'); + when(product2.getWeight()).thenReturn(200); when(product2.getPriceFromCents()).thenReturn(10); when(productRepository.findProducts(1)).thenResolve([ @@ -34,12 +36,14 @@ describe('GetProductsQueryHandler', () => { 'd54f15d6-1a1d-47e8-8672-9f46018f9960', 'Porte clef', 10, + 200, null ), new ProductView( 'eb9e1d9b-dce2-48a9-b64f-f0872f3157d2', 'Mug', 9.99, + 1000, 'Mug portrait enfant' ) ], diff --git a/api/src/Application/Product/Query/GetProductsQueryHandler.ts b/api/src/Application/Product/Query/GetProductsQueryHandler.ts index 3a9aa62..361f231 100644 --- a/api/src/Application/Product/Query/GetProductsQueryHandler.ts +++ b/api/src/Application/Product/Query/GetProductsQueryHandler.ts @@ -28,6 +28,7 @@ export class GetProductsQueryHandler { product.getId(), product.getTitle(), product.getPriceFromCents(), + product.getWeight(), product.getDescription(), ) ); diff --git a/api/src/Application/Product/View/ProductView.ts b/api/src/Application/Product/View/ProductView.ts index 260d85ee..083e27e 100644 --- a/api/src/Application/Product/View/ProductView.ts +++ b/api/src/Application/Product/View/ProductView.ts @@ -3,6 +3,7 @@ export class ProductView { public readonly id: string, public readonly title: string, public readonly unitPrice: number, + public readonly weight: number, public readonly description?: string ) {} } diff --git a/api/src/Domain/Order/Repository/IShippingCostRepository.ts b/api/src/Domain/Order/Repository/IShippingCostRepository.ts index c7493b1..18a6bf2 100644 --- a/api/src/Domain/Order/Repository/IShippingCostRepository.ts +++ b/api/src/Domain/Order/Repository/IShippingCostRepository.ts @@ -3,7 +3,7 @@ import { ShippingCost } from '../ShippingCost.entity'; export interface IShippingCostRepository { save(shippingcost: ShippingCost): Promise; remove(shippingcost: ShippingCost): void; - findOneByGrams(grams: number): Promise; + findOneByWeight(weight: number): Promise; findShippingCosts(): Promise; findOneById(id: string): Promise; } diff --git a/api/src/Domain/Order/ShippingCost.entity.spec.ts b/api/src/Domain/Order/ShippingCost.entity.spec.ts index c337e46..d38197f 100644 --- a/api/src/Domain/Order/ShippingCost.entity.spec.ts +++ b/api/src/Domain/Order/ShippingCost.entity.spec.ts @@ -7,7 +7,7 @@ describe('ShippingCost', () => { 999 ); expect(shippingcost.getId()).toBeUndefined(); - expect(shippingcost.getGrams()).toBe(1000); + expect(shippingcost.getWeight()).toBe(1000); expect(shippingcost.getPrice()).toBe(999); expect(shippingcost.getPriceFromCents()).toBe(9.99); }); @@ -18,12 +18,12 @@ describe('ShippingCost', () => { 999 ); expect(shippingcost.getId()).toBeUndefined(); - expect(shippingcost.getGrams()).toBe(1000); + expect(shippingcost.getWeight()).toBe(1000); expect(shippingcost.getPrice()).toBe(999); expect(shippingcost.getPriceFromCents()).toBe(9.99); shippingcost.update(100, 399); - expect(shippingcost.getGrams()).toBe(100); + expect(shippingcost.getWeight()).toBe(100); expect(shippingcost.getPrice()).toBe(399); expect(shippingcost.getPriceFromCents()).toBe(3.99); }); diff --git a/api/src/Domain/Order/ShippingCost.entity.ts b/api/src/Domain/Order/ShippingCost.entity.ts index ff75ab8..da0f42d 100644 --- a/api/src/Domain/Order/ShippingCost.entity.ts +++ b/api/src/Domain/Order/ShippingCost.entity.ts @@ -6,13 +6,13 @@ export class ShippingCost { private id: string; @Column({ type: 'integer', nullable: false, default: 0 }) - private grams: number; + private weight: number; @Column({ type: 'integer', nullable: false, default: 0 }) private price: number; - constructor(grams: number, price: number) { - this.grams = grams; + constructor(weight: number, price: number) { + this.weight = weight; this.price = price; } @@ -20,8 +20,8 @@ export class ShippingCost { return this.id; } - public getGrams(): number { - return this.grams; + public getWeight(): number { + return this.weight; } public getPrice(): number { @@ -32,8 +32,8 @@ export class ShippingCost { return this.price / 100; } - public update(grams: number, price: number): void { - this.grams = grams; + public update(weight: number, price: number): void { + this.weight = weight; this.price = price; } } diff --git a/api/src/Domain/Order/Specification/IsShippingCostAlreadyExist.spec.ts b/api/src/Domain/Order/Specification/IsShippingCostAlreadyExist.spec.ts index 66fa8c9..fad156f 100644 --- a/api/src/Domain/Order/Specification/IsShippingCostAlreadyExist.spec.ts +++ b/api/src/Domain/Order/Specification/IsShippingCostAlreadyExist.spec.ts @@ -15,20 +15,20 @@ describe('IsShippingCostAlreadyExist', () => { }); it('testShippingCostAlreadyExist', async () => { - when(shippingCostRepository.findOneByGrams(100)).thenResolve( + when(shippingCostRepository.findOneByWeight(100)).thenResolve( new ShippingCost(100, 99) ); expect(await isShippingCostAlreadyExist.isSatisfiedBy(100)).toBe( true ); - verify(shippingCostRepository.findOneByGrams(100)).once(); + verify(shippingCostRepository.findOneByWeight(100)).once(); }); it('testShippingCostDontExist', async () => { - when(shippingCostRepository.findOneByGrams(100)).thenResolve(null); + when(shippingCostRepository.findOneByWeight(100)).thenResolve(null); expect(await isShippingCostAlreadyExist.isSatisfiedBy(100)).toBe( false ); - verify(shippingCostRepository.findOneByGrams(100)).once(); + verify(shippingCostRepository.findOneByWeight(100)).once(); }); }); diff --git a/api/src/Domain/Order/Specification/IsShippingCostAlreadyExist.ts b/api/src/Domain/Order/Specification/IsShippingCostAlreadyExist.ts index fe2aecf..adf1e95 100644 --- a/api/src/Domain/Order/Specification/IsShippingCostAlreadyExist.ts +++ b/api/src/Domain/Order/Specification/IsShippingCostAlreadyExist.ts @@ -8,9 +8,9 @@ export class IsShippingCostAlreadyExist { private readonly shippingcostRepository: IShippingCostRepository ) {} - public async isSatisfiedBy(grams: number): Promise { + public async isSatisfiedBy(weight: number): Promise { return ( - (await this.shippingcostRepository.findOneByGrams(grams)) instanceof ShippingCost + (await this.shippingcostRepository.findOneByWeight(weight)) instanceof ShippingCost ); } } diff --git a/api/src/Domain/Product/Product.entity.spec.ts b/api/src/Domain/Product/Product.entity.spec.ts index 4e76b92..5e9b4a9 100644 --- a/api/src/Domain/Product/Product.entity.spec.ts +++ b/api/src/Domain/Product/Product.entity.spec.ts @@ -5,12 +5,14 @@ describe('Product', () => { const product = new Product( 'Mug', 'Mug avec le portrait de l\'enfant', - 999 + 999, + 1000 ); expect(product.getId()).toBeUndefined(); expect(product.getTitle()).toBe('Mug'); expect(product.getDescription()).toBe('Mug avec le portrait de l\'enfant'); expect(product.getUnitPrice()).toBe(999); + expect(product.getWeight()).toBe(1000); expect(product.getPriceFromCents()).toBe(9.99); }); @@ -18,18 +20,21 @@ describe('Product', () => { const product = new Product( 'Mug', 'Mug avec le portrait de l\'enfant', - 999 + 999, + 1000 ); expect(product.getId()).toBeUndefined(); expect(product.getTitle()).toBe('Mug'); expect(product.getDescription()).toBe('Mug avec le portrait de l\'enfant'); expect(product.getUnitPrice()).toBe(999); + expect(product.getWeight()).toBe(1000); expect(product.getPriceFromCents()).toBe(9.99); - product.update('Porte clef', 'Porte clef portrait', 1000); + product.update('Porte clef', 'Porte clef portrait', 1000, 500); expect(product.getTitle()).toBe('Porte clef'); expect(product.getDescription()).toBe('Porte clef portrait'); expect(product.getUnitPrice()).toBe(1000); + expect(product.getWeight()).toBe(500); expect(product.getPriceFromCents()).toBe(10); }); }); diff --git a/api/src/Domain/Product/Product.entity.ts b/api/src/Domain/Product/Product.entity.ts index e35993d..a45795a 100644 --- a/api/src/Domain/Product/Product.entity.ts +++ b/api/src/Domain/Product/Product.entity.ts @@ -14,10 +14,19 @@ export class Product { @Column({ type: 'integer', nullable: false, default: 0 }) private unitPrice: number; - constructor(title: string, description: string, unitPrice: number) { + @Column({ type: 'integer', nullable: false, default: 0 }) + private weight: number; + + constructor( + title: string, + description: string, + unitPrice: number, + weight: number + ) { this.title = title; this.description = description; this.unitPrice = unitPrice; + this.weight = weight; } public getId(): string { @@ -36,13 +45,23 @@ export class Product { return this.unitPrice; } + public getWeight(): number { + return this.weight; + } + public getPriceFromCents(): number { return this.unitPrice / 100; } - public update(title: string, description: string, unitPrice: number): void { + public update( + title: string, + description: string, + unitPrice: number, + weight: number + ): void { this.title = title; this.description = description; this.unitPrice = unitPrice; + this.weight = weight; } } diff --git a/api/src/Domain/Product/Specification/IsProductAlreadyExist.spec.ts b/api/src/Domain/Product/Specification/IsProductAlreadyExist.spec.ts index 2e7fbdf..5a26415 100644 --- a/api/src/Domain/Product/Specification/IsProductAlreadyExist.spec.ts +++ b/api/src/Domain/Product/Specification/IsProductAlreadyExist.spec.ts @@ -16,7 +16,7 @@ describe('IsProductAlreadyExist', () => { it('testProductAlreadyExist', async () => { when(productRepository.findOneByTitle('Mug')).thenResolve( - new Product('Mug', anything(), anything()) + new Product('Mug', anything(), anything(), anything()) ); expect(await isProductAlreadyExist.isSatisfiedBy('Mug')).toBe( true diff --git a/api/src/Infrastructure/Order/Action/ShippingCost/CreateShippingCostAction.ts b/api/src/Infrastructure/Order/Action/ShippingCost/CreateShippingCostAction.ts index eb157a0..586ed83 100644 --- a/api/src/Infrastructure/Order/Action/ShippingCost/CreateShippingCostAction.ts +++ b/api/src/Infrastructure/Order/Action/ShippingCost/CreateShippingCostAction.ts @@ -29,11 +29,11 @@ export class CreateShippingCostAction { @Roles(UserRole.PHOTOGRAPHER) @ApiOperation({ summary: 'Create new shipping cost' }) public async index(@Body() dto: ShippingCostDTO) { - const { grams, price } = dto; + const { weight, price } = dto; try { const id = await this.commandBus.execute( - new CreateShippingCostCommand(grams, price) + new CreateShippingCostCommand(weight, price) ); return { id }; diff --git a/api/src/Infrastructure/Order/Action/ShippingCost/UpdateShippingCostAction.ts b/api/src/Infrastructure/Order/Action/ShippingCost/UpdateShippingCostAction.ts index 764a1d4..090a247 100644 --- a/api/src/Infrastructure/Order/Action/ShippingCost/UpdateShippingCostAction.ts +++ b/api/src/Infrastructure/Order/Action/ShippingCost/UpdateShippingCostAction.ts @@ -32,9 +32,9 @@ export class UpdateShippingCostAction { @ApiOperation({ summary: 'Update shipping cost' }) public async index(@Param() idDto: IdDTO, @Body() dto: ShippingCostDTO) { try { - const { price, grams } = dto; + const { price, weight } = dto; const id = await this.commandBus.execute( - new UpdateShippingCostCommand(idDto.id, grams, price) + new UpdateShippingCostCommand(idDto.id, weight, price) ); return { id }; diff --git a/api/src/Infrastructure/Order/DTO/ShippingCost.spec.ts b/api/src/Infrastructure/Order/DTO/ShippingCost.spec.ts index 9e36d18..651038b 100644 --- a/api/src/Infrastructure/Order/DTO/ShippingCost.spec.ts +++ b/api/src/Infrastructure/Order/DTO/ShippingCost.spec.ts @@ -4,7 +4,7 @@ import { validate } from 'class-validator'; describe('ShippingCostDTO', () => { it('testValidDTO', async () => { const dto = new ShippingCostDTO(); - dto.grams = 1000; + dto.weight = 1000; dto.price = 9.99; const validation = await validate(dto); @@ -17,7 +17,7 @@ describe('ShippingCostDTO', () => { const validation = await validate(dto); expect(validation).toHaveLength(2); expect(validation[0].constraints).toMatchObject({ - isPositive: 'grams must be a positive number' + isPositive: 'weight must be a positive number' }); expect(validation[1].constraints).toMatchObject({ isPositive: 'price must be a positive number' diff --git a/api/src/Infrastructure/Order/DTO/ShippingCostDTO.ts b/api/src/Infrastructure/Order/DTO/ShippingCostDTO.ts index 1a2acdb..e3c312f 100644 --- a/api/src/Infrastructure/Order/DTO/ShippingCostDTO.ts +++ b/api/src/Infrastructure/Order/DTO/ShippingCostDTO.ts @@ -5,7 +5,7 @@ export class ShippingCostDTO { @ApiProperty() @IsPositive() @IsNotEmpty() - public grams: number; + public weight: number; @ApiProperty() @IsPositive() diff --git a/api/src/Infrastructure/Order/Repository/ShippingCostRepository.ts b/api/src/Infrastructure/Order/Repository/ShippingCostRepository.ts index c265b59..53e32a1 100644 --- a/api/src/Infrastructure/Order/Repository/ShippingCostRepository.ts +++ b/api/src/Infrastructure/Order/Repository/ShippingCostRepository.ts @@ -19,11 +19,11 @@ export class ShippingCostRepository implements IShippingCostRepository { this.repository.delete(shippingCost.getId()); } - public findOneByGrams(grams: number): Promise { + public findOneByWeight(weight: number): Promise { return this.repository .createQueryBuilder('shippingCost') .select([ 'shippingCost.id' ]) - .where('shippingCost.grams = :grams', { grams }) + .where('shippingCost.weight = :weight', { weight }) .getOne(); } @@ -32,7 +32,7 @@ export class ShippingCostRepository implements IShippingCostRepository { .createQueryBuilder('shippingcost') .select([ 'shippingcost.id', - 'shippingcost.grams', + 'shippingcost.weight', 'shippingcost.price' ]) .where('shippingcost.id = :id', { id }) @@ -45,9 +45,9 @@ export class ShippingCostRepository implements IShippingCostRepository { .select([ 'shippingcost.id', 'shippingcost.price', - 'shippingcost.grams' + 'shippingcost.weight' ]) - .orderBy('shippingcost.grams', 'ASC') + .orderBy('shippingcost.weight', 'ASC') .getMany(); } } diff --git a/api/src/Infrastructure/Product/Action/CreateProductAction.ts b/api/src/Infrastructure/Product/Action/CreateProductAction.ts index b62bf1c..33b1c19 100644 --- a/api/src/Infrastructure/Product/Action/CreateProductAction.ts +++ b/api/src/Infrastructure/Product/Action/CreateProductAction.ts @@ -29,11 +29,11 @@ export class CreateProductAction { @Roles(UserRole.PHOTOGRAPHER) @ApiOperation({ summary: 'Create new product' }) public async index(@Body() dto: ProductDTO) { - const { title, description, unitPrice } = dto; + const { title, description, unitPrice, weight } = dto; try { const id = await this.commandBus.execute( - new CreateProductCommand(title, description, unitPrice) + new CreateProductCommand(title, description, unitPrice, weight) ); return { id }; diff --git a/api/src/Infrastructure/Product/Action/UpdateProductAction.ts b/api/src/Infrastructure/Product/Action/UpdateProductAction.ts index b312fb2..0ea8bff 100644 --- a/api/src/Infrastructure/Product/Action/UpdateProductAction.ts +++ b/api/src/Infrastructure/Product/Action/UpdateProductAction.ts @@ -32,9 +32,9 @@ export class UpdateProductAction { @ApiOperation({ summary: 'Update product' }) public async index(@Param() idDto: IdDTO, @Body() dto: ProductDTO) { try { - const { title, description, unitPrice } = dto; + const { title, description, unitPrice, weight } = dto; const id = await this.commandBus.execute( - new UpdateProductCommand(idDto.id, title, unitPrice, description) + new UpdateProductCommand(idDto.id, title, unitPrice, weight, description) ); return { id }; diff --git a/api/src/Infrastructure/Product/DTO/ProductDTO.spec.ts b/api/src/Infrastructure/Product/DTO/ProductDTO.spec.ts index 4c8a203..669b7e7 100644 --- a/api/src/Infrastructure/Product/DTO/ProductDTO.spec.ts +++ b/api/src/Infrastructure/Product/DTO/ProductDTO.spec.ts @@ -7,6 +7,7 @@ describe('ProductDTO', () => { dto.title = 'Mug'; dto.description = 'Mug portrait enfant'; dto.unitPrice = 999; + dto.weight = 1000; const validation = await validate(dto); expect(validation).toHaveLength(0); @@ -16,12 +17,15 @@ describe('ProductDTO', () => { const dto = new ProductDTO(); const validation = await validate(dto); - expect(validation).toHaveLength(2); + expect(validation).toHaveLength(3); expect(validation[0].constraints).toMatchObject({ - isNotEmpty: "title should not be empty" + isNotEmpty: 'title should not be empty' }); expect(validation[1].constraints).toMatchObject({ isPositive: 'unitPrice must be a positive number' }); + expect(validation[2].constraints).toMatchObject({ + isPositive: 'weight must be a positive number' + }); }); }); diff --git a/api/src/Infrastructure/Product/DTO/ProductDTO.ts b/api/src/Infrastructure/Product/DTO/ProductDTO.ts index 6ca8e4d..535c713 100644 --- a/api/src/Infrastructure/Product/DTO/ProductDTO.ts +++ b/api/src/Infrastructure/Product/DTO/ProductDTO.ts @@ -13,4 +13,9 @@ export class ProductDTO { @IsPositive() @IsNotEmpty() public unitPrice: number; + + @ApiProperty() + @IsPositive() + @IsNotEmpty() + public weight: number; } diff --git a/api/src/Infrastructure/Product/Repository/ProductRepository.ts b/api/src/Infrastructure/Product/Repository/ProductRepository.ts index 357b0f8..33b349e 100644 --- a/api/src/Infrastructure/Product/Repository/ProductRepository.ts +++ b/api/src/Infrastructure/Product/Repository/ProductRepository.ts @@ -36,6 +36,7 @@ export class ProductRepository implements IProductRepository { .select([ 'product.id', 'product.title', + 'product.weight', 'product.description', 'product.unitPrice' ]) @@ -43,13 +44,14 @@ export class ProductRepository implements IProductRepository { .getOne(); } - public findProducts(page: number = 1): Promise<[Product[], number]> { + public findProducts(page = 1): Promise<[Product[], number]> { return this.repository .createQueryBuilder('product') .select([ 'product.id', 'product.title', 'product.description', + 'product.weight', 'product.unitPrice' ]) .orderBy('product.title', 'ASC') diff --git a/client/i18n/fr.json b/client/i18n/fr.json index cd13295..29157a3 100644 --- a/client/i18n/fr.json +++ b/client/i18n/fr.json @@ -68,15 +68,15 @@ }, "form": { "price": "Prix", - "grams": "Poids en grammes" + "weight": "Poids en grammes" }, "edit": { "title": "Edition du frais de port" }, "list": { - "grams": "Poids", + "weight": "Poids", "price": "Montant", - "from": "À partir de {grams} grammes" + "from": "À partir de {weight} grammes" }, "errors": { "already_exist": "Un frais de port a déjà été configuré pour ce poids.", @@ -152,7 +152,9 @@ "list": { "title": "Nom du produit", "description": "Description", - "unit_price": "Prix unitaire TTC" + "unit_price": "Prix unitaire TTC", + "weight": "Poids", + "grams": "{weight} grammes" }, "add": { "title": "Ajouter un produit" @@ -166,7 +168,8 @@ "form": { "title": "Nom du produit", "description": "Description", - "unit_price": "Prix unitaire TTC" + "unit_price": "Prix unitaire TTC", + "weight": "Poids en grammes" }, "errors": { "already_exist": "Un produit avec ce nom existe déjà.", diff --git a/client/src/routes/admin/products/[id]/edit.svelte b/client/src/routes/admin/products/[id]/edit.svelte index 01c5bee..ebeed3e 100644 --- a/client/src/routes/admin/products/[id]/edit.svelte +++ b/client/src/routes/admin/products/[id]/edit.svelte @@ -10,10 +10,10 @@ import { onMount } from 'svelte'; import { get, put } from 'utils/axios'; import Breadcrumb from 'components/Breadcrumb.svelte'; - import Form from '../_Form.svelte'; import { errorNormalizer } from 'normalizer/errors'; import ServerErrors from 'components/ServerErrors.svelte'; import H4Title from 'components/H4Title.svelte'; + import Form from '../_Form.svelte'; export let id; @@ -56,6 +56,7 @@ on:save={onSave} title={product.title} description={product.description} + weight={product.weight} unitPrice={product.unitPrice} {loading} /> {/if} diff --git a/client/src/routes/admin/products/_Form.svelte b/client/src/routes/admin/products/_Form.svelte index c19e019..4e4ef4e 100644 --- a/client/src/routes/admin/products/_Form.svelte +++ b/client/src/routes/admin/products/_Form.svelte @@ -6,13 +6,14 @@ export let unitPrice = ''; export let description = ''; + export let weight = ''; export let title = ''; export let loading; const dispatch = createEventDispatcher(); const submit = () => { - dispatch('save', { title, description, unitPrice }); + dispatch('save', { title, description, unitPrice, weight }); }; @@ -30,8 +31,12 @@ type={'money'} label={$_('products.form.unit_price')} bind:value={unitPrice} /> +