import { ConflictException, HttpException, Injectable, NotFoundException, UnprocessableEntityException } from '@nestjs/common' import { CreateTrainDto } from './dto/create-train.dto' import { UpdateTrainDto } from './dto/update-train.dto' import { PrismaService } from 'src/prisma/prisma.service' import { MoneyUpdateType, Player, TrainTrip } from '@prisma/client' import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto' import { paginate } from 'src/common/utils/pagination.utils' import { ImportTrainDto } from './dto/import-train.dto' import { InterrailJourney, InterrailLegInfo, InterrailTravelInfo } from './dto/interrail-api.dto' import { distanceCoordinates } from 'src/common/utils/calculus.utils' import { PlayerFilterDto } from 'src/common/dto/player_filter.dto' @Injectable() export class TrainsService { constructor(private prisma: PrismaService) { } async create(createTrainDto: CreateTrainDto): Promise { return await this.prisma.trainTrip.create({ data: createTrainDto }) } async findAll(queryPagination: QueryPaginationDto, playerFilter: PlayerFilterDto): Promise<[TrainTrip[], number]> { return [ await this.prisma.trainTrip.findMany({ where: playerFilter, ...paginate(queryPagination), }), await this.prisma.trainTrip.count({ where: playerFilter, }), ] } async findOne(id: string): Promise { return await this.prisma.trainTrip.findUnique({ where: { id }, }) } async update(id: string, updateTrainDto: UpdateTrainDto): Promise { if (!this.findOne(id)) throw new NotFoundException(`Le train à modifier n'existe pas avec l'identifiant ${id}`) return await this.prisma.trainTrip.update({ where: { id }, data: updateTrainDto, }) } async remove(id: string): Promise { if (!this.findOne(id)) throw new NotFoundException(`Le train à supprimer n'existe pas avec l'identifiant ${id}`) return await this.prisma.trainTrip.delete({ where: { id }, }) } async import(player: Player, { id: trainId }: ImportTrainDto): Promise { if (this.findOne(trainId)) throw new ConflictException(`Le train avec l'identifiant ${trainId} est déjà importé`) const interrailResult: InterrailJourney = await fetch(`https://3uiwjsimnh.execute-api.eu-central-1.amazonaws.com/Prod/journey-import?id=${trainId}`) .then(data => data.json()) if (interrailResult.data.travels.length !== 1) throw new UnprocessableEntityException(`Ce voyage contient ${interrailResult.data.travels.length} trajets. Merci d'ajouter les trajets un à un.`) const travel = interrailResult.data.travels[0] if (travel.legs.length !== 1) throw new UnprocessableEntityException(`Ce trajet contient ${travel.legs.length} trains. Merci d'ajouter les trajets un à un.`) const leg = travel.legs[0] const travelInfoJson: InterrailTravelInfo = JSON.parse(travel.infoJson) const departure = new Date(`${travelInfoJson.date.year}-${travelInfoJson.date.month.toString().padStart(2, "0")}-${travelInfoJson.date.day.toString().padStart(2, "0")}` + `T${travelInfoJson.departureTime.hours.toString().padStart(2, "0")}:${travelInfoJson.departureTime.minutes.toString().padStart(2, "0")}:00+0100`) departure.setDate(departure.getDate() + travelInfoJson.departureTime.offset) const arrival = new Date(`${travelInfoJson.date.year}-${travelInfoJson.date.month.toString().padStart(2, "0")}-${travelInfoJson.date.day.toString().padStart(2, "0")}` + `T${travelInfoJson.arrivalTime.hours.toString().padStart(2, "0")}:${travelInfoJson.arrivalTime.minutes.toString().padStart(2, "0")}:00+0100`) arrival.setDate(arrival.getDate() + travelInfoJson.arrivalTime.offset) const legInfoJson: InterrailLegInfo = JSON.parse(leg.infoJson) const distance = legInfoJson.trainStopStations .map(trainStopStation => trainStopStation.coordinates) .reduce((distance, coordinates, index) => { if (index === 0) return distance const oldCoordinates = legInfoJson.trainStopStations.at(index - 1).coordinates return distance + distanceCoordinates({ from: oldCoordinates, to: coordinates }) }, 0) const cost = 10 * 10 * Math.ceil(distance / 1000) const train = await this.prisma.trainTrip.create({ data: { id: trainId, playerId: player.id, distance: distance, from: travel.from, to: travel.to, departureTime: departure, arrivalTime: arrival, infoJson: leg.infoJson, }, }) // Ajout du trajet en points await this.prisma.moneyUpdate.create({ data: { playerId: player.id, amount: -cost, reason: MoneyUpdateType.BUY_TRAIN, tripId: train.id, } }) return train } }