Merge branch 'createAD' into 'main'
feat : ad creation to the service See merge request v3/service/ad!3
This commit is contained in:
commit
954962d072
13
.env.dist
13
.env.dist
|
@ -15,3 +15,16 @@ RMQ_EXCHANGE=mobicoop
|
|||
REDIS_HOST=v3-redis
|
||||
REDIS_PASSWORD=redis
|
||||
REDIS_PORT=6379
|
||||
|
||||
# DEFAULT CARPOOL DEPARTURE MARGIN (in seconds)
|
||||
DEPARTURE_MARGIN=900
|
||||
|
||||
# DEFAULT ROLE
|
||||
ROLE=passenger
|
||||
|
||||
# SEATS PROVIDED AS DRIVER / REQUESTED AS PASSENGER
|
||||
SEATS_PROVIDED=3
|
||||
SEATS_REQUESTED=1
|
||||
|
||||
# ACCEPT ONLY SAME FREQUENCY REQUESTS
|
||||
STRICT_FREQUENCY=false
|
|
@ -0,0 +1,8 @@
|
|||
# SERVICE
|
||||
SERVICE_URL=0.0.0.0
|
||||
SERVICE_PORT=5006
|
||||
SERVICE_CONFIGURATION_DOMAIN=AD
|
||||
|
||||
|
||||
# PRISMA
|
||||
DATABASE_URL="postgresql://mobicoop:mobicoop@localhost:5432/mobicoop-test?schema=ad"
|
|
@ -26,6 +26,7 @@
|
|||
"@prisma/client": "^4.13.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"dotenv-cli": "^7.2.1",
|
||||
"ioredis": "^5.3.2",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.2.0"
|
||||
|
@ -3841,7 +3842,6 @@
|
|||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
|
@ -4003,6 +4003,20 @@
|
|||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv-cli": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-7.2.1.tgz",
|
||||
"integrity": "sha512-ODHbGTskqRtXAzZapDPvgNuDVQApu4oKX8lZW7Y0+9hKA6le1ZJlyRS687oU9FXjOVEDU/VFV6zI125HzhM1UQ==",
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.3",
|
||||
"dotenv": "^16.0.0",
|
||||
"dotenv-expand": "^10.0.0",
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
"bin": {
|
||||
"dotenv": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv-expand": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz",
|
||||
|
@ -5354,8 +5368,7 @@
|
|||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
|
||||
},
|
||||
"node_modules/istanbul-lib-coverage": {
|
||||
"version": "3.2.0",
|
||||
|
@ -6798,7 +6811,6 @@
|
|||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
|
@ -7657,7 +7669,6 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
},
|
||||
|
@ -7669,7 +7680,6 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
|
@ -8626,7 +8636,6 @@
|
|||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
},
|
||||
|
|
|
@ -19,13 +19,16 @@
|
|||
"pretty": "./node_modules/.bin/prettier --write .",
|
||||
"test": "npm run migrate:test && dotenv -e .env.test jest",
|
||||
"test:unit": "jest --testPathPattern 'tests/unit/' --verbose",
|
||||
"test:unit:watch": "jest --testPathPattern 'tests/unit/' --verbose --watch",
|
||||
"test:unit:ci": "jest --testPathPattern 'tests/unit/' --coverage",
|
||||
"test:integration": "npm run migrate:test && dotenv -e .env.test -- jest --testPathPattern 'tests/integration/' --verbose",
|
||||
"test:integration:watch": "npm run migrate:test && dotenv -e .env.test -- jest --testPathPattern 'tests/integration/' --verbose --watch",
|
||||
"test:integration:ci": "npm run migrate:test:ci && dotenv -e ci/.env.ci -- jest --testPathPattern 'tests/integration/'",
|
||||
"test:cov": "jest --testPathPattern 'tests/unit/' --coverage",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||
"generate": "docker exec v3-ad-api sh -c 'npx prisma generate'",
|
||||
"migrate": "docker exec v3-ad-api sh -c 'npx prisma migrate dev'",
|
||||
"migrate:init": "docker exec v3-ad-api sh -c 'npx prisma migrate dev --name init'",
|
||||
"migrate:test": "dotenv -e .env.test -- npx prisma migrate deploy",
|
||||
"migrate:test:ci": "dotenv -e ci/.env.ci -- npx prisma migrate deploy",
|
||||
"migrate:deploy": "npx prisma migrate deploy"
|
||||
|
@ -48,6 +51,7 @@
|
|||
"@prisma/client": "^4.13.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"dotenv-cli": "^7.2.1",
|
||||
"ioredis": "^5.3.2",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.2.0"
|
||||
|
@ -100,6 +104,7 @@
|
|||
"**/*.(t|j)s"
|
||||
],
|
||||
"coveragePathIgnorePatterns": [
|
||||
".validator.ts",
|
||||
".controller.ts",
|
||||
".module.ts",
|
||||
".request.ts",
|
||||
|
|
|
@ -1,34 +1,32 @@
|
|||
-- CreateEnum
|
||||
CREATE TYPE "Frequency" AS ENUM ('PUNCTUAL', 'RECURRENT');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "AddressType" AS ENUM ('HOUSE_NUMBER', 'STREET_ADDRESS', 'LOCALITY', 'VENUE', 'OTHER');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ad" (
|
||||
"uuid" UUID NOT NULL,
|
||||
"userUuid" UUID NOT NULL,
|
||||
"driver" BOOLEAN,
|
||||
"passenger" BOOLEAN,
|
||||
"frequency" "Frequency" NOT NULL DEFAULT 'RECURRENT',
|
||||
"driver" BOOLEAN NOT NULL,
|
||||
"passenger" BOOLEAN NOT NULL,
|
||||
"frequency" "Frequency" NOT NULL,
|
||||
"fromDate" DATE NOT NULL,
|
||||
"toDate" DATE,
|
||||
"monTime" TIMESTAMPTZ,
|
||||
"tueTime" TIMESTAMPTZ,
|
||||
"wedTime" TIMESTAMPTZ,
|
||||
"thuTime" TIMESTAMPTZ,
|
||||
"friTime" TIMESTAMPTZ,
|
||||
"satTime" TIMESTAMPTZ,
|
||||
"sunTime" TIMESTAMPTZ,
|
||||
"monMargin" INTEGER,
|
||||
"tueMargin" INTEGER,
|
||||
"wedMargin" INTEGER,
|
||||
"thuMargin" INTEGER,
|
||||
"friMargin" INTEGER,
|
||||
"satMargin" INTEGER,
|
||||
"sunMargin" INTEGER,
|
||||
"seatsDriver" SMALLINT,
|
||||
"seatsPassenger" SMALLINT,
|
||||
"toDate" DATE NOT NULL,
|
||||
"monTime" TEXT,
|
||||
"tueTime" TEXT,
|
||||
"wedTime" TEXT,
|
||||
"thuTime" TEXT,
|
||||
"friTime" TEXT,
|
||||
"satTime" TEXT,
|
||||
"sunTime" TEXT,
|
||||
"monMargin" INTEGER NOT NULL,
|
||||
"tueMargin" INTEGER NOT NULL,
|
||||
"wedMargin" INTEGER NOT NULL,
|
||||
"thuMargin" INTEGER NOT NULL,
|
||||
"friMargin" INTEGER NOT NULL,
|
||||
"satMargin" INTEGER NOT NULL,
|
||||
"sunMargin" INTEGER NOT NULL,
|
||||
"seatsDriver" SMALLINT NOT NULL,
|
||||
"seatsPassenger" SMALLINT NOT NULL,
|
||||
"strict" BOOLEAN NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
|
@ -42,29 +40,17 @@ CREATE TABLE "address" (
|
|||
"position" SMALLINT NOT NULL,
|
||||
"lon" DOUBLE PRECISION NOT NULL,
|
||||
"lat" DOUBLE PRECISION NOT NULL,
|
||||
"name" TEXT,
|
||||
"houseNumber" TEXT,
|
||||
"street" TEXT,
|
||||
"locality" TEXT,
|
||||
"postalCode" TEXT,
|
||||
"country" TEXT,
|
||||
"type" "AddressType" DEFAULT 'OTHER',
|
||||
"country" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "address_pkey" PRIMARY KEY ("uuid")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ad_driver_idx" ON "ad"("driver");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ad_passenger_idx" ON "ad"("passenger");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ad_fromDate_idx" ON "ad"("fromDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ad_toDate_idx" ON "ad"("toDate");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "address" ADD CONSTRAINT "address_adUuid_fkey" FOREIGN KEY ("adUuid") REFERENCES "ad"("uuid") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@ -13,53 +13,50 @@ datasource db {
|
|||
model Ad {
|
||||
uuid String @id @default(uuid()) @db.Uuid
|
||||
userUuid String @db.Uuid
|
||||
driver Boolean?
|
||||
passenger Boolean?
|
||||
frequency Frequency @default(RECURRENT)
|
||||
driver Boolean
|
||||
passenger Boolean
|
||||
frequency Frequency
|
||||
fromDate DateTime @db.Date
|
||||
toDate DateTime? @db.Date
|
||||
monTime DateTime? @db.Timestamptz()
|
||||
tueTime DateTime? @db.Timestamptz()
|
||||
wedTime DateTime? @db.Timestamptz()
|
||||
thuTime DateTime? @db.Timestamptz()
|
||||
friTime DateTime? @db.Timestamptz()
|
||||
satTime DateTime? @db.Timestamptz()
|
||||
sunTime DateTime? @db.Timestamptz()
|
||||
monMargin Int?
|
||||
tueMargin Int?
|
||||
wedMargin Int?
|
||||
thuMargin Int?
|
||||
friMargin Int?
|
||||
satMargin Int?
|
||||
sunMargin Int?
|
||||
seatsDriver Int? @db.SmallInt
|
||||
seatsPassenger Int? @db.SmallInt
|
||||
toDate DateTime @db.Date
|
||||
monTime String?
|
||||
tueTime String?
|
||||
wedTime String?
|
||||
thuTime String?
|
||||
friTime String?
|
||||
satTime String?
|
||||
sunTime String?
|
||||
monMargin Int
|
||||
tueMargin Int
|
||||
wedMargin Int
|
||||
thuMargin Int
|
||||
friMargin Int
|
||||
satMargin Int
|
||||
sunMargin Int
|
||||
seatsDriver Int @db.SmallInt
|
||||
seatsPassenger Int @db.SmallInt
|
||||
strict Boolean
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @default(now()) @updatedAt
|
||||
addresses Address[]
|
||||
|
||||
@@index([driver])
|
||||
@@index([passenger])
|
||||
@@index([fromDate])
|
||||
@@index([toDate])
|
||||
@@map("ad")
|
||||
}
|
||||
|
||||
model Address {
|
||||
uuid String @id @default(uuid()) @db.Uuid
|
||||
adUuid String @db.Uuid
|
||||
position Int @db.SmallInt
|
||||
uuid String @id @default(uuid()) @db.Uuid
|
||||
adUuid String @db.Uuid
|
||||
position Int @db.SmallInt
|
||||
lon Float
|
||||
lat Float
|
||||
name String?
|
||||
houseNumber String?
|
||||
street String?
|
||||
locality String?
|
||||
postalCode String?
|
||||
country String?
|
||||
type AddressType? @default(OTHER)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @default(now()) @updatedAt
|
||||
Ad Ad @relation(fields: [adUuid], references: [uuid], onDelete: Cascade)
|
||||
country String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @default(now()) @updatedAt
|
||||
Ad Ad @relation(fields: [adUuid], references: [uuid], onDelete: Cascade)
|
||||
|
||||
@@map("address")
|
||||
}
|
||||
|
@ -68,11 +65,3 @@ enum Frequency {
|
|||
PUNCTUAL
|
||||
RECURRENT
|
||||
}
|
||||
|
||||
enum AddressType {
|
||||
HOUSE_NUMBER
|
||||
STREET_ADDRESS
|
||||
LOCALITY
|
||||
VENUE
|
||||
OTHER
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import { AdProfile } from './mappers/ad.profile';
|
|||
import { AdsRepository } from './adapters/secondaries/ads.repository';
|
||||
import { Messager } from './adapters/secondaries/messager';
|
||||
import { FindAdByUuidUseCase } from './domain/usecases/find-ad-by-uuid.usecase';
|
||||
import { CreateAdUseCase } from './domain/usecases/create-ad.usecase';
|
||||
import { DefaultParamsProvider } from './adapters/secondaries/default-params.provider';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
@ -29,6 +31,16 @@ import { FindAdByUuidUseCase } from './domain/usecases/find-ad-by-uuid.usecase';
|
|||
}),
|
||||
],
|
||||
controllers: [AdController],
|
||||
providers: [AdProfile, AdsRepository, Messager, FindAdByUuidUseCase],
|
||||
providers: [
|
||||
AdProfile,
|
||||
AdsRepository,
|
||||
Messager,
|
||||
FindAdByUuidUseCase,
|
||||
CreateAdUseCase,
|
||||
{
|
||||
provide: 'ParamsProvider',
|
||||
useClass: DefaultParamsProvider,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AdModule {}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import { Mapper } from '@automapper/core';
|
||||
import { InjectMapper } from '@automapper/nestjs';
|
||||
import { Controller, UsePipes } from '@nestjs/common';
|
||||
import { QueryBus } from '@nestjs/cqrs';
|
||||
import { CommandBus, QueryBus } from '@nestjs/cqrs';
|
||||
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||
import { RpcValidationPipe } from '../../../../utils/pipes/rpc.validation-pipe';
|
||||
import { FindAdByUuidRequest } from '../../domain/dtos/find-ad-by-uuid.request';
|
||||
import { AdPresenter } from './ad.presenter';
|
||||
import { FindAdByUuidQuery } from '../../queries/find-ad-by-uuid.query';
|
||||
import { Ad } from '../../domain/entities/ad';
|
||||
import { CreateAdRequest } from '../../domain/dtos/create-ad.request';
|
||||
import { CreateAdCommand } from '../../commands/create-ad.command';
|
||||
import { DatabaseException } from '../../../database/exceptions/database.exception';
|
||||
|
||||
@UsePipes(
|
||||
new RpcValidationPipe({
|
||||
|
@ -18,6 +21,7 @@ import { Ad } from '../../domain/entities/ad';
|
|||
@Controller()
|
||||
export class AdController {
|
||||
constructor(
|
||||
private readonly _commandBus: CommandBus,
|
||||
private readonly queryBus: QueryBus,
|
||||
@InjectMapper() private readonly _mapper: Mapper,
|
||||
) {}
|
||||
|
@ -25,7 +29,6 @@ export class AdController {
|
|||
@GrpcMethod('AdsService', 'FindOneByUuid')
|
||||
async findOnebyUuid(data: FindAdByUuidRequest): Promise<AdPresenter> {
|
||||
try {
|
||||
console.log('ici');
|
||||
const ad = await this.queryBus.execute(new FindAdByUuidQuery(data));
|
||||
return this._mapper.map(ad, Ad, AdPresenter);
|
||||
} catch (e) {
|
||||
|
@ -35,4 +38,22 @@ export class AdController {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
@GrpcMethod('AdsService', 'Create')
|
||||
async createAd(data: CreateAdRequest): Promise<AdPresenter> {
|
||||
try {
|
||||
const ad = await this._commandBus.execute(new CreateAdCommand(data));
|
||||
return this._mapper.map(ad, Ad, AdPresenter);
|
||||
} catch (e) {
|
||||
if (e instanceof DatabaseException) {
|
||||
if (e.message.includes('Already exists')) {
|
||||
throw new RpcException({
|
||||
code: 6,
|
||||
message: 'Ad already exists',
|
||||
});
|
||||
}
|
||||
}
|
||||
throw new RpcException({});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ package ad;
|
|||
service AdsService {
|
||||
rpc FindOneByUuid(AdByUuid) returns (Ad);
|
||||
rpc FindAll(AdFilter) returns (Ads);
|
||||
rpc Create(Ad) returns (Ad);
|
||||
rpc Create(Ad) returns (AdByUuid);
|
||||
rpc Update(Ad) returns (Ad);
|
||||
rpc Delete(AdByUuid) returns (Empty);
|
||||
}
|
||||
|
@ -19,25 +19,26 @@ message Ad {
|
|||
string userUuid = 2;
|
||||
bool driver = 3;
|
||||
bool passenger = 4;
|
||||
int32 frequency = 5;
|
||||
string fromDate = 6;
|
||||
string toDate = 7;
|
||||
Schedule schedule = 8;
|
||||
MarginDurations marginDurations = 9;
|
||||
int32 seatsPassenger = 10;
|
||||
int32 seatsDriver = 11;
|
||||
bool strict = 12;
|
||||
Addresses addresses = 13;
|
||||
Frequency frequency = 5;
|
||||
optional string departure = 6;
|
||||
string fromDate = 7;
|
||||
string toDate = 8;
|
||||
Schedule schedule = 9;
|
||||
MarginDurations marginDurations = 10;
|
||||
int32 seatsPassenger = 11;
|
||||
int32 seatsDriver = 12;
|
||||
bool strict = 13;
|
||||
repeated Address addresses = 14;
|
||||
}
|
||||
|
||||
message Schedule {
|
||||
string mon = 1;
|
||||
string tue = 2;
|
||||
string wed = 3;
|
||||
string thu = 4;
|
||||
string fri = 5;
|
||||
string sat = 6;
|
||||
string sun = 7;
|
||||
optional string mon = 1;
|
||||
optional string tue = 2;
|
||||
optional string wed = 3;
|
||||
optional string thu = 4;
|
||||
optional string fri = 5;
|
||||
optional string sat = 6;
|
||||
optional string sun = 7;
|
||||
}
|
||||
|
||||
message MarginDurations {
|
||||
|
@ -50,32 +51,28 @@ message MarginDurations {
|
|||
int32 sun = 7;
|
||||
}
|
||||
|
||||
message Addresses {
|
||||
repeated Address address = 1;
|
||||
}
|
||||
|
||||
message Address {
|
||||
float lon = 1;
|
||||
float lat = 2;
|
||||
string houseNumber = 3;
|
||||
string street = 4;
|
||||
string locality = 5;
|
||||
string postalCode = 6;
|
||||
string country = 7;
|
||||
AddressType type = 8;
|
||||
string uuid = 1;
|
||||
int32 position = 2;
|
||||
float lon = 3;
|
||||
float lat = 4;
|
||||
optional string name = 5;
|
||||
optional string houseNumber = 6;
|
||||
optional string street = 7;
|
||||
optional string locality = 8;
|
||||
optional string postalCode = 9;
|
||||
string country = 10;
|
||||
}
|
||||
|
||||
enum AddressType {
|
||||
HOUSE_NUMBER = 1;
|
||||
STREET_ADDRESS = 2;
|
||||
LOCALITY = 3;
|
||||
VENUE = 4;
|
||||
OTHER = 5;
|
||||
|
||||
enum Frequency {
|
||||
PUNCTUAL = 1;
|
||||
RECURRENT = 2;
|
||||
}
|
||||
|
||||
message AdFilter {
|
||||
optional int32 page = 1;
|
||||
optional int32 perPage = 2;
|
||||
int32 page = 1;
|
||||
int32 perPage = 2;
|
||||
}
|
||||
|
||||
message Ads {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { AdRepository } from '../../../database/domain/ad-repository';
|
||||
import { Ad } from '../../domain/entities/ad';
|
||||
|
||||
//TODO : properly implement mutate operation to prisma
|
||||
@Injectable()
|
||||
export class AdsRepository extends AdRepository<Ad> {
|
||||
protected _model = 'ad';
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { DefaultParams } from '../../domain/types/default-params.type';
|
||||
import { IProvideParams } from '../../domain/interfaces/param-provider.interface';
|
||||
|
||||
@Injectable()
|
||||
export class DefaultParamsProvider implements IProvideParams {
|
||||
constructor(private readonly configService: ConfigService) {}
|
||||
getParams = (): DefaultParams => {
|
||||
return {
|
||||
MON_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
|
||||
TUE_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
|
||||
WED_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
|
||||
THU_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
|
||||
FRI_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
|
||||
SAT_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
|
||||
SUN_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
|
||||
DRIVER: this.configService.get('ROLE') == 'driver' ? true : false,
|
||||
SEATS_PROVIDED: parseInt(this.configService.get('SEATS_PROVIDED')),
|
||||
PASSENGER: this.configService.get('ROLE') == 'passenger' ? true : false,
|
||||
SEATS_REQUESTED: parseInt(this.configService.get('SEATS_REQUESTED')),
|
||||
STRICT: false,
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import { CreateAdRequest } from '../domain/dtos/create-ad.request';
|
||||
|
||||
export class CreateAdCommand {
|
||||
readonly createAdRequest: CreateAdRequest;
|
||||
|
||||
constructor(request: CreateAdRequest) {
|
||||
this.createAdRequest = request;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
import { AutoMap } from '@automapper/classes';
|
||||
import {
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsBoolean,
|
||||
IsDate,
|
||||
IsInt,
|
||||
IsEnum,
|
||||
ValidateNested,
|
||||
IsUUID,
|
||||
} from 'class-validator';
|
||||
import { Frequency } from '../types/frequency.enum';
|
||||
import { Address } from '../entities/address';
|
||||
|
||||
export class AdCreation {
|
||||
@IsUUID(4)
|
||||
@AutoMap()
|
||||
uuid: string;
|
||||
|
||||
@IsUUID(4)
|
||||
@AutoMap()
|
||||
userUuid: string;
|
||||
|
||||
@IsBoolean()
|
||||
@AutoMap()
|
||||
driver: boolean;
|
||||
|
||||
@IsBoolean()
|
||||
@AutoMap()
|
||||
passenger: boolean;
|
||||
|
||||
@IsEnum(Frequency)
|
||||
@AutoMap()
|
||||
frequency: Frequency;
|
||||
|
||||
@IsDate()
|
||||
@AutoMap()
|
||||
fromDate: Date;
|
||||
|
||||
@IsDate()
|
||||
@AutoMap()
|
||||
toDate: Date;
|
||||
|
||||
@IsOptional()
|
||||
@IsDate()
|
||||
@AutoMap()
|
||||
monTime?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
tueTime?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
wedTime?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
thuTime?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
friTime?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
satTime?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
sunTime?: string;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
monMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
tueMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
wedMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
thuMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
friMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
satMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
sunMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
seatsDriver: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
seatsPassenger: number;
|
||||
|
||||
@IsBoolean()
|
||||
@AutoMap()
|
||||
strict: boolean;
|
||||
|
||||
@IsDate()
|
||||
@AutoMap()
|
||||
createdAt: Date;
|
||||
|
||||
@IsDate()
|
||||
@AutoMap()
|
||||
updatedAt?: Date;
|
||||
|
||||
@ValidateNested({ each: true })
|
||||
@AutoMap()
|
||||
addresses: { create: Address[] };
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
import { AutoMap } from '@automapper/classes';
|
||||
import {
|
||||
IsOptional,
|
||||
IsBoolean,
|
||||
IsDate,
|
||||
IsInt,
|
||||
IsEnum,
|
||||
ValidateNested,
|
||||
ArrayMinSize,
|
||||
IsUUID,
|
||||
} from 'class-validator';
|
||||
import { Frequency } from '../types/frequency.enum';
|
||||
import { Transform, Type } from 'class-transformer';
|
||||
import { mappingKeyToFrequency } from './validators/frequency.mapping';
|
||||
import { MarginDTO } from './create.margin.dto';
|
||||
import { ScheduleDTO } from './create.schedule.dto';
|
||||
import { AddressRequestDTO } from './create.address.request';
|
||||
import { IsPunctualOrRecurrent } from './validators/decorators/is-punctual-or-recurrent.validator';
|
||||
import { HasProperDriverSeats } from './validators/decorators/has-driver-seats.validator';
|
||||
import { HasProperPassengerSeats } from './validators/decorators/has-passenger-seats.validator';
|
||||
import { HasProperPositionIndexes } from './validators/decorators/address-position.validator';
|
||||
|
||||
export class CreateAdRequest {
|
||||
@IsOptional()
|
||||
@IsUUID(4)
|
||||
@AutoMap()
|
||||
uuid?: string;
|
||||
|
||||
@IsUUID(4)
|
||||
@AutoMap()
|
||||
userUuid: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@AutoMap()
|
||||
driver?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@AutoMap()
|
||||
passenger?: boolean;
|
||||
|
||||
@Transform(({ value }) => mappingKeyToFrequency(value), {
|
||||
toClassOnly: true,
|
||||
})
|
||||
@IsEnum(Frequency)
|
||||
@AutoMap()
|
||||
frequency: Frequency;
|
||||
|
||||
@IsOptional()
|
||||
@IsPunctualOrRecurrent()
|
||||
@Type(() => Date)
|
||||
@IsDate()
|
||||
@AutoMap()
|
||||
departure?: Date;
|
||||
|
||||
@IsOptional()
|
||||
@IsPunctualOrRecurrent()
|
||||
@Type(() => Date)
|
||||
@IsDate()
|
||||
@AutoMap()
|
||||
fromDate?: Date;
|
||||
|
||||
@IsOptional()
|
||||
@IsPunctualOrRecurrent()
|
||||
@Type(() => Date)
|
||||
@IsDate()
|
||||
@AutoMap()
|
||||
toDate?: Date;
|
||||
|
||||
@Type(() => ScheduleDTO)
|
||||
@IsPunctualOrRecurrent()
|
||||
@ValidateNested({ each: true })
|
||||
@AutoMap()
|
||||
schedule: ScheduleDTO = {};
|
||||
|
||||
@IsOptional()
|
||||
@Type(() => MarginDTO)
|
||||
@ValidateNested({ each: true })
|
||||
@AutoMap()
|
||||
marginDurations?: MarginDTO;
|
||||
|
||||
@IsOptional()
|
||||
@HasProperDriverSeats()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
seatsDriver?: number;
|
||||
|
||||
@IsOptional()
|
||||
@HasProperPassengerSeats()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
seatsPassenger?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@AutoMap()
|
||||
strict?: boolean;
|
||||
|
||||
@ArrayMinSize(2)
|
||||
@Type(() => AddressRequestDTO)
|
||||
@HasProperPositionIndexes()
|
||||
@ValidateNested({ each: true })
|
||||
@AutoMap()
|
||||
addresses: AddressRequestDTO[];
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
import { AutoMap } from '@automapper/classes';
|
||||
import {
|
||||
IsInt,
|
||||
IsLatitude,
|
||||
IsLongitude,
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsUUID,
|
||||
} from 'class-validator';
|
||||
|
||||
export class AddressRequestDTO {
|
||||
@IsOptional()
|
||||
@IsUUID(4)
|
||||
@AutoMap()
|
||||
uuid?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsUUID(4)
|
||||
@AutoMap()
|
||||
adUuid?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
position?: number;
|
||||
|
||||
@IsLongitude()
|
||||
@AutoMap()
|
||||
lon: number;
|
||||
|
||||
@IsLatitude()
|
||||
@AutoMap()
|
||||
lat: number;
|
||||
|
||||
@IsOptional()
|
||||
@AutoMap()
|
||||
name?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
houseNumber?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
street?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
locality?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
postalCode?: string;
|
||||
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
country: string;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
import { AutoMap } from '@automapper/classes';
|
||||
import { IsInt, IsOptional } from 'class-validator';
|
||||
|
||||
export class MarginDTO {
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
mon?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
tue?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
wed?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
thu?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
fri?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
sat?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
sun?: number;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
import { AutoMap } from '@automapper/classes';
|
||||
import { IsOptional, IsMilitaryTime } from 'class-validator';
|
||||
|
||||
export class ScheduleDTO {
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
mon?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
tue?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
wed?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
thu?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
fri?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
sat?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
sun?: string;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { AddressRequestDTO } from '../create.address.request';
|
||||
|
||||
export function hasProperPositionIndexes(value: AddressRequestDTO[]) {
|
||||
if (value.every((address) => address.position === undefined)) return true;
|
||||
else if (value.every((address) => typeof address.position === 'number')) {
|
||||
value.sort((a, b) => a.position - b.position);
|
||||
for (let i = 1; i < value.length; i++) {
|
||||
if (value[i - 1].position >= value[i].position) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { ValidateBy, ValidationOptions, buildMessage } from 'class-validator';
|
||||
import { AddressRequestDTO } from '../../create.address.request';
|
||||
import { hasProperPositionIndexes } from '../address-position';
|
||||
|
||||
export function HasProperPositionIndexes(
|
||||
validationOptions?: ValidationOptions,
|
||||
): PropertyDecorator {
|
||||
return ValidateBy(
|
||||
{
|
||||
name: '',
|
||||
constraints: [],
|
||||
validator: {
|
||||
validate: (value: AddressRequestDTO[]): boolean =>
|
||||
hasProperPositionIndexes(value),
|
||||
|
||||
defaultMessage: buildMessage(
|
||||
() =>
|
||||
`indexes position incorrect, please provide a complete list of indexes or ordened list of adresses from start to end of journey`,
|
||||
validationOptions,
|
||||
),
|
||||
},
|
||||
},
|
||||
validationOptions,
|
||||
);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import {
|
||||
ValidateBy,
|
||||
ValidationArguments,
|
||||
ValidationOptions,
|
||||
buildMessage,
|
||||
} from 'class-validator';
|
||||
import { hasProperDriverSeats } from '../has-driver-seats';
|
||||
|
||||
export function HasProperDriverSeats(
|
||||
validationOptions?: ValidationOptions,
|
||||
): PropertyDecorator {
|
||||
return ValidateBy(
|
||||
{
|
||||
name: '',
|
||||
constraints: [],
|
||||
validator: {
|
||||
validate: (value: any, args: ValidationArguments): boolean =>
|
||||
hasProperDriverSeats(args),
|
||||
defaultMessage: buildMessage(
|
||||
() => `driver and driver seats are not correct`,
|
||||
validationOptions,
|
||||
),
|
||||
},
|
||||
},
|
||||
validationOptions,
|
||||
);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import {
|
||||
ValidateBy,
|
||||
ValidationArguments,
|
||||
ValidationOptions,
|
||||
buildMessage,
|
||||
} from 'class-validator';
|
||||
import { hasProperPassengerSeats } from '../has-passenger-seats';
|
||||
|
||||
export function HasProperPassengerSeats(
|
||||
validationOptions?: ValidationOptions,
|
||||
): PropertyDecorator {
|
||||
return ValidateBy(
|
||||
{
|
||||
name: '',
|
||||
constraints: [],
|
||||
validator: {
|
||||
validate: (value, args: ValidationArguments): boolean =>
|
||||
hasProperPassengerSeats(args),
|
||||
defaultMessage: buildMessage(
|
||||
() => `passenger and passenger seats are not correct`,
|
||||
validationOptions,
|
||||
),
|
||||
},
|
||||
},
|
||||
validationOptions,
|
||||
);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import {
|
||||
ValidateBy,
|
||||
ValidationArguments,
|
||||
ValidationOptions,
|
||||
buildMessage,
|
||||
} from 'class-validator';
|
||||
import { isPunctualOrRecurrent } from '../is-punctual-or-recurrent';
|
||||
|
||||
export function IsPunctualOrRecurrent(
|
||||
validationOptions?: ValidationOptions,
|
||||
): PropertyDecorator {
|
||||
return ValidateBy(
|
||||
{
|
||||
name: '',
|
||||
constraints: [],
|
||||
validator: {
|
||||
validate: (value, args: ValidationArguments): boolean =>
|
||||
isPunctualOrRecurrent(args),
|
||||
defaultMessage: buildMessage(
|
||||
() =>
|
||||
`the departure, from date, to date and schedule must be properly set on reccurent or punctual ad `,
|
||||
validationOptions,
|
||||
),
|
||||
},
|
||||
},
|
||||
validationOptions,
|
||||
);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
import { Frequency } from '../../types/frequency.enum';
|
||||
export const mappingKeyToFrequency = (index: number): Frequency => {
|
||||
if (index == 1) return Frequency.PUNCTUAL;
|
||||
if (index == 2) return Frequency.RECURRENT;
|
||||
return undefined;
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
import { ValidationArguments } from 'class-validator';
|
||||
|
||||
export function hasProperDriverSeats(args: ValidationArguments) {
|
||||
if (
|
||||
args.object['driver'] === true &&
|
||||
typeof args.object['seatsDriver'] === 'number'
|
||||
)
|
||||
return args.object['seatsDriver'] > 0;
|
||||
if (
|
||||
(args.object['driver'] === false ||
|
||||
args.object['driver'] === null ||
|
||||
args.object['driver'] === undefined) &&
|
||||
(args.object['seatsDriver'] === 0 ||
|
||||
args.object['seatsDriver'] === null ||
|
||||
args.object['seatsDriver'] === undefined)
|
||||
)
|
||||
return true;
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import { ValidationArguments } from 'class-validator';
|
||||
|
||||
export function hasProperPassengerSeats(args: ValidationArguments) {
|
||||
if (
|
||||
args.object['passenger'] === true &&
|
||||
typeof args.object['seatsPassenger'] === 'number'
|
||||
)
|
||||
return args.object['seatsPassenger'] > 0;
|
||||
else if (
|
||||
(args.object['passenger'] === false ||
|
||||
args.object['passenger'] === null ||
|
||||
args.object['passenger'] === undefined) &&
|
||||
(args.object['seatsPassenger'] === 0 ||
|
||||
args.object['seatsPassenger'] === null ||
|
||||
args.object['seatsPassenger'] === undefined)
|
||||
)
|
||||
return true;
|
||||
else return false;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import { ValidationArguments } from 'class-validator';
|
||||
import { Frequency } from '../../types/frequency.enum';
|
||||
|
||||
function isPunctual(args: ValidationArguments): boolean {
|
||||
if (
|
||||
args.object['frequency'] === Frequency.PUNCTUAL &&
|
||||
args.object['departure'] instanceof Date &&
|
||||
!Object.keys(args.object['schedule']).length
|
||||
)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function isRecurrent(args: ValidationArguments): boolean {
|
||||
if (
|
||||
args.object['frequency'] === Frequency.RECURRENT &&
|
||||
args.object['fromDate'] instanceof Date &&
|
||||
args.object['toDate'] instanceof Date &&
|
||||
Object.keys(args.object['schedule']).length
|
||||
)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
export const isPunctualOrRecurrent = (args: ValidationArguments): boolean => {
|
||||
return isPunctual(args) || isRecurrent(args);
|
||||
};
|
|
@ -1,6 +1,131 @@
|
|||
import { AutoMap } from '@automapper/classes';
|
||||
|
||||
import {
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsBoolean,
|
||||
IsDate,
|
||||
IsInt,
|
||||
IsEnum,
|
||||
ValidateNested,
|
||||
ArrayMinSize,
|
||||
IsUUID,
|
||||
} from 'class-validator';
|
||||
import { Address } from '../entities/address';
|
||||
import { Frequency } from '../types/frequency.enum';
|
||||
export class Ad {
|
||||
@IsUUID(4)
|
||||
@AutoMap()
|
||||
uuid: string;
|
||||
|
||||
@IsUUID(4)
|
||||
@AutoMap()
|
||||
userUuid: string;
|
||||
|
||||
@IsBoolean()
|
||||
@AutoMap()
|
||||
driver: boolean;
|
||||
|
||||
@IsBoolean()
|
||||
@AutoMap()
|
||||
passenger: boolean;
|
||||
|
||||
@IsEnum(Frequency)
|
||||
@AutoMap()
|
||||
frequency: Frequency;
|
||||
|
||||
@IsDate()
|
||||
@AutoMap()
|
||||
fromDate: Date;
|
||||
|
||||
@IsDate()
|
||||
@AutoMap()
|
||||
toDate: Date;
|
||||
|
||||
@IsOptional()
|
||||
@IsDate()
|
||||
@AutoMap()
|
||||
monTime?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
tueTime?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
wedTime?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
thuTime?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
friTime?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
satTime?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
sunTime?: string;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
monMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
tueMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
wedMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
thuMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
friMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
satMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
sunMargin: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
seatsDriver: number;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
seatsPassenger: number;
|
||||
|
||||
@IsBoolean()
|
||||
@AutoMap()
|
||||
strict: boolean;
|
||||
|
||||
@IsDate()
|
||||
@AutoMap()
|
||||
createdAt: Date;
|
||||
|
||||
@IsDate()
|
||||
@AutoMap()
|
||||
updatedAt?: Date;
|
||||
|
||||
@ArrayMinSize(2)
|
||||
@ValidateNested({ each: true })
|
||||
@AutoMap(() => [Address])
|
||||
addresses: Address[];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import { AutoMap } from '@automapper/classes';
|
||||
import { IsInt, IsUUID } from 'class-validator';
|
||||
|
||||
export class Address {
|
||||
@IsUUID(4)
|
||||
@AutoMap()
|
||||
uuid: string;
|
||||
|
||||
@IsUUID(4)
|
||||
@AutoMap()
|
||||
adUuid: string;
|
||||
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
position: number;
|
||||
|
||||
@AutoMap()
|
||||
lon: number;
|
||||
|
||||
@AutoMap()
|
||||
lat: number;
|
||||
|
||||
@AutoMap()
|
||||
name?: string;
|
||||
|
||||
@AutoMap()
|
||||
houseNumber?: string;
|
||||
|
||||
@AutoMap()
|
||||
street?: string;
|
||||
|
||||
@AutoMap()
|
||||
locality: string;
|
||||
|
||||
@AutoMap()
|
||||
postalCode: string;
|
||||
|
||||
@AutoMap()
|
||||
country: string;
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
import { CreateAdRequest } from '../dtos/create-ad.request';
|
||||
|
||||
import { Frequency } from '../types/frequency.enum';
|
||||
|
||||
export class RecurrentNormaliser {
|
||||
fromDateResolver(createAdRequest: CreateAdRequest): Date {
|
||||
if (createAdRequest.frequency === Frequency.PUNCTUAL)
|
||||
return createAdRequest.departure;
|
||||
return createAdRequest.fromDate;
|
||||
}
|
||||
toDateResolver(createAdRequest: CreateAdRequest): Date {
|
||||
if (createAdRequest.frequency === Frequency.PUNCTUAL)
|
||||
return createAdRequest.departure;
|
||||
return createAdRequest.toDate;
|
||||
}
|
||||
scheduleSunResolver(createAdRequest: CreateAdRequest): string {
|
||||
if (
|
||||
Object.keys(createAdRequest.schedule).length === 0 &&
|
||||
createAdRequest.frequency == Frequency.PUNCTUAL &&
|
||||
createAdRequest.departure.getDay() === 0
|
||||
)
|
||||
return `${('0' + createAdRequest.departure.getHours()).slice(-2)}:${(
|
||||
'0' + createAdRequest.departure.getMinutes()
|
||||
).slice(-2)}`;
|
||||
return createAdRequest.schedule.sun;
|
||||
}
|
||||
scheduleMonResolver(createAdRequest: CreateAdRequest): string {
|
||||
if (
|
||||
Object.keys(createAdRequest.schedule).length === 0 &&
|
||||
createAdRequest.frequency == Frequency.PUNCTUAL &&
|
||||
createAdRequest.departure.getDay() === 1
|
||||
) {
|
||||
return `${('0' + createAdRequest.departure.getHours()).slice(-2)}:${(
|
||||
'0' + createAdRequest.departure.getMinutes()
|
||||
).slice(-2)}`;
|
||||
}
|
||||
|
||||
return createAdRequest.schedule.mon;
|
||||
}
|
||||
scheduleTueResolver(createAdRequest: CreateAdRequest): string {
|
||||
if (
|
||||
Object.keys(createAdRequest.schedule).length === 0 &&
|
||||
createAdRequest.frequency == Frequency.PUNCTUAL &&
|
||||
createAdRequest.departure.getDay() === 2
|
||||
)
|
||||
return `${('0' + createAdRequest.departure.getHours()).slice(-2)}:${(
|
||||
'0' + createAdRequest.departure.getMinutes()
|
||||
).slice(-2)}`;
|
||||
return createAdRequest.schedule.tue;
|
||||
}
|
||||
scheduleWedResolver(createAdRequest: CreateAdRequest): string {
|
||||
if (
|
||||
Object.keys(createAdRequest.schedule).length === 0 &&
|
||||
createAdRequest.frequency == Frequency.PUNCTUAL &&
|
||||
createAdRequest.departure.getDay() === 3
|
||||
)
|
||||
return `${('0' + createAdRequest.departure.getHours()).slice(-2)}:${(
|
||||
'0' + createAdRequest.departure.getMinutes()
|
||||
).slice(-2)}`;
|
||||
return createAdRequest.schedule.wed;
|
||||
}
|
||||
scheduleThuResolver(createAdRequest: CreateAdRequest): string {
|
||||
if (
|
||||
Object.keys(createAdRequest.schedule).length === 0 &&
|
||||
createAdRequest.frequency == Frequency.PUNCTUAL &&
|
||||
createAdRequest.departure.getDay() === 4
|
||||
)
|
||||
return `${('0' + createAdRequest.departure.getHours()).slice(-2)}:${(
|
||||
'0' + createAdRequest.departure.getMinutes()
|
||||
).slice(-2)}`;
|
||||
return createAdRequest.schedule.thu;
|
||||
}
|
||||
scheduleFriResolver(createAdRequest: CreateAdRequest): string {
|
||||
if (
|
||||
Object.keys(createAdRequest.schedule).length === 0 &&
|
||||
createAdRequest.frequency == Frequency.PUNCTUAL &&
|
||||
createAdRequest.departure.getDay() === 5
|
||||
)
|
||||
return `${('0' + createAdRequest.departure.getHours()).slice(-2)}:${(
|
||||
'0' + createAdRequest.departure.getMinutes()
|
||||
).slice(-2)}`;
|
||||
return createAdRequest.schedule.fri;
|
||||
}
|
||||
scheduleSatResolver(createAdRequest: CreateAdRequest): string {
|
||||
if (
|
||||
Object.keys(createAdRequest.schedule).length === 0 &&
|
||||
createAdRequest.frequency == Frequency.PUNCTUAL &&
|
||||
createAdRequest.departure.getDay() === 6
|
||||
)
|
||||
return `${('0' + createAdRequest.departure.getHours()).slice(-2)}:${(
|
||||
'0' + createAdRequest.departure.getMinutes()
|
||||
).slice(-2)}`;
|
||||
return createAdRequest.schedule.sat;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
import { DefaultParams } from '../types/default-params.type';
|
||||
export interface IProvideParams {
|
||||
getParams(): DefaultParams;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
export type DefaultParams = {
|
||||
MON_MARGIN: number;
|
||||
TUE_MARGIN: number;
|
||||
WED_MARGIN: number;
|
||||
THU_MARGIN: number;
|
||||
FRI_MARGIN: number;
|
||||
SAT_MARGIN: number;
|
||||
SUN_MARGIN: number;
|
||||
DRIVER: boolean;
|
||||
SEATS_PROVIDED: number;
|
||||
PASSENGER: boolean;
|
||||
SEATS_REQUESTED: number;
|
||||
STRICT: boolean;
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
export enum Frequency {
|
||||
PUNCTUAL = 'PUNCTUAL',
|
||||
RECURRENT = 'RECURRENT',
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
import { Mapper } from '@automapper/core';
|
||||
import { InjectMapper } from '@automapper/nestjs';
|
||||
import { Inject } from '@nestjs/common';
|
||||
import { CommandHandler } from '@nestjs/cqrs';
|
||||
import { Messager } from '../../adapters/secondaries/messager';
|
||||
import { AdsRepository } from '../../adapters/secondaries/ads.repository';
|
||||
import { CreateAdCommand } from '../../commands/create-ad.command';
|
||||
import { CreateAdRequest } from '../dtos/create-ad.request';
|
||||
|
||||
import { IProvideParams } from '../interfaces/param-provider.interface';
|
||||
import { DefaultParams } from '../types/default-params.type';
|
||||
import { AdCreation } from '../dtos/ad.creation';
|
||||
import { Ad } from '../entities/ad';
|
||||
|
||||
@CommandHandler(CreateAdCommand)
|
||||
export class CreateAdUseCase {
|
||||
private readonly defaultParams: DefaultParams;
|
||||
private ad: AdCreation;
|
||||
constructor(
|
||||
private readonly _repository: AdsRepository,
|
||||
private readonly _messager: Messager,
|
||||
@InjectMapper() private readonly _mapper: Mapper,
|
||||
@Inject('ParamsProvider')
|
||||
private readonly defaultParamsProvider: IProvideParams,
|
||||
) {
|
||||
this.defaultParams = defaultParamsProvider.getParams();
|
||||
}
|
||||
|
||||
async execute(command: CreateAdCommand): Promise<Ad> {
|
||||
this.ad = this._mapper.map(
|
||||
command.createAdRequest,
|
||||
CreateAdRequest,
|
||||
AdCreation,
|
||||
);
|
||||
this.setDefaultSchedule();
|
||||
this.setDefaultAddressesPosition();
|
||||
this.setDefaultDriverAndPassengerParameters();
|
||||
this.setDefaultDistanceMargin();
|
||||
|
||||
try {
|
||||
const adCreated: Ad = await this._repository.create(this.ad);
|
||||
this._messager.publish('ad.create', JSON.stringify(adCreated));
|
||||
this._messager.publish(
|
||||
'logging.ad.create.info',
|
||||
JSON.stringify(adCreated),
|
||||
);
|
||||
return adCreated;
|
||||
} catch (error) {
|
||||
let key = 'logging.ad.create.crit';
|
||||
if (error.message.includes('Already exists')) {
|
||||
key = 'logging.ad.create.warning';
|
||||
}
|
||||
this._messager.publish(
|
||||
key,
|
||||
JSON.stringify({
|
||||
command,
|
||||
error,
|
||||
}),
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
setDefaultSchedule(): void {
|
||||
if (this.ad.monMargin === undefined)
|
||||
this.ad.monMargin = this.defaultParams.MON_MARGIN;
|
||||
if (this.ad.tueMargin === undefined)
|
||||
this.ad.tueMargin = this.defaultParams.TUE_MARGIN;
|
||||
if (this.ad.wedMargin === undefined)
|
||||
this.ad.wedMargin = this.defaultParams.WED_MARGIN;
|
||||
if (this.ad.thuMargin === undefined)
|
||||
this.ad.thuMargin = this.defaultParams.THU_MARGIN;
|
||||
if (this.ad.friMargin === undefined)
|
||||
this.ad.friMargin = this.defaultParams.FRI_MARGIN;
|
||||
if (this.ad.satMargin === undefined)
|
||||
this.ad.satMargin = this.defaultParams.SAT_MARGIN;
|
||||
if (this.ad.sunMargin === undefined)
|
||||
this.ad.sunMargin = this.defaultParams.SUN_MARGIN;
|
||||
}
|
||||
setDefaultDistanceMargin(): void {
|
||||
if (this.ad.strict === undefined)
|
||||
this.ad.strict = this.defaultParams.STRICT;
|
||||
}
|
||||
setDefaultDriverAndPassengerParameters(): void {
|
||||
if (!this.ad.driver && !this.ad.passenger) {
|
||||
this.ad.driver = this.defaultParams.DRIVER;
|
||||
this.ad.seatsDriver = this.defaultParams.SEATS_PROVIDED;
|
||||
this.ad.passenger = this.defaultParams.PASSENGER;
|
||||
this.ad.seatsPassenger = this.defaultParams.SEATS_REQUESTED;
|
||||
} else {
|
||||
if (!this.ad.driver) {
|
||||
this.ad.driver = false;
|
||||
this.ad.seatsDriver = 0;
|
||||
}
|
||||
if (!this.ad.passenger) {
|
||||
this.ad.passenger = false;
|
||||
this.ad.seatsPassenger = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
setDefaultAddressesPosition(): void {
|
||||
if (this.ad.addresses.create[0].position === undefined) {
|
||||
for (let i = 0; i < this.ad.addresses.create.length; i++) {
|
||||
this.ad.addresses.create[i].position = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +1,139 @@
|
|||
import { createMap, Mapper } from '@automapper/core';
|
||||
import { createMap, forMember, mapFrom, Mapper } from '@automapper/core';
|
||||
import { AutomapperProfile, InjectMapper } from '@automapper/nestjs';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Ad } from '../domain/entities/ad';
|
||||
import { AdPresenter } from '../adapters/primaries/ad.presenter';
|
||||
import { CreateAdRequest } from '../domain/dtos/create-ad.request';
|
||||
import { AdCreation } from '../domain/dtos/ad.creation';
|
||||
import { RecurrentNormaliser } from '../domain/entities/recurrent-normaliser';
|
||||
|
||||
@Injectable()
|
||||
export class AdProfile extends AutomapperProfile {
|
||||
recurrentNormaliser = new RecurrentNormaliser();
|
||||
constructor(@InjectMapper() mapper: Mapper) {
|
||||
super(mapper);
|
||||
}
|
||||
|
||||
override get profile() {
|
||||
return (mapper) => {
|
||||
createMap(mapper, Ad, AdPresenter);
|
||||
createMap(
|
||||
mapper,
|
||||
CreateAdRequest,
|
||||
AdCreation,
|
||||
|
||||
forMember(
|
||||
(destination) => destination.monMargin,
|
||||
mapFrom((source) => source.marginDurations.mon),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.tueMargin,
|
||||
mapFrom((source) => source.marginDurations.tue),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.wedMargin,
|
||||
mapFrom((source) => source.marginDurations.wed),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.thuMargin,
|
||||
mapFrom((source) => source.marginDurations.thu),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.friMargin,
|
||||
mapFrom((source) => source.marginDurations.fri),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.satMargin,
|
||||
mapFrom((source) => source.marginDurations.sat),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.sunMargin,
|
||||
mapFrom((source) => source.marginDurations.sun),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.monTime,
|
||||
mapFrom((source) => source.schedule.mon),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.tueTime,
|
||||
mapFrom((source) => source.schedule.tue),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.wedTime,
|
||||
mapFrom((source) => source.schedule.wed),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.thuTime,
|
||||
mapFrom((source) => source.schedule.thu),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.friTime,
|
||||
mapFrom((source) => source.schedule.fri),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.satTime,
|
||||
mapFrom((source) => source.schedule.sat),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.sunTime,
|
||||
mapFrom((source) => source.schedule.sun),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.addresses.create,
|
||||
mapFrom((source) => source.addresses),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.fromDate,
|
||||
mapFrom((source) =>
|
||||
this.recurrentNormaliser.fromDateResolver(source),
|
||||
),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.toDate,
|
||||
mapFrom((source) => this.recurrentNormaliser.toDateResolver(source)),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.monTime,
|
||||
mapFrom((source) =>
|
||||
this.recurrentNormaliser.scheduleMonResolver(source),
|
||||
),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.tueTime,
|
||||
mapFrom((source) =>
|
||||
this.recurrentNormaliser.scheduleTueResolver(source),
|
||||
),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.wedTime,
|
||||
mapFrom((source) =>
|
||||
this.recurrentNormaliser.scheduleWedResolver(source),
|
||||
),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.thuTime,
|
||||
mapFrom((source) =>
|
||||
this.recurrentNormaliser.scheduleThuResolver(source),
|
||||
),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.friTime,
|
||||
mapFrom((source) =>
|
||||
this.recurrentNormaliser.scheduleFriResolver(source),
|
||||
),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.satTime,
|
||||
mapFrom((source) =>
|
||||
this.recurrentNormaliser.scheduleSatResolver(source),
|
||||
),
|
||||
),
|
||||
forMember(
|
||||
(destination) => destination.sunTime,
|
||||
mapFrom((source) =>
|
||||
this.recurrentNormaliser.scheduleSunResolver(source),
|
||||
),
|
||||
),
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import { Mapper, createMap } from '@automapper/core';
|
||||
import { AutomapperProfile, InjectMapper } from '@automapper/nestjs';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AddressRequestDTO } from '../domain/dtos/create.address.request';
|
||||
import { Address } from '../domain/entities/address';
|
||||
|
||||
@Injectable()
|
||||
export class AdProfile extends AutomapperProfile {
|
||||
constructor(@InjectMapper() mapper: Mapper) {
|
||||
super(mapper);
|
||||
}
|
||||
|
||||
override get profile() {
|
||||
return (mapper) => {
|
||||
createMap(mapper, AddressRequestDTO, Address);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,468 @@
|
|||
import { Test } from '@nestjs/testing';
|
||||
import { PrismaService } from '../../../database/adapters/secondaries/prisma-service';
|
||||
import { AdsRepository } from '../../adapters/secondaries/ads.repository';
|
||||
import { DatabaseModule } from '../../../database/database.module';
|
||||
import { Frequency } from '../../domain/types/frequency.enum';
|
||||
import { AdCreation } from '../../domain/dtos/ad.creation';
|
||||
import { Address } from '../../domain/entities/address';
|
||||
|
||||
describe('Ad Repository', () => {
|
||||
let prismaService: PrismaService;
|
||||
let adsRepository: AdsRepository;
|
||||
|
||||
const executeInsertCommand = async (table: string, object: any) => {
|
||||
const command = `INSERT INTO ${table} ("${Object.keys(object).join(
|
||||
'","',
|
||||
)}") VALUES (${Object.values(object).join(',')})`;
|
||||
|
||||
await prismaService.$executeRawUnsafe(command);
|
||||
};
|
||||
const getSeed = (index: number, uuid: string): string => {
|
||||
return `'${uuid.slice(0, -2)}${index.toString(16).padStart(2, '0')}'`;
|
||||
};
|
||||
const baseUuid = {
|
||||
uuid: 'be459a29-7a41-4c0b-b371-abe90bfb6f00',
|
||||
};
|
||||
const baseAdress0Uuid = {
|
||||
uuid: 'bad5e786-3b15-4e51-a8fc-926fa9327ff1',
|
||||
};
|
||||
const baseAdress1Uuid = {
|
||||
uuid: '4d200eb6-7389-487f-a1ca-dbc0e40381c9',
|
||||
};
|
||||
const baseUserUuid = {
|
||||
userUuid: "'113e0000-0000-4000-a000-000000000000'",
|
||||
};
|
||||
const driverAd = {
|
||||
driver: 'true',
|
||||
passenger: 'false',
|
||||
seatsDriver: 3,
|
||||
seatsPassenger: 0,
|
||||
strict: 'false',
|
||||
};
|
||||
const passengerAd = {
|
||||
driver: 'false',
|
||||
passenger: 'true',
|
||||
seatsDriver: 0,
|
||||
seatsPassenger: 1,
|
||||
strict: 'false',
|
||||
};
|
||||
const driverAndPassengerAd = {
|
||||
driver: 'true',
|
||||
passenger: 'true',
|
||||
seatsDriver: 3,
|
||||
seatsPassenger: 1,
|
||||
strict: 'false',
|
||||
};
|
||||
const punctualAd = {
|
||||
frequency: `'PUNCTUAL'`,
|
||||
fromDate: `'2023-01-01'`,
|
||||
toDate: `'2023-01-01'`,
|
||||
monTime: 'NULL',
|
||||
tueTime: 'NULL',
|
||||
wedTime: 'NULL',
|
||||
thuTime: 'NULL',
|
||||
friTime: 'NULL',
|
||||
satTime: 'NULL',
|
||||
sunTime: `'07:00'`,
|
||||
monMargin: 900,
|
||||
tueMargin: 900,
|
||||
wedMargin: 900,
|
||||
thuMargin: 900,
|
||||
friMargin: 900,
|
||||
satMargin: 900,
|
||||
sunMargin: 900,
|
||||
};
|
||||
const recurrentAd = {
|
||||
frequency: `'RECURRENT'`,
|
||||
fromDate: `'2023-01-01'`,
|
||||
toDate: `'2023-12-31'`,
|
||||
monTime: `'07:00'`,
|
||||
tueTime: `'07:00'`,
|
||||
wedTime: `'07:00'`,
|
||||
thuTime: `'07:00'`,
|
||||
friTime: `'07:00'`,
|
||||
satTime: 'NULL',
|
||||
sunTime: 'NULL',
|
||||
monMargin: 900,
|
||||
tueMargin: 900,
|
||||
wedMargin: 900,
|
||||
thuMargin: 900,
|
||||
friMargin: 900,
|
||||
satMargin: 900,
|
||||
sunMargin: 900,
|
||||
};
|
||||
|
||||
const address0 = {
|
||||
position: 0,
|
||||
lon: 43.7102,
|
||||
lat: 7.262,
|
||||
locality: "'Nice'",
|
||||
postalCode: "'06000'",
|
||||
country: "'France'",
|
||||
};
|
||||
const address1 = {
|
||||
position: 1,
|
||||
lon: 43.2965,
|
||||
lat: 5.3698,
|
||||
locality: "'Marseille'",
|
||||
postalCode: "'13000'",
|
||||
country: "'France'",
|
||||
};
|
||||
const createPunctualDriverAds = async (nbToCreate = 10) => {
|
||||
const adToCreate = {
|
||||
...baseUuid,
|
||||
...baseUserUuid,
|
||||
...driverAd,
|
||||
...punctualAd,
|
||||
};
|
||||
for (let i = 0; i < nbToCreate; i++) {
|
||||
adToCreate.uuid = getSeed(i, baseUuid.uuid);
|
||||
await executeInsertCommand('ad', adToCreate);
|
||||
await executeInsertCommand('address', {
|
||||
uuid: getSeed(i, baseAdress0Uuid.uuid),
|
||||
adUuid: adToCreate.uuid,
|
||||
...address0,
|
||||
});
|
||||
await executeInsertCommand('address', {
|
||||
uuid: getSeed(i, baseAdress1Uuid.uuid),
|
||||
adUuid: adToCreate.uuid,
|
||||
...address1,
|
||||
});
|
||||
}
|
||||
};
|
||||
const createRecurrentDriverAds = async (nbToCreate = 10) => {
|
||||
const adToCreate = {
|
||||
...baseUuid,
|
||||
...baseUserUuid,
|
||||
...driverAd,
|
||||
...punctualAd,
|
||||
};
|
||||
for (let i = 0; i < nbToCreate; i++) {
|
||||
adToCreate.uuid = getSeed(i, baseUuid.uuid);
|
||||
await executeInsertCommand('ad', adToCreate);
|
||||
await executeInsertCommand('address', {
|
||||
uuid: getSeed(i, baseAdress0Uuid.uuid),
|
||||
adUuid: adToCreate.uuid,
|
||||
...address0,
|
||||
});
|
||||
await executeInsertCommand('address', {
|
||||
uuid: getSeed(i, baseAdress1Uuid.uuid),
|
||||
adUuid: adToCreate.uuid,
|
||||
...address1,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const createPunctualPassengerAds = async (nbToCreate = 10) => {
|
||||
const adToCreate = {
|
||||
...baseUuid,
|
||||
...baseUserUuid,
|
||||
...passengerAd,
|
||||
...punctualAd,
|
||||
};
|
||||
for (let i = 0; i < nbToCreate; i++) {
|
||||
adToCreate.uuid = getSeed(i, baseUuid.uuid);
|
||||
await executeInsertCommand('ad', adToCreate);
|
||||
await executeInsertCommand('address', {
|
||||
uuid: getSeed(i, baseAdress0Uuid.uuid),
|
||||
adUuid: adToCreate.uuid,
|
||||
...address0,
|
||||
});
|
||||
await executeInsertCommand('address', {
|
||||
uuid: getSeed(i, baseAdress1Uuid.uuid),
|
||||
adUuid: adToCreate.uuid,
|
||||
...address1,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const createRecurrentPassengerAds = async (nbToCreate = 10) => {
|
||||
const adToCreate = {
|
||||
...baseUuid,
|
||||
...baseUserUuid,
|
||||
...passengerAd,
|
||||
...recurrentAd,
|
||||
};
|
||||
for (let i = 0; i < nbToCreate; i++) {
|
||||
adToCreate.uuid = getSeed(i, baseUuid.uuid);
|
||||
await executeInsertCommand('ad', adToCreate);
|
||||
await executeInsertCommand('address', {
|
||||
uuid: getSeed(i, baseAdress0Uuid.uuid),
|
||||
adUuid: adToCreate.uuid,
|
||||
...address0,
|
||||
});
|
||||
await executeInsertCommand('address', {
|
||||
uuid: getSeed(i, baseAdress1Uuid.uuid),
|
||||
adUuid: adToCreate.uuid,
|
||||
...address1,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const createPunctualDriverPassengerAds = async (nbToCreate = 10) => {
|
||||
const adToCreate = {
|
||||
...baseUuid,
|
||||
...baseUserUuid,
|
||||
...driverAndPassengerAd,
|
||||
...punctualAd,
|
||||
};
|
||||
for (let i = 0; i < nbToCreate; i++) {
|
||||
adToCreate.uuid = getSeed(i, baseUuid.uuid);
|
||||
await executeInsertCommand('ad', adToCreate);
|
||||
await executeInsertCommand('address', {
|
||||
uuid: getSeed(i, baseAdress0Uuid.uuid),
|
||||
adUuid: adToCreate.uuid,
|
||||
...address0,
|
||||
});
|
||||
await executeInsertCommand('address', {
|
||||
uuid: getSeed(i, baseAdress1Uuid.uuid),
|
||||
adUuid: adToCreate.uuid,
|
||||
...address1,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const createRecurrentDriverPassengerAds = async (nbToCreate = 10) => {
|
||||
const adToCreate = {
|
||||
...baseUuid,
|
||||
...baseUserUuid,
|
||||
...driverAndPassengerAd,
|
||||
...recurrentAd,
|
||||
};
|
||||
for (let i = 0; i < nbToCreate; i++) {
|
||||
adToCreate.uuid = getSeed(i, baseUuid.uuid);
|
||||
await executeInsertCommand('ad', adToCreate);
|
||||
await executeInsertCommand('address', {
|
||||
uuid: getSeed(i, baseAdress0Uuid.uuid),
|
||||
adUuid: adToCreate.uuid,
|
||||
...address0,
|
||||
});
|
||||
await executeInsertCommand('address', {
|
||||
uuid: getSeed(i, baseAdress1Uuid.uuid),
|
||||
adUuid: adToCreate.uuid,
|
||||
...address1,
|
||||
});
|
||||
}
|
||||
};
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [DatabaseModule],
|
||||
providers: [PrismaService, AdsRepository],
|
||||
}).compile();
|
||||
prismaService = module.get<PrismaService>(PrismaService);
|
||||
adsRepository = module.get<AdsRepository>(AdsRepository);
|
||||
});
|
||||
afterAll(async () => {
|
||||
await prismaService.$disconnect();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await prismaService.ad.deleteMany();
|
||||
});
|
||||
describe('findAll', () => {
|
||||
it('should return an empty data array', async () => {
|
||||
const res = await adsRepository.findAll();
|
||||
expect(res).toEqual({
|
||||
data: [],
|
||||
total: 0,
|
||||
});
|
||||
});
|
||||
|
||||
describe('drivers', () => {
|
||||
it('should return a data array with 8 punctual driver ads', async () => {
|
||||
await createPunctualDriverAds(8);
|
||||
const ads = await adsRepository.findAll();
|
||||
expect(ads.data.length).toBe(8);
|
||||
expect(ads.total).toBe(8);
|
||||
expect(ads.data[0].driver).toBeTruthy();
|
||||
expect(ads.data[0].passenger).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should return a data array limited to 10 punctual driver ads', async () => {
|
||||
await createPunctualDriverAds(20);
|
||||
const ads = await adsRepository.findAll();
|
||||
expect(ads.data.length).toBe(10);
|
||||
expect(ads.total).toBe(20);
|
||||
expect(ads.data[1].driver).toBeTruthy();
|
||||
expect(ads.data[1].passenger).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should return a data array with 8 recurrent driver ads', async () => {
|
||||
await createRecurrentDriverAds(8);
|
||||
const ads = await adsRepository.findAll();
|
||||
expect(ads.data.length).toBe(8);
|
||||
expect(ads.total).toBe(8);
|
||||
expect(ads.data[2].driver).toBeTruthy();
|
||||
expect(ads.data[2].passenger).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should return a data array limited to 10 recurrent driver ads', async () => {
|
||||
await createRecurrentDriverAds(20);
|
||||
const ads = await adsRepository.findAll();
|
||||
expect(ads.data.length).toBe(10);
|
||||
expect(ads.total).toBe(20);
|
||||
expect(ads.data[3].driver).toBeTruthy();
|
||||
expect(ads.data[3].passenger).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('passengers', () => {
|
||||
it('should return a data array with 7 punctual passenger ads', async () => {
|
||||
await createPunctualPassengerAds(7);
|
||||
const ads = await adsRepository.findAll();
|
||||
expect(ads.data.length).toBe(7);
|
||||
expect(ads.total).toBe(7);
|
||||
expect(ads.data[0].passenger).toBeTruthy();
|
||||
expect(ads.data[0].driver).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should return a data array limited to 10 punctual passenger ads', async () => {
|
||||
await createPunctualPassengerAds(15);
|
||||
const ads = await adsRepository.findAll();
|
||||
expect(ads.data.length).toBe(10);
|
||||
expect(ads.total).toBe(15);
|
||||
expect(ads.data[1].passenger).toBeTruthy();
|
||||
expect(ads.data[1].driver).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should return a data array with 7 recurrent passenger ads', async () => {
|
||||
await createRecurrentPassengerAds(7);
|
||||
const ads = await adsRepository.findAll();
|
||||
expect(ads.data.length).toBe(7);
|
||||
expect(ads.total).toBe(7);
|
||||
expect(ads.data[2].passenger).toBeTruthy();
|
||||
expect(ads.data[2].driver).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should return a data array limited to 10 recurrent passenger ads', async () => {
|
||||
await createRecurrentPassengerAds(15);
|
||||
const ads = await adsRepository.findAll();
|
||||
expect(ads.data.length).toBe(10);
|
||||
expect(ads.total).toBe(15);
|
||||
expect(ads.data[3].passenger).toBeTruthy();
|
||||
expect(ads.data[3].driver).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('drivers and passengers', () => {
|
||||
it('should return a data array with 6 punctual driver and passenger ads', async () => {
|
||||
await createPunctualDriverPassengerAds(6);
|
||||
const ads = await adsRepository.findAll();
|
||||
expect(ads.data.length).toBe(6);
|
||||
expect(ads.total).toBe(6);
|
||||
expect(ads.data[0].passenger).toBeTruthy();
|
||||
expect(ads.data[0].driver).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return a data array limited to 10 punctual driver and passenger ads', async () => {
|
||||
await createPunctualDriverPassengerAds(16);
|
||||
const ads = await adsRepository.findAll();
|
||||
expect(ads.data.length).toBe(10);
|
||||
expect(ads.total).toBe(16);
|
||||
expect(ads.data[1].passenger).toBeTruthy();
|
||||
expect(ads.data[1].driver).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return a data array with 6 recurrent driver and passenger ads', async () => {
|
||||
await createRecurrentDriverPassengerAds(6);
|
||||
const ads = await adsRepository.findAll();
|
||||
expect(ads.data.length).toBe(6);
|
||||
expect(ads.total).toBe(6);
|
||||
expect(ads.data[2].passenger).toBeTruthy();
|
||||
expect(ads.data[2].driver).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return a data array limited to 10 recurrent driver and passenger ads', async () => {
|
||||
await createRecurrentDriverPassengerAds(16);
|
||||
const ads = await adsRepository.findAll();
|
||||
expect(ads.data.length).toBe(10);
|
||||
expect(ads.total).toBe(16);
|
||||
expect(ads.data[3].passenger).toBeTruthy();
|
||||
expect(ads.data[3].driver).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('findOneByUuid', () => {
|
||||
it('should return an ad', async () => {
|
||||
await createPunctualDriverAds(1);
|
||||
const ad = await adsRepository.findOneByUuid(baseUuid.uuid);
|
||||
|
||||
expect(ad.uuid).toBe(baseUuid.uuid);
|
||||
});
|
||||
|
||||
it('should return null', async () => {
|
||||
const ad = await adsRepository.findOneByUuid(
|
||||
'544572be-11fb-4244-8235-587221fc9104',
|
||||
);
|
||||
expect(ad).toBeNull();
|
||||
});
|
||||
});
|
||||
describe('create', () => {
|
||||
it('should create an punctual ad', async () => {
|
||||
const beforeCount = await prismaService.ad.count();
|
||||
const adToCreate: AdCreation = new AdCreation();
|
||||
|
||||
adToCreate.uuid = 'be459a29-7a41-4c0b-b371-abe90bfb6f00';
|
||||
adToCreate.userUuid = '4e52b54d-a729-4dbd-9283-f84a11bb2200';
|
||||
adToCreate.driver = true;
|
||||
adToCreate.passenger = false;
|
||||
adToCreate.frequency = Frequency.PUNCTUAL;
|
||||
adToCreate.fromDate = new Date('05-22-2023 09:36');
|
||||
adToCreate.toDate = new Date('05-22-2023 09:36');
|
||||
adToCreate.monTime = '09:36';
|
||||
adToCreate.monMargin = 900;
|
||||
adToCreate.tueMargin = 900;
|
||||
adToCreate.wedMargin = 900;
|
||||
adToCreate.thuMargin = 900;
|
||||
adToCreate.friMargin = 900;
|
||||
adToCreate.satMargin = 900;
|
||||
adToCreate.sunMargin = 900;
|
||||
adToCreate.seatsDriver = 3;
|
||||
adToCreate.seatsPassenger = 0;
|
||||
adToCreate.strict = false;
|
||||
adToCreate.addresses = {
|
||||
create: [address0 as Address, address1 as Address],
|
||||
};
|
||||
const ad = await adsRepository.create(adToCreate);
|
||||
|
||||
const afterCount = await prismaService.ad.count();
|
||||
|
||||
expect(afterCount - beforeCount).toBe(1);
|
||||
expect(ad.uuid).toBe('be459a29-7a41-4c0b-b371-abe90bfb6f00');
|
||||
});
|
||||
it('should create an recurrent ad', async () => {
|
||||
const beforeCount = await prismaService.ad.count();
|
||||
const adToCreate: AdCreation = new AdCreation();
|
||||
|
||||
adToCreate.uuid = '137a26fa-4b38-48ba-aecf-1a75f6b20f3d';
|
||||
adToCreate.userUuid = '4e52b54d-a729-4dbd-9283-f84a11bb2200';
|
||||
adToCreate.driver = true;
|
||||
adToCreate.passenger = false;
|
||||
adToCreate.frequency = Frequency.RECURRENT;
|
||||
adToCreate.fromDate = new Date('01-15-2023 ');
|
||||
adToCreate.toDate = new Date('10-31-2023');
|
||||
adToCreate.monTime = '07:30';
|
||||
adToCreate.friTime = '07:45';
|
||||
adToCreate.thuTime = '08:00';
|
||||
adToCreate.monMargin = 900;
|
||||
adToCreate.tueMargin = 900;
|
||||
adToCreate.wedMargin = 900;
|
||||
adToCreate.thuMargin = 900;
|
||||
adToCreate.friMargin = 900;
|
||||
adToCreate.satMargin = 900;
|
||||
adToCreate.sunMargin = 900;
|
||||
adToCreate.seatsDriver = 2;
|
||||
adToCreate.seatsPassenger = 0;
|
||||
adToCreate.strict = false;
|
||||
adToCreate.addresses = {
|
||||
create: [address0 as Address, address1 as Address],
|
||||
};
|
||||
const ad = await adsRepository.create(adToCreate);
|
||||
|
||||
const afterCount = await prismaService.ad.count();
|
||||
|
||||
expect(afterCount - beforeCount).toBe(1);
|
||||
expect(ad.uuid).toBe('137a26fa-4b38-48ba-aecf-1a75f6b20f3d');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,40 @@
|
|||
import { ConfigService } from '@nestjs/config';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { DefaultParamsProvider } from '../../../../adapters/secondaries/default-params.provider';
|
||||
import { DefaultParams } from '../../../../domain/types/default-params.type';
|
||||
|
||||
const mockConfigService = {
|
||||
get: jest.fn().mockImplementation(() => 'some_default_value'),
|
||||
};
|
||||
//TODO complete coverage
|
||||
describe('DefaultParamsProvider', () => {
|
||||
let defaultParamsProvider: DefaultParamsProvider;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
imports: [],
|
||||
providers: [
|
||||
DefaultParamsProvider,
|
||||
{
|
||||
provide: ConfigService,
|
||||
useValue: mockConfigService,
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
defaultParamsProvider = module.get<DefaultParamsProvider>(
|
||||
DefaultParamsProvider,
|
||||
);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(defaultParamsProvider).toBeDefined();
|
||||
});
|
||||
|
||||
it('should provide default params', async () => {
|
||||
const params: DefaultParams = defaultParamsProvider.getParams();
|
||||
expect(params.SUN_MARGIN).toBeNaN();
|
||||
expect(params.PASSENGER).toBe(false);
|
||||
expect(params.DRIVER).toBe(false);
|
||||
});
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
import { AmqpConnection } from '@golevelup/nestjs-rabbitmq';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { Messager } from '../../adapters/secondaries/messager';
|
||||
import { Messager } from '../../../../adapters/secondaries/messager';
|
||||
|
||||
const mockAmqpConnection = {
|
||||
publish: jest.fn().mockImplementation(),
|
|
@ -0,0 +1,256 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { CreateAdUseCase } from '../../../domain/usecases/create-ad.usecase';
|
||||
import { CreateAdRequest } from '../../../domain/dtos/create-ad.request';
|
||||
import { Messager } from '../../../adapters/secondaries/messager';
|
||||
import { AdsRepository } from '../../../adapters/secondaries/ads.repository';
|
||||
import { CreateAdCommand } from '../../../commands/create-ad.command';
|
||||
import { AutomapperModule } from '@automapper/nestjs';
|
||||
import { classes } from '@automapper/classes';
|
||||
import { Frequency } from '../../../domain/types/frequency.enum';
|
||||
import { Ad } from '../../../domain/entities/ad';
|
||||
import { AdProfile } from '../../../mappers/ad.profile';
|
||||
import { AddressRequestDTO } from '../../../domain/dtos/create.address.request';
|
||||
import { AdCreation } from '../../../domain/dtos/ad.creation';
|
||||
import { Address } from 'src/modules/ad/domain/entities/address';
|
||||
|
||||
const mockAddress1: AddressRequestDTO = {
|
||||
position: 0,
|
||||
lon: 48.68944505415954,
|
||||
lat: 6.176510296462267,
|
||||
houseNumber: '5',
|
||||
street: 'Avenue Foch',
|
||||
locality: 'Nancy',
|
||||
postalCode: '54000',
|
||||
country: 'France',
|
||||
};
|
||||
const mockAddress2: AddressRequestDTO = {
|
||||
position: 1,
|
||||
lon: 48.8566,
|
||||
lat: 2.3522,
|
||||
locality: 'Paris',
|
||||
postalCode: '75000',
|
||||
country: 'France',
|
||||
};
|
||||
const mockAddressWithoutPos1: AddressRequestDTO = {
|
||||
lon: 43.2965,
|
||||
lat: 5.3698,
|
||||
locality: 'Marseille',
|
||||
postalCode: '13000',
|
||||
country: 'France',
|
||||
};
|
||||
const mockAddressWithoutPos2: AddressRequestDTO = {
|
||||
lon: 43.7102,
|
||||
lat: 7.262,
|
||||
locality: 'Nice',
|
||||
postalCode: '06000',
|
||||
country: 'France',
|
||||
};
|
||||
const minimalRecurrentAdREquest: CreateAdRequest = {
|
||||
userUuid: '224e0000-0000-4000-a000-000000000000',
|
||||
frequency: Frequency.RECURRENT,
|
||||
fromDate: new Date('01-05-2023'),
|
||||
toDate: new Date('01-05-2024'),
|
||||
schedule: {
|
||||
mon: '08:00',
|
||||
},
|
||||
marginDurations: {},
|
||||
addresses: [mockAddress1, mockAddress2],
|
||||
};
|
||||
const newAdRequest: CreateAdRequest = {
|
||||
userUuid: '113e0000-0000-4000-a000-000000000000',
|
||||
driver: true,
|
||||
passenger: false,
|
||||
frequency: Frequency.RECURRENT,
|
||||
fromDate: new Date('01-05-2023'),
|
||||
toDate: new Date('20-08-2023'),
|
||||
schedule: {
|
||||
tue: '08:00',
|
||||
wed: '08:30',
|
||||
},
|
||||
marginDurations: {
|
||||
mon: undefined,
|
||||
tue: undefined,
|
||||
wed: undefined,
|
||||
thu: undefined,
|
||||
fri: undefined,
|
||||
sat: undefined,
|
||||
sun: undefined,
|
||||
},
|
||||
seatsDriver: 2,
|
||||
addresses: [mockAddress1, mockAddress2],
|
||||
};
|
||||
|
||||
const mockMessager = {
|
||||
publish: jest.fn().mockImplementation(),
|
||||
};
|
||||
const mockDefaultParamsProvider = {
|
||||
getParams: () => {
|
||||
return {
|
||||
MON_MARGIN: 900,
|
||||
TUE_MARGIN: 900,
|
||||
WED_MARGIN: 900,
|
||||
THU_MARGIN: 900,
|
||||
FRI_MARGIN: 900,
|
||||
SAT_MARGIN: 900,
|
||||
SUN_MARGIN: 900,
|
||||
DRIVER: false,
|
||||
SEATS_PROVIDED: 0,
|
||||
PASSENGER: true,
|
||||
SEATS_REQUESTED: 1,
|
||||
STRICT: false,
|
||||
};
|
||||
},
|
||||
};
|
||||
const mockAdRepository = {
|
||||
create: jest
|
||||
.fn()
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.mockImplementationOnce((command?: CreateAdCommand) => {
|
||||
return Promise.resolve({
|
||||
...newAdRequest,
|
||||
uuid: 'ad000000-0000-4000-a000-000000000000',
|
||||
createdAt: new Date('01-05-2023'),
|
||||
});
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
throw new Error('Already exists');
|
||||
})
|
||||
.mockImplementation(),
|
||||
};
|
||||
describe('CreateAdUseCase', () => {
|
||||
let createAdUseCase: CreateAdUseCase;
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
imports: [AutomapperModule.forRoot({ strategyInitializer: classes() })],
|
||||
providers: [
|
||||
{
|
||||
provide: AdsRepository,
|
||||
useValue: mockAdRepository,
|
||||
},
|
||||
{
|
||||
provide: Messager,
|
||||
useValue: mockMessager,
|
||||
},
|
||||
CreateAdUseCase,
|
||||
AdProfile,
|
||||
{
|
||||
provide: 'ParamsProvider',
|
||||
useValue: mockDefaultParamsProvider,
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
createAdUseCase = module.get<CreateAdUseCase>(CreateAdUseCase);
|
||||
});
|
||||
it('should be defined', () => {
|
||||
expect(createAdUseCase).toBeDefined();
|
||||
});
|
||||
describe('execution', () => {
|
||||
const newAdCommand = new CreateAdCommand(newAdRequest);
|
||||
it('should create an new ad', async () => {
|
||||
const newAd: Ad = await createAdUseCase.execute(newAdCommand);
|
||||
expect(newAd.userUuid).toBe(newAdRequest.userUuid);
|
||||
expect(newAd.uuid).toBeDefined();
|
||||
});
|
||||
it('should throw an error if the ad already exists', async () => {
|
||||
await expect(
|
||||
createAdUseCase.execute(newAdCommand),
|
||||
).rejects.toBeInstanceOf(Error);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Ad parameter default setting ', () => {
|
||||
beforeEach(() => {
|
||||
mockAdRepository.create.mockClear();
|
||||
});
|
||||
|
||||
it('should define mimimal ad as 1 passager add', async () => {
|
||||
const newAdCommand = new CreateAdCommand(minimalRecurrentAdREquest);
|
||||
await createAdUseCase.execute(newAdCommand);
|
||||
const expectedAdCreation = {
|
||||
userUuid: minimalRecurrentAdREquest.userUuid,
|
||||
frequency: minimalRecurrentAdREquest.frequency,
|
||||
fromDate: minimalRecurrentAdREquest.fromDate,
|
||||
toDate: minimalRecurrentAdREquest.toDate,
|
||||
monTime: minimalRecurrentAdREquest.schedule.mon,
|
||||
tueTime: undefined,
|
||||
wedTime: undefined,
|
||||
thuTime: undefined,
|
||||
friTime: undefined,
|
||||
satTime: undefined,
|
||||
sunTime: undefined,
|
||||
monMargin: mockDefaultParamsProvider.getParams().MON_MARGIN,
|
||||
tueMargin: mockDefaultParamsProvider.getParams().TUE_MARGIN,
|
||||
wedMargin: mockDefaultParamsProvider.getParams().WED_MARGIN,
|
||||
thuMargin: mockDefaultParamsProvider.getParams().THU_MARGIN,
|
||||
friMargin: mockDefaultParamsProvider.getParams().FRI_MARGIN,
|
||||
satMargin: mockDefaultParamsProvider.getParams().SAT_MARGIN,
|
||||
sunMargin: mockDefaultParamsProvider.getParams().SUN_MARGIN,
|
||||
driver: mockDefaultParamsProvider.getParams().DRIVER,
|
||||
seatsDriver: mockDefaultParamsProvider.getParams().SEATS_PROVIDED,
|
||||
passenger: mockDefaultParamsProvider.getParams().PASSENGER,
|
||||
seatsPassenger: mockDefaultParamsProvider.getParams().SEATS_REQUESTED,
|
||||
strict: mockDefaultParamsProvider.getParams().STRICT,
|
||||
addresses: {
|
||||
create: minimalRecurrentAdREquest.addresses as Address[],
|
||||
},
|
||||
createdAt: undefined,
|
||||
} as AdCreation;
|
||||
|
||||
expect(mockAdRepository.create).toBeCalledWith(expectedAdCreation);
|
||||
});
|
||||
it('should create an passengerAd with addresses without position ', async () => {
|
||||
const newPunctualPassengerAdRequest: CreateAdRequest = {
|
||||
userUuid: '113e0000-0000-4000-a000-000000000000',
|
||||
passenger: true,
|
||||
frequency: Frequency.PUNCTUAL,
|
||||
departure: new Date('05-22-2023 09:36'),
|
||||
|
||||
marginDurations: {
|
||||
mon: undefined,
|
||||
tue: undefined,
|
||||
wed: undefined,
|
||||
thu: undefined,
|
||||
fri: undefined,
|
||||
sat: undefined,
|
||||
sun: undefined,
|
||||
},
|
||||
seatsPassenger: 1,
|
||||
addresses: [mockAddressWithoutPos1, mockAddressWithoutPos2],
|
||||
schedule: {},
|
||||
};
|
||||
const newAdCommand = new CreateAdCommand(newPunctualPassengerAdRequest);
|
||||
await createAdUseCase.execute(newAdCommand);
|
||||
const expectedAdCreation = {
|
||||
userUuid: newPunctualPassengerAdRequest.userUuid,
|
||||
frequency: newPunctualPassengerAdRequest.frequency,
|
||||
fromDate: newPunctualPassengerAdRequest.departure,
|
||||
toDate: newPunctualPassengerAdRequest.departure,
|
||||
monTime: '09:36',
|
||||
tueTime: undefined,
|
||||
wedTime: undefined,
|
||||
thuTime: undefined,
|
||||
friTime: undefined,
|
||||
satTime: undefined,
|
||||
sunTime: undefined,
|
||||
monMargin: mockDefaultParamsProvider.getParams().MON_MARGIN,
|
||||
tueMargin: mockDefaultParamsProvider.getParams().TUE_MARGIN,
|
||||
wedMargin: mockDefaultParamsProvider.getParams().WED_MARGIN,
|
||||
thuMargin: mockDefaultParamsProvider.getParams().THU_MARGIN,
|
||||
friMargin: mockDefaultParamsProvider.getParams().FRI_MARGIN,
|
||||
satMargin: mockDefaultParamsProvider.getParams().SAT_MARGIN,
|
||||
sunMargin: mockDefaultParamsProvider.getParams().SUN_MARGIN,
|
||||
driver: false,
|
||||
seatsDriver: 0,
|
||||
passenger: newPunctualPassengerAdRequest.passenger,
|
||||
seatsPassenger: newPunctualPassengerAdRequest.seatsPassenger,
|
||||
strict: mockDefaultParamsProvider.getParams().STRICT,
|
||||
addresses: {
|
||||
create: newPunctualPassengerAdRequest.addresses as Address[],
|
||||
},
|
||||
createdAt: undefined,
|
||||
} as AdCreation;
|
||||
expect(mockAdRepository.create).toBeCalledWith(expectedAdCreation);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,10 +1,10 @@
|
|||
import { NotFoundException } from '@nestjs/common';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { Messager } from '../../adapters/secondaries/messager';
|
||||
import { FindAdByUuidQuery } from '../../queries/find-ad-by-uuid.query';
|
||||
import { AdsRepository } from '../../adapters/secondaries/ads.repository';
|
||||
import { FindAdByUuidUseCase } from '../../domain/usecases/find-ad-by-uuid.usecase';
|
||||
import { FindAdByUuidRequest } from '../../domain/dtos/find-ad-by-uuid.request';
|
||||
import { Messager } from '../../../adapters/secondaries/messager';
|
||||
import { FindAdByUuidQuery } from '../../../queries/find-ad-by-uuid.query';
|
||||
import { AdsRepository } from '../../../adapters/secondaries/ads.repository';
|
||||
import { FindAdByUuidUseCase } from '../../../domain/usecases/find-ad-by-uuid.usecase';
|
||||
import { FindAdByUuidRequest } from '../../../domain/dtos/find-ad-by-uuid.request';
|
||||
|
||||
const mockAd = {
|
||||
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
|
||||
|
@ -18,7 +18,7 @@ const mockAdRepository = {
|
|||
return Promise.resolve(mockAd);
|
||||
})
|
||||
.mockImplementation(() => {
|
||||
return Promise.resolve(undefined);
|
||||
return Promise.resolve(null);
|
||||
}),
|
||||
};
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { mappingKeyToFrequency } from '../../../domain/dtos/validators/frequency.mapping';
|
||||
import { Frequency } from '../../../domain/types/frequency.enum';
|
||||
|
||||
describe('frequency mapping function ', () => {
|
||||
it('should return punctual', () => {
|
||||
expect(mappingKeyToFrequency(1)).toBe(Frequency.PUNCTUAL);
|
||||
});
|
||||
it('should return recurent', () => {
|
||||
expect(mappingKeyToFrequency(2)).toBe(Frequency.RECURRENT);
|
||||
});
|
||||
it('should return undefined', () => {
|
||||
expect(mappingKeyToFrequency(0)).toBeUndefined();
|
||||
expect(mappingKeyToFrequency(3)).toBeUndefined();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,100 @@
|
|||
import { hasProperDriverSeats } from '../../../domain/dtos/validators/has-driver-seats';
|
||||
|
||||
describe('driver and/or driver seats validator', () => {
|
||||
it('should validate if driver and drivers seats is not provided ', () => {
|
||||
expect(
|
||||
hasProperDriverSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { driver: undefined },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
hasProperDriverSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { driver: false },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
hasProperDriverSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { driver: null },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
it('should not validate if driver is set to true but not the related seats is not provided or 0', () => {
|
||||
expect(
|
||||
hasProperDriverSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { driver: true },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasProperDriverSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { driver: true, seatsDriver: 0 },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasProperDriverSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { driver: true, seatsDriver: undefined },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasProperDriverSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { driver: true, seatsDriver: null },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
it('should not validate if driver seats are provided but driver is not set or set to false ', () => {
|
||||
expect(
|
||||
hasProperDriverSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { driver: false, seatsDriver: 1 },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasProperDriverSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { driver: undefined, seatsDriver: 1 },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasProperDriverSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { driver: null, seatsDriver: 1 },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,100 @@
|
|||
import { hasProperPassengerSeats } from '../../../domain/dtos/validators/has-passenger-seats';
|
||||
|
||||
describe('driver and/or passenger seats validator', () => {
|
||||
it('should validate if passenger and passengers seats is not provided ', () => {
|
||||
expect(
|
||||
hasProperPassengerSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { passenger: undefined },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
hasProperPassengerSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { passenger: false },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
hasProperPassengerSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { passenger: null },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
it('should not validate if passenger is set to true but not the related seats is not provided or 0', () => {
|
||||
expect(
|
||||
hasProperPassengerSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { passenger: true },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasProperPassengerSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { passenger: true, seatsPassenger: 0 },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasProperPassengerSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { passenger: true, seatsPassenger: undefined },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasProperPassengerSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { passenger: true, seatsPassenger: null },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
it('should not validate if passenger seats are provided but passenger is not set or set to false ', () => {
|
||||
expect(
|
||||
hasProperPassengerSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { passenger: false, seatsPassenger: 1 },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasProperPassengerSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { passenger: undefined, seatsPassenger: 1 },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasProperPassengerSeats({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: { passenger: null, seatsPassenger: 1 },
|
||||
property: '',
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,70 @@
|
|||
import { AddressRequestDTO } from '../../../domain/dtos/create.address.request';
|
||||
import { hasProperPositionIndexes } from '../../../domain/dtos/validators/address-position';
|
||||
describe('addresses position validators', () => {
|
||||
const mockAddress1: AddressRequestDTO = {
|
||||
lon: 48.68944505415954,
|
||||
lat: 6.176510296462267,
|
||||
houseNumber: '5',
|
||||
street: 'Avenue Foch',
|
||||
locality: 'Nancy',
|
||||
postalCode: '54000',
|
||||
country: 'France',
|
||||
};
|
||||
const mockAddress2: AddressRequestDTO = {
|
||||
lon: 48.8566,
|
||||
lat: 2.3522,
|
||||
locality: 'Paris',
|
||||
postalCode: '75000',
|
||||
country: 'France',
|
||||
};
|
||||
|
||||
const mockAddress3: AddressRequestDTO = {
|
||||
lon: 49.2628,
|
||||
lat: 4.0347,
|
||||
locality: 'Reims',
|
||||
postalCode: '51454',
|
||||
country: 'France',
|
||||
};
|
||||
it('should validate if none of position is definded ', () => {
|
||||
expect(
|
||||
hasProperPositionIndexes([mockAddress1, mockAddress2, mockAddress3]),
|
||||
).toBeTruthy();
|
||||
});
|
||||
it('should throw an error if position are partialy defined ', () => {
|
||||
mockAddress1.position = 0;
|
||||
expect(
|
||||
hasProperPositionIndexes([mockAddress1, mockAddress2, mockAddress3]),
|
||||
).toBeFalsy();
|
||||
});
|
||||
it('should throw an error if position are partialy defined ', () => {
|
||||
mockAddress1.position = 0;
|
||||
mockAddress2.position = null;
|
||||
mockAddress3.position = undefined;
|
||||
expect(
|
||||
hasProperPositionIndexes([mockAddress1, mockAddress2, mockAddress3]),
|
||||
).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should throw an error if positions are not incremented ', () => {
|
||||
mockAddress1.position = 0;
|
||||
mockAddress2.position = 1;
|
||||
mockAddress3.position = 1;
|
||||
expect(
|
||||
hasProperPositionIndexes([mockAddress1, mockAddress2, mockAddress3]),
|
||||
).toBeFalsy();
|
||||
});
|
||||
it('should validate if all positions are defined and incremented', () => {
|
||||
mockAddress1.position = 0;
|
||||
mockAddress2.position = 1;
|
||||
mockAddress3.position = 2;
|
||||
expect(
|
||||
hasProperPositionIndexes([mockAddress1, mockAddress2, mockAddress3]),
|
||||
).toBeTruthy();
|
||||
mockAddress1.position = 10;
|
||||
mockAddress2.position = 0;
|
||||
mockAddress3.position = 3;
|
||||
expect(
|
||||
hasProperPositionIndexes([mockAddress1, mockAddress2, mockAddress3]),
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,113 @@
|
|||
import { isPunctualOrRecurrent } from '../../../domain/dtos/validators/is-punctual-or-recurrent';
|
||||
import { Frequency } from '../../../domain/types/frequency.enum';
|
||||
|
||||
describe('punctual or reccurent validators', () => {
|
||||
describe('punctual case ', () => {
|
||||
describe('valid cases', () => {
|
||||
it('should validate with valid departure and empty schedule ', () => {
|
||||
expect(
|
||||
isPunctualOrRecurrent({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: {
|
||||
frequency: Frequency.PUNCTUAL,
|
||||
departure: new Date('01-02-2023'),
|
||||
schedule: {},
|
||||
},
|
||||
property: '',
|
||||
}),
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
describe('invalid cases ', () => {
|
||||
it('should not validate with invalid departure and empty schedule and margin', () => {
|
||||
expect(
|
||||
isPunctualOrRecurrent({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: {
|
||||
frequency: Frequency.PUNCTUAL,
|
||||
fromDate: new Date('20-10-2023'),
|
||||
toDate: new Date('30-10-2023'),
|
||||
},
|
||||
property: '',
|
||||
}),
|
||||
).toBeFalsy();
|
||||
});
|
||||
it('should not validate with no empty schedule', () => {
|
||||
expect(
|
||||
isPunctualOrRecurrent({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: {
|
||||
frequency: Frequency.PUNCTUAL,
|
||||
departure: new Date('01-02-2023'),
|
||||
schedule: {
|
||||
mon: '08:30',
|
||||
},
|
||||
},
|
||||
property: '',
|
||||
}),
|
||||
).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('reccurent case ', () => {
|
||||
describe('valid cases', () => {
|
||||
it('should validate with valid from date, to date and non empty schedule ', () => {
|
||||
expect(
|
||||
isPunctualOrRecurrent({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: {
|
||||
frequency: Frequency.RECURRENT,
|
||||
fromDate: new Date('01-15-2023'),
|
||||
toDate: new Date('06-30-2023'),
|
||||
schedule: {
|
||||
mon: '08:30',
|
||||
},
|
||||
},
|
||||
property: '',
|
||||
}),
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
describe('invalid cases ', () => {
|
||||
it('should not validate with empty schedule ', () => {
|
||||
expect(
|
||||
isPunctualOrRecurrent({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: {
|
||||
frequency: Frequency.RECURRENT,
|
||||
fromDate: new Date('01-15-2023'),
|
||||
toDate: new Date('06-30-2023'),
|
||||
schedule: {},
|
||||
},
|
||||
property: '',
|
||||
}),
|
||||
).toBeFalsy();
|
||||
});
|
||||
it('should not validate with invalid from date to date and empty schedule and margin', () => {
|
||||
expect(
|
||||
isPunctualOrRecurrent({
|
||||
value: undefined,
|
||||
constraints: [],
|
||||
targetName: '',
|
||||
object: {
|
||||
frequency: Frequency.RECURRENT,
|
||||
departure: new Date('20-10-2023'),
|
||||
toDate: new Date('30-10-2023'),
|
||||
},
|
||||
property: '',
|
||||
}),
|
||||
).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,92 @@
|
|||
import { CreateAdRequest } from '../../../domain/dtos/create-ad.request';
|
||||
import { ScheduleDTO } from '../../../domain/dtos/create.schedule.dto';
|
||||
import { RecurrentNormaliser } from '../../../domain/entities/recurrent-normaliser';
|
||||
import { Frequency } from '../../../domain/types/frequency.enum';
|
||||
describe('recurrent normalizer transformer for punctual ad ', () => {
|
||||
const recurrentNormaliser = new RecurrentNormaliser();
|
||||
it('should transform punctual ad into recurrent ad ', () => {
|
||||
const punctualAd: CreateAdRequest = {
|
||||
userUuid: '',
|
||||
frequency: Frequency.PUNCTUAL,
|
||||
departure: new Date('05-03-2023 12:39:39 '),
|
||||
schedule: {} as ScheduleDTO,
|
||||
addresses: [],
|
||||
};
|
||||
expect(recurrentNormaliser.fromDateResolver(punctualAd)).toBe(
|
||||
punctualAd.departure,
|
||||
);
|
||||
expect(recurrentNormaliser.toDateResolver(punctualAd)).toBe(
|
||||
punctualAd.departure,
|
||||
);
|
||||
expect(recurrentNormaliser.scheduleMonResolver(punctualAd)).toBeUndefined();
|
||||
expect(recurrentNormaliser.scheduleTueResolver(punctualAd)).toBeUndefined();
|
||||
expect(recurrentNormaliser.scheduleWedResolver(punctualAd)).toBe('12:39');
|
||||
expect(recurrentNormaliser.scheduleThuResolver(punctualAd)).toBeUndefined();
|
||||
expect(recurrentNormaliser.scheduleFriResolver(punctualAd)).toBeUndefined();
|
||||
expect(recurrentNormaliser.scheduleSatResolver(punctualAd)).toBeUndefined();
|
||||
expect(recurrentNormaliser.scheduleSunResolver(punctualAd)).toBeUndefined();
|
||||
});
|
||||
it('should leave recurrent ad as is', () => {
|
||||
const recurrentAd: CreateAdRequest = {
|
||||
userUuid: '',
|
||||
frequency: Frequency.RECURRENT,
|
||||
schedule: {
|
||||
mon: '08:30',
|
||||
tue: '08:30',
|
||||
wed: '09:00',
|
||||
fri: '09:00',
|
||||
},
|
||||
addresses: [],
|
||||
};
|
||||
expect(recurrentNormaliser.fromDateResolver(recurrentAd)).toBe(
|
||||
recurrentAd.departure,
|
||||
);
|
||||
expect(recurrentNormaliser.toDateResolver(recurrentAd)).toBe(
|
||||
recurrentAd.departure,
|
||||
);
|
||||
expect(recurrentNormaliser.scheduleMonResolver(recurrentAd)).toBe(
|
||||
recurrentAd.schedule.mon,
|
||||
);
|
||||
expect(recurrentNormaliser.scheduleTueResolver(recurrentAd)).toBe(
|
||||
recurrentAd.schedule.tue,
|
||||
);
|
||||
expect(recurrentNormaliser.scheduleWedResolver(recurrentAd)).toBe(
|
||||
recurrentAd.schedule.wed,
|
||||
);
|
||||
expect(recurrentNormaliser.scheduleThuResolver(recurrentAd)).toBe(
|
||||
recurrentAd.schedule.thu,
|
||||
);
|
||||
expect(recurrentNormaliser.scheduleFriResolver(recurrentAd)).toBe(
|
||||
recurrentAd.schedule.fri,
|
||||
);
|
||||
expect(recurrentNormaliser.scheduleSatResolver(recurrentAd)).toBe(
|
||||
recurrentAd.schedule.sat,
|
||||
);
|
||||
expect(recurrentNormaliser.scheduleSunResolver(recurrentAd)).toBe(
|
||||
recurrentAd.schedule.sun,
|
||||
);
|
||||
});
|
||||
it('should pass for each day of the week of a deprarture ', () => {
|
||||
const punctualAd: CreateAdRequest = {
|
||||
userUuid: '',
|
||||
frequency: Frequency.PUNCTUAL,
|
||||
departure: undefined,
|
||||
schedule: {} as ScheduleDTO,
|
||||
addresses: [],
|
||||
};
|
||||
punctualAd.departure = new Date('05-01-2023 ');
|
||||
expect(recurrentNormaliser.scheduleMonResolver(punctualAd)).toBe('00:00');
|
||||
punctualAd.departure = new Date('05-02-2023 06:32:45');
|
||||
expect(recurrentNormaliser.scheduleTueResolver(punctualAd)).toBe('06:32');
|
||||
punctualAd.departure = new Date('05-03-2023 10:21');
|
||||
expect(recurrentNormaliser.scheduleWedResolver(punctualAd)).toBe('10:21');
|
||||
punctualAd.departure = new Date('05-04-2023 11:06:00');
|
||||
expect(recurrentNormaliser.scheduleThuResolver(punctualAd)).toBe('11:06');
|
||||
punctualAd.departure = new Date('05-05-2023 05:20');
|
||||
expect(recurrentNormaliser.scheduleFriResolver(punctualAd)).toBe('05:20');
|
||||
punctualAd.departure = new Date('05-06-2023');
|
||||
expect(recurrentNormaliser.scheduleSatResolver(punctualAd)).toBe('00:00');
|
||||
punctualAd.departure = new Date('05-07-2023');
|
||||
expect(recurrentNormaliser.scheduleSunResolver(punctualAd)).toBe('00:00');
|
||||
});
|
||||
});
|
|
@ -85,7 +85,6 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
|
|||
data: entity,
|
||||
include: include,
|
||||
});
|
||||
|
||||
return res;
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
|
|
Loading…
Reference in New Issue