Commit 09e16b81 authored by Heber Cordova's avatar Heber Cordova

feat: added business rules

parent 84afc748
...@@ -10,6 +10,24 @@ services: ...@@ -10,6 +10,24 @@ services:
- ./flight-agency-app/nginx.conf:/etc/nginx/conf.d/default.conf - ./flight-agency-app/nginx.conf:/etc/nginx/conf.d/default.conf
networks: networks:
- my-flight-app-network - my-flight-app-network
database:
image: mysql:latest
container_name: flight-booking-db
environment:
- MYSQL_ROOT_PASSWORD=admin
ports:
- "3307:3306"
networks:
- my-flight-app-network
api:
build: ./flight-agency-api
container_name: flight-booking-api
ports:
- "8082:8080"
depends_on:
- database
networks:
- my-flight-app-network
networks: networks:
my-flight-app-network: my-flight-app-network:
...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.agent.controllers; ...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.agent.controllers;
import java.util.List; import java.util.List;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
...@@ -18,6 +19,7 @@ import com.hcordova.flightagencyapi.agent.dto.AgentEditDTO; ...@@ -18,6 +19,7 @@ import com.hcordova.flightagencyapi.agent.dto.AgentEditDTO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@CrossOrigin(origins = "http://localhost:4200")
@RestController @RestController
@RequestMapping("/api/v1/agents") @RequestMapping("/api/v1/agents")
@RequiredArgsConstructor @RequiredArgsConstructor
......
package com.hcordova.flightagencyapi.agent.domain.repositories; package com.hcordova.flightagencyapi.agent.domain.repositories;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
...@@ -10,4 +11,6 @@ import com.hcordova.flightagencyapi.agent.domain.models.Agent; ...@@ -10,4 +11,6 @@ import com.hcordova.flightagencyapi.agent.domain.models.Agent;
@Repository @Repository
public interface AgentRepository extends JpaRepository<Agent, Long>{ public interface AgentRepository extends JpaRepository<Agent, Long>{
Optional<Agent> findByUserId(Long userId); Optional<Agent> findByUserId(Long userId);
Optional<Agent> findByIdAndDeletedAtIsNull(Long id);
List<Agent> findAllByDeletedAtIsNull();
} }
...@@ -21,12 +21,12 @@ public class AgentServiceImpl implements AgentService { ...@@ -21,12 +21,12 @@ public class AgentServiceImpl implements AgentService {
@Override @Override
public List<Agent> getAll() { public List<Agent> getAll() {
return agentRepository.findAll(); return agentRepository.findAllByDeletedAtIsNull();
} }
@Override @Override
public Agent getById(Long id) { public Agent getById(Long id) {
return agentRepository.findById(id) return agentRepository.findByIdAndDeletedAtIsNull(id)
.orElseThrow(() -> new NotFoundException("Agent not found")); .orElseThrow(() -> new NotFoundException("Agent not found"));
} }
......
...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.aircraft.controllers; ...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.aircraft.controllers;
import java.util.List; import java.util.List;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
...@@ -12,6 +13,7 @@ import com.hcordova.flightagencyapi.aircraft.dto.AircraftDTO; ...@@ -12,6 +13,7 @@ import com.hcordova.flightagencyapi.aircraft.dto.AircraftDTO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping("/api/v1/aircrafts") @RequestMapping("/api/v1/aircrafts")
@RequiredArgsConstructor @RequiredArgsConstructor
......
...@@ -6,4 +6,5 @@ import com.hcordova.flightagencyapi.aircraft.domain.models.Aircraft; ...@@ -6,4 +6,5 @@ import com.hcordova.flightagencyapi.aircraft.domain.models.Aircraft;
public interface AircraftService { public interface AircraftService {
List<Aircraft> getAll(); List<Aircraft> getAll();
Aircraft getById(Long id);
} }
...@@ -20,4 +20,10 @@ public class AircraftServiceImpl implements AircraftService { ...@@ -20,4 +20,10 @@ public class AircraftServiceImpl implements AircraftService {
public List<Aircraft> getAll() { public List<Aircraft> getAll() {
return aircraftRepository.findAll(); return aircraftRepository.findAll();
} }
@Override
public Aircraft getById(Long id) {
return aircraftRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Aircraft not found"));
}
} }
...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.airline.controllers; ...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.airline.controllers;
import java.util.List; import java.util.List;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
...@@ -12,6 +13,7 @@ import com.hcordova.flightagencyapi.airline.dto.AirlineDTO; ...@@ -12,6 +13,7 @@ import com.hcordova.flightagencyapi.airline.dto.AirlineDTO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping("/api/v1/airlines") @RequestMapping("/api/v1/airlines")
@RequiredArgsConstructor @RequiredArgsConstructor
......
...@@ -8,6 +8,7 @@ import jakarta.persistence.Id; ...@@ -8,6 +8,7 @@ import jakarta.persistence.Id;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@Entity @Entity
...@@ -15,6 +16,7 @@ import lombok.Setter; ...@@ -15,6 +16,7 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor
public class Airline { public class Airline {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
......
...@@ -6,4 +6,5 @@ import com.hcordova.flightagencyapi.airline.domain.models.Airline; ...@@ -6,4 +6,5 @@ import com.hcordova.flightagencyapi.airline.domain.models.Airline;
public interface AirlineService { public interface AirlineService {
List<Airline> getAll(); List<Airline> getAll();
Airline getById(Long id);
} }
...@@ -7,6 +7,7 @@ import org.springframework.stereotype.Service; ...@@ -7,6 +7,7 @@ import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.airline.domain.models.Airline; import com.hcordova.flightagencyapi.airline.domain.models.Airline;
import com.hcordova.flightagencyapi.airline.domain.repositories.AirlineRepository; import com.hcordova.flightagencyapi.airline.domain.repositories.AirlineRepository;
import com.hcordova.flightagencyapi.airline.domain.services.AirlineService; import com.hcordova.flightagencyapi.airline.domain.services.AirlineService;
import com.hcordova.flightagencyapi.shared.exceptions.NotFoundException;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
...@@ -19,4 +20,10 @@ public class AirlineServiceImpl implements AirlineService{ ...@@ -19,4 +20,10 @@ public class AirlineServiceImpl implements AirlineService{
public List<Airline> getAll() { public List<Airline> getAll() {
return this.airlineRepository.findAll(); return this.airlineRepository.findAll();
} }
@Override
public Airline getById(Long id) {
return this.airlineRepository.findById(id)
.orElseThrow(() -> new NotFoundException("Airline not found"));
}
} }
...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.airport.controllers; ...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.airport.controllers;
import java.util.List; import java.util.List;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
...@@ -12,6 +13,7 @@ import com.hcordova.flightagencyapi.airport.dto.AirportDTO; ...@@ -12,6 +13,7 @@ import com.hcordova.flightagencyapi.airport.dto.AirportDTO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping("/api/v1/airports") @RequestMapping("/api/v1/airports")
@RequiredArgsConstructor @RequiredArgsConstructor
......
...@@ -6,4 +6,5 @@ import com.hcordova.flightagencyapi.airport.domain.models.Airport; ...@@ -6,4 +6,5 @@ import com.hcordova.flightagencyapi.airport.domain.models.Airport;
public interface AirportService { public interface AirportService {
List<Airport> getAll(); List<Airport> getAll();
Airport getById(Long id);
} }
...@@ -7,6 +7,7 @@ import org.springframework.stereotype.Service; ...@@ -7,6 +7,7 @@ import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.airport.domain.models.Airport; import com.hcordova.flightagencyapi.airport.domain.models.Airport;
import com.hcordova.flightagencyapi.airport.domain.repositories.AirportRepository; import com.hcordova.flightagencyapi.airport.domain.repositories.AirportRepository;
import com.hcordova.flightagencyapi.airport.domain.services.AirportService; import com.hcordova.flightagencyapi.airport.domain.services.AirportService;
import com.hcordova.flightagencyapi.shared.exceptions.NotFoundException;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
...@@ -20,4 +21,10 @@ public class AirportServiceImpl implements AirportService { ...@@ -20,4 +21,10 @@ public class AirportServiceImpl implements AirportService {
public List<Airport> getAll() { public List<Airport> getAll() {
return airportRepository.findAll(); return airportRepository.findAll();
} }
@Override
public Airport getById(Long id) {
return airportRepository.findById(id)
.orElseThrow(() -> new NotFoundException(String.format("Airport with id %d not found", id)));
}
} }
package com.hcordova.flightagencyapi.flight.controllers;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.hcordova.flightagencyapi.flight.domain.services.FlightScheduleService;
import com.hcordova.flightagencyapi.flight.dto.FlightAllDTO;
import com.hcordova.flightagencyapi.flight.dto.FlightByDTO;
import com.hcordova.flightagencyapi.flight.dto.FlightSaveDTO;
import com.hcordova.flightagencyapi.flight.dto.FlightSearchDTO;
import lombok.RequiredArgsConstructor;
@CrossOrigin(origins = "*")
@RestController
@RequestMapping("/api/v1/flights")
@RequiredArgsConstructor
public class FlightScheduleController {
private final FlightScheduleService flightScheduleService;
@GetMapping()
public ResponseEntity<List<FlightAllDTO>> getAll() {
System.out.print("getAll");
return ResponseEntity.ok(flightScheduleService.getAll().stream().map(flight -> {
return new FlightAllDTO(flight);
}).toList());
}
@GetMapping("{id}")
public ResponseEntity<FlightByDTO> getById(@PathVariable Long id) {
return ResponseEntity.ok(new FlightByDTO(flightScheduleService.getById(id)));
}
@GetMapping("/search")
public ResponseEntity<List<FlightSearchDTO>> searchFlight(@RequestParam(name = "airportOriginId") Long origin,
@RequestParam(name = "airportDestinationId") Long destination, @RequestParam(name = "startDate") String startDate) {
return ResponseEntity.ok(flightScheduleService.searchByOriginDestinationAndDate(origin, destination, startDate).stream().map(flight -> new FlightSearchDTO(flight, startDate)).toList());
}
@PostMapping
public ResponseEntity<FlightAllDTO> save(@RequestBody FlightSaveDTO saveDTO) {
return ResponseEntity.ok(new FlightAllDTO(flightScheduleService.save(saveDTO)));
}
@DeleteMapping("{id}")
public ResponseEntity<FlightAllDTO> delete(@PathVariable Long id) {
return ResponseEntity.ok(new FlightAllDTO(flightScheduleService.delete(id)));
}
}
package com.hcordova.flightagencyapi.flight.domain.models;
import java.time.LocalDate;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "flight_costs")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class FlightCost {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)
@JoinColumn(name = "flight_schedule_id", nullable = false, updatable = false)
private FlightSchedule flightSchedule;
@Column(nullable = false)
@Temporal(TemporalType.DATE)
private LocalDate dateStart;
@Column(nullable = false)
@Temporal(TemporalType.DATE)
private LocalDate dateEnd;
@Column(nullable = false, columnDefinition = "DECIMAL(10,2)")
private Double cost;
}
package com.hcordova.flightagencyapi.flight.domain.models;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import com.hcordova.flightagencyapi.aircraft.domain.models.Aircraft;
import com.hcordova.flightagencyapi.airline.domain.models.Airline;
import com.hcordova.flightagencyapi.airport.domain.models.Airport;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "flight_schedules")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class FlightSchedule implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Airline airline;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Aircraft aircraft;
@ManyToOne(optional = false)
@JoinColumn(name = "airport_origin_id", referencedColumnName = "id")
@Access(AccessType.FIELD)
private Airport airportOrigin;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Airport airportDestination;
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime departureDateTime;
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime arrivalDateTime;
@OneToMany(mappedBy = "flightSchedule", cascade = CascadeType.ALL)
List<Leg> legs;
@OneToMany(mappedBy = "flightSchedule", cascade = CascadeType.ALL)
List<FlightCost> costs;
@Column(nullable = true)
@Temporal(TemporalType.DATE)
public LocalDate deletedAt;
}
package com.hcordova.flightagencyapi.flight.domain.models;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import com.hcordova.flightagencyapi.airport.domain.models.Airport;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "legs")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Leg {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)
@JoinColumn(name = "flight_schedule_id", nullable = false, updatable = false)
private FlightSchedule flightSchedule;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "airport_origin_id", nullable = false, updatable = false)
private Airport airportOrigin;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "airport_destination_id", nullable = false, updatable = false)
private Airport airportDestination;
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime actualDeparture;
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime actualArrival;
@ManyToMany(cascade = CascadeType.ALL)
private List<Reservation> reservations = new ArrayList<>();
}
package com.hcordova.flightagencyapi.flight.domain.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.flight.domain.models.FlightCost;
@Repository
public interface FlightCostRepository extends JpaRepository<FlightCost, Long> {
}
package com.hcordova.flightagencyapi.flight.domain.repositories;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.flight.domain.models.FlightSchedule;
@Repository
public interface FlightScheduleRepository extends JpaRepository<FlightSchedule, Long> {
List<FlightSchedule> findAllByDeletedAtIsNull();
List<FlightSchedule> findByAirportOrigin_Id(Long airportOriginId);
@Query("SELECT fs FROM FlightSchedule fs WHERE fs.airportOrigin.id = ?1 AND fs.airportDestination.id = ?2 AND (?3 between fs.departureDateTime AND fs.arrivalDateTime) AND fs.deletedAt IS NULL")
List<FlightSchedule> searchFlight(Long airportOriginId, Long airportDestinationId, LocalDateTime startDate);
Optional<FlightSchedule> findByIdAndDeletedAtIsNull(Long id);
}
package com.hcordova.flightagencyapi.flight.domain.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
@Repository
public interface LegRepository extends JpaRepository<Leg, Long> {
}
package com.hcordova.flightagencyapi.flight.domain.services;
import java.util.List;
import com.hcordova.flightagencyapi.flight.domain.models.FlightCost;
public interface FlightCostService {
List<FlightCost> getAll();
FlightCost getById(Long id);
}
package com.hcordova.flightagencyapi.flight.domain.services;
import java.util.List;
import com.hcordova.flightagencyapi.flight.domain.models.FlightSchedule;
import com.hcordova.flightagencyapi.flight.dto.FlightSaveDTO;
public interface FlightScheduleService {
List<FlightSchedule> getAll();
List<FlightSchedule> searchByOriginDestinationAndDate(Long airportOriginId, Long airportDestinationId, String startDate);
FlightSchedule getById(Long id);
FlightSchedule save(FlightSaveDTO saveDTO);
FlightSchedule delete(Long id);
}
package com.hcordova.flightagencyapi.flight.domain.services;
import java.util.List;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
import com.hcordova.flightagencyapi.flight.dto.LegSaveDTO;
public interface LegService {
List<Leg> getAll();
List<Leg> saveAll(List<LegSaveDTO> legs);
}
package com.hcordova.flightagencyapi.flight.dto;
import java.time.LocalDateTime;
import com.hcordova.flightagencyapi.flight.domain.models.FlightSchedule;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FlightAllDTO {
private Long id;
private String airportOrigin;
private String airportDestination;
private LocalDateTime departureDate;
private LocalDateTime arrivalDate;
public FlightAllDTO(FlightSchedule flightSchedule) {
this.id = flightSchedule.getId();
this.airportOrigin = flightSchedule.getAirportOrigin().getName();
this.airportDestination = flightSchedule.getAirportDestination().getName();
this.departureDate = flightSchedule.getDepartureDateTime();
this.arrivalDate = flightSchedule.getArrivalDateTime();
}
}
package com.hcordova.flightagencyapi.flight.dto;
import java.util.List;
import com.hcordova.flightagencyapi.flight.domain.models.FlightSchedule;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FlightByDTO {
private Long id;
private String airline;
private Long airlineId;
private String aircraft;
private Long aircraftId;
private String departureDate;
private String arrivalDate;
private List<LegDTO> legs;
private List<FlightCostDTO> costs;
public FlightByDTO(FlightSchedule flightSchedule) {
this.id = flightSchedule.getId();
this.departureDate = flightSchedule.getDepartureDateTime().toLocalDate().toString();
this.arrivalDate = flightSchedule.getArrivalDateTime().toLocalDate().toString();
this.airline = flightSchedule.getAirline().getName();
this.airlineId = flightSchedule.getAirline().getId();
this.aircraft = flightSchedule.getAircraft().getName();
this.aircraftId = flightSchedule.getAircraft().getId();
this.legs = flightSchedule.getLegs().stream().map(leg -> {
return new LegDTO(leg);
}).toList();
this.costs = flightSchedule.getCosts().stream().map(cost -> {
return new FlightCostDTO(cost);
}).toList();
}
}
package com.hcordova.flightagencyapi.flight.dto;
import com.hcordova.flightagencyapi.flight.domain.models.FlightCost;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class FlightCostDTO {
private Long id;
private String dateStart;
private String dateEnd;
private Double cost;
public FlightCostDTO(FlightCost flightCost) {
this.id = flightCost.getId();
this.dateStart = flightCost.getDateStart().toString();
this.dateEnd = flightCost.getDateEnd().toString();
this.cost = flightCost.getCost();
}
}
package com.hcordova.flightagencyapi.flight.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FlightCostSaveDTO {
private Long aircraftId;
private String dateStart;
private String dateEnd;
private Double cost;
}
package com.hcordova.flightagencyapi.flight.dto;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FlightSaveDTO {
private Long airlineId;
private Long aircraftId;
private String departureDate;
private String arrivalDate;
private List<LegSaveDTO> legs;
private List<FlightCostSaveDTO> costs;
}
package com.hcordova.flightagencyapi.flight.dto;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import com.hcordova.flightagencyapi.flight.domain.models.FlightCost;
import com.hcordova.flightagencyapi.flight.domain.models.FlightSchedule;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FlightSearchDTO {
private Long id;
private String airline;
private String aircraft;
private String airportOrigin;
private String airportDestination;
private String flightType;
private String departureDate;
private String arrivalDate;
private Double price;
private List<LegDTO> legs;
public FlightSearchDTO(FlightSchedule flightSchedule, String startDate) {
this.id = flightSchedule.getId();
LocalDate dateToCheck = LocalDate.parse(startDate);
FlightCost flightCost = new FlightCost();
for (FlightCost cost : flightSchedule.getCosts()) {
if ((dateToCheck.isAfter(cost.getDateStart()) && dateToCheck.isBefore(cost.getDateEnd())) ||
dateToCheck.isEqual(cost.getDateStart()) || dateToCheck.isEqual(cost.getDateEnd())) {
flightCost = cost;
}
}
this.airportOrigin = flightSchedule.getAirportOrigin().getName();
this.airportDestination = flightSchedule.getAirportDestination().getName();
LocalDateTime legDeparture = flightSchedule.getLegs().stream().findFirst().get().getActualDeparture();
LocalDateTime legArrival = flightSchedule.getLegs().get(flightSchedule.getLegs().size() - 1).getActualArrival();
Duration duration = java.time.Duration.between(legDeparture, legArrival);
LocalDateTime departureDateTime = LocalDateTime.of(LocalDate.parse(startDate), flightSchedule.getDepartureDateTime().toLocalTime());
LocalDateTime arrivalDateTime = departureDateTime.plus(duration);
calculateDates(flightSchedule.getLegs(), startDate);
this.departureDate = departureDateTime.toString();
this.arrivalDate = arrivalDateTime.toString();
this.airline = flightSchedule.getAirline().getName();
this.aircraft = flightSchedule.getAircraft().getName();
this.flightType = flightSchedule.getLegs().size() > 1 ? "Round Trip" : "One Way";
this.price = flightCost.getCost();
this.legs = flightSchedule.getLegs().stream().map(leg -> {
return new LegDTO(leg);
}).toList();
}
private void calculateDates(List<Leg> legs, String startDate) {
LocalDate start = LocalDate.parse(startDate);
for (int i = 0; i < legs.size(); i++) {
Leg leg = legs.get(i);
if (i == 0) {
leg.setActualDeparture(LocalDateTime.of(start, leg.getActualDeparture().toLocalTime()));
leg.setActualArrival(LocalDateTime.of(start, leg.getActualArrival().toLocalTime()));
} else {
Duration durationDeparture = Duration.between(leg.getActualDeparture(), legs.get(i - 1).getActualArrival());
Duration durationArrival = Duration.between(leg.getActualDeparture(), leg.getActualArrival());
leg.setActualArrival(leg.getActualDeparture().plus(durationArrival));
leg.setActualDeparture(legs.get(i - 1).getActualArrival().plus(durationDeparture));
}
}
}
}
package com.hcordova.flightagencyapi.flight.dto;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class LegDTO {
private Long id;
private String airportOrigin;
private String airportDestination;
private String departureDateTime;
private String arrivalDateTime;
public LegDTO(Leg leg) {
this.id = leg.getId();
this.airportOrigin = leg.getAirportOrigin().getName();
this.airportDestination = leg.getAirportDestination().getName();
this.departureDateTime = leg.getActualDeparture().toString();
this.arrivalDateTime = leg.getActualArrival().toString();
}
}
package com.hcordova.flightagencyapi.flight.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class LegSaveDTO {
private Long airportOriginId;
private Long airportDestinationId;
private String departureDateTime;
private String arrivalDateTime;
}
package com.hcordova.flightagencyapi.flight.services;
import java.util.List;
import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.flight.domain.models.FlightCost;
import com.hcordova.flightagencyapi.flight.domain.repositories.FlightCostRepository;
import com.hcordova.flightagencyapi.flight.domain.services.FlightCostService;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class FlightCostServiceImpl implements FlightCostService {
private final FlightCostRepository flightCostRepository;
@Override
public List<FlightCost> getAll() {
return flightCostRepository.findAll();
}
@Override
public FlightCost getById(Long id) {
return null;
}
}
package com.hcordova.flightagencyapi.flight.services;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.ResponseBody;
import com.hcordova.flightagencyapi.aircraft.domain.services.AircraftService;
import com.hcordova.flightagencyapi.airline.domain.services.AirlineService;
import com.hcordova.flightagencyapi.airport.domain.models.Airport;
import com.hcordova.flightagencyapi.airport.domain.services.AirportService;
import com.hcordova.flightagencyapi.flight.domain.models.FlightCost;
import com.hcordova.flightagencyapi.flight.domain.models.FlightSchedule;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
import com.hcordova.flightagencyapi.flight.domain.repositories.FlightScheduleRepository;
import com.hcordova.flightagencyapi.flight.domain.services.FlightScheduleService;
import com.hcordova.flightagencyapi.flight.dto.FlightSaveDTO;
import com.hcordova.flightagencyapi.shared.exceptions.NotFoundException;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class FlightScheduleServiceImpl implements FlightScheduleService{
private final FlightScheduleRepository flightScheduleRepository;
private final AirlineService airlineService;
private final AircraftService aircraftService;
private final AirportService airportService;
@Override
public List<FlightSchedule> getAll() {
return flightScheduleRepository.findAllByDeletedAtIsNull();
}
@Override
public FlightSchedule save(FlightSaveDTO saveDTO) {
FlightSchedule flightSchedule = new FlightSchedule();
// Set airline and aircraft
flightSchedule.setAirline(airlineService.getById(saveDTO.getAirlineId()));
flightSchedule.setAircraft(aircraftService.getById(saveDTO.getAircraftId()));
// Valid legs size
if (saveDTO.getLegs().size() == 0)
throw new RuntimeException("Invalid legs size");
if (saveDTO.getCosts().size() == 0)
throw new RuntimeException("Invalid costs size");
List<Leg> legsToSave = saveDTO.getLegs().stream().map(leg -> {
Airport airportOrigin = airportService.getById(leg.getAirportOriginId());
Airport airportDestination = airportService.getById(leg.getAirportDestinationId());
try {
LocalDateTime departureDateTime = LocalDateTime.parse(leg.getDepartureDateTime());
LocalDateTime arrivalDateTime = LocalDateTime.parse(leg.getArrivalDateTime());
return new Leg(null, flightSchedule, airportOrigin, airportDestination, departureDateTime, arrivalDateTime, null);
} catch (Exception e) {
throw new RuntimeException("Invalid date format 1");
}
}).toList();
List<FlightCost> costsToSave = saveDTO.getCosts().stream().map(cost -> {
try {
LocalDate validFrontDate = LocalDate.parse(cost.getDateStart());
LocalDate validToDate = LocalDate.parse(cost.getDateEnd());
return new FlightCost(null, flightSchedule, validFrontDate, validToDate, cost.getCost());
} catch (Exception e) {
throw new RuntimeException("Invalid date format 2");
}
}).toList();
// Set departure and arrival date
try {
LocalDateTime departureDate = LocalDateTime.of(LocalDate.parse(saveDTO.getDepartureDate()), legsToSave.get(0).getActualDeparture().toLocalTime());
LocalDateTime arrivalDate = LocalDateTime.of(LocalDate.parse(saveDTO.getArrivalDate()), legsToSave.get(legsToSave.size() - 1).getActualArrival().toLocalTime());
flightSchedule.setDepartureDateTime(departureDate);
flightSchedule.setArrivalDateTime(arrivalDate);
} catch (Exception e) {
throw new RuntimeException("Invalid date format 3");
}
// Set airport origin and destination
flightSchedule.setAirportOrigin(legsToSave.get(0).getAirportOrigin());
flightSchedule.setAirportDestination(legsToSave.get(legsToSave.size() - 1).getAirportDestination());
// Save legs and costs
flightSchedule.setLegs(legsToSave);
flightSchedule.setCosts(costsToSave);
return flightScheduleRepository.save(flightSchedule);
}
@Override
public FlightSchedule getById(Long id) {
return flightScheduleRepository.findByIdAndDeletedAtIsNull(id)
.orElseThrow(() -> new NotFoundException(String.format("Flight with id %d not found", id)));
}
@Override
public FlightSchedule delete(Long id) {
FlightSchedule flightSchedule = getById(id);
flightSchedule.setDeletedAt(LocalDate.now());
return flightScheduleRepository.save(flightSchedule);
}
@Override
@ResponseBody
public List<FlightSchedule> searchByOriginDestinationAndDate(Long airportOriginId, Long airportDestinationId,
String startDate) {
LocalDate date = LocalDate.parse(startDate);
LocalDateTime dateTime = date.atStartOfDay();
return flightScheduleRepository.searchFlight(airportOriginId, airportDestinationId, dateTime);
}
}
package com.hcordova.flightagencyapi.flight.services;
import java.util.List;
import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
import com.hcordova.flightagencyapi.flight.domain.repositories.LegRepository;
import com.hcordova.flightagencyapi.flight.domain.services.LegService;
import com.hcordova.flightagencyapi.flight.dto.LegSaveDTO;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class LegServiceImpl implements LegService{
private final LegRepository legRepository;
@Override
public List<Leg> getAll() {
return legRepository.findAll();
}
@Override
public List<Leg> saveAll(List<LegSaveDTO> legs) {
// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// List<Leg> legsToSave = legs.stream().map(leg -> {
// Airport airportOrigin = airportService.getById(leg.getAirportOriginId());
// Airport airportDestination = airportService.getById(leg.getAirportDestinationId());
// LocalDateTime departureDateTime = LocalDateTime.parse(leg.getDepartureDateTime(), formatter);
// LocalDateTime arrivalDateTime = LocalDateTime.parse(leg.getArrivalDateTime(), formatter);
// return new Leg(null, airportOrigin, airportDestination, departureDateTime, arrivalDateTime);
// }).toList();
// return legRepository.saveAll(legs);
return null;
}
}
...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.passenger.controllers; ...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.passenger.controllers;
import java.util.List; import java.util.List;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
...@@ -18,6 +19,7 @@ import com.hcordova.flightagencyapi.passenger.dto.PassengerTableDTO; ...@@ -18,6 +19,7 @@ import com.hcordova.flightagencyapi.passenger.dto.PassengerTableDTO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping("/api/v1/passengers") @RequestMapping("/api/v1/passengers")
@RequiredArgsConstructor @RequiredArgsConstructor
...@@ -27,8 +29,7 @@ public class PassengerController { ...@@ -27,8 +29,7 @@ public class PassengerController {
@GetMapping @GetMapping
public ResponseEntity<List<PassengerTableDTO>> getAll() { public ResponseEntity<List<PassengerTableDTO>> getAll() {
return ResponseEntity.ok(passengerService.getAll().stream().map(passenger -> { return ResponseEntity.ok(passengerService.getAll().stream().map(passenger -> {
return new PassengerTableDTO(passenger.getId(), passenger.getUser().getName(), passenger.getUser().getLastname(), return new PassengerTableDTO(passenger);
passenger.getCountry(), passenger.getCity());
}).toList()); }).toList());
} }
......
package com.hcordova.flightagencyapi.passenger.domain.repositories; package com.hcordova.flightagencyapi.passenger.domain.repositories;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
...@@ -9,4 +10,6 @@ import com.hcordova.flightagencyapi.passenger.domain.models.Passenger; ...@@ -9,4 +10,6 @@ import com.hcordova.flightagencyapi.passenger.domain.models.Passenger;
public interface PassengerRepository extends JpaRepository<Passenger, Long>{ public interface PassengerRepository extends JpaRepository<Passenger, Long>{
Optional<Passenger> findByUserId(Long userId); Optional<Passenger> findByUserId(Long userId);
List<Passenger> findAllByDeletedAtIsNull();
Optional<Passenger> findByIdAndDeletedAtIsNull(Long id);
} }
package com.hcordova.flightagencyapi.passenger.dto; package com.hcordova.flightagencyapi.passenger.dto;
import com.hcordova.flightagencyapi.passenger.domain.models.Passenger;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
...@@ -11,6 +13,20 @@ public class PassengerTableDTO { ...@@ -11,6 +13,20 @@ public class PassengerTableDTO {
private Long id; private Long id;
private String name; private String name;
private String lastname; private String lastname;
private String fullname;
private String country; private String country;
private String city; private String city;
private String phone;
private String email;
public PassengerTableDTO(Passenger passenger) {
this.id = passenger.getId();
this.name = passenger.getUser().getName();
this.lastname = passenger.getUser().getLastname();
this.fullname = passenger.getUser().getName() + " " + passenger.getUser().getLastname();
this.country = passenger.getCountry();
this.city = passenger.getCity();
this.phone = passenger.getPhone();
this.email = passenger.getUser().getEmail();
}
} }
...@@ -21,12 +21,12 @@ public class PassengerServiceImpl implements PassengerService { ...@@ -21,12 +21,12 @@ public class PassengerServiceImpl implements PassengerService {
@Override @Override
public List<Passenger> getAll() { public List<Passenger> getAll() {
return passengerRepository.findAll(); return passengerRepository.findAllByDeletedAtIsNull();
} }
@Override @Override
public Passenger getById(Long id) { public Passenger getById(Long id) {
return passengerRepository.findById(id) return passengerRepository.findByIdAndDeletedAtIsNull(id)
.orElseThrow(() -> new NotFoundException("Passenger not found")); .orElseThrow(() -> new NotFoundException("Passenger not found"));
} }
......
package com.hcordova.flightagencyapi.reservation.controllers;
import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.hcordova.flightagencyapi.reservation.domain.services.ReservationService;
import com.hcordova.flightagencyapi.reservation.dto.ReservationDTO;
import com.hcordova.flightagencyapi.reservation.dto.ReservationExtendedDTO;
import com.hcordova.flightagencyapi.reservation.dto.ReservationPassengerDTO;
import com.hcordova.flightagencyapi.reservation.dto.ReservationSaveDTO;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping("/api/v1/reservations")
@RequiredArgsConstructor
public class ReservationController {
private final ReservationService reservationService;
@GetMapping
public List<ReservationDTO> getAll() {
return reservationService.getAll().stream().map(reservation -> {
return new ReservationDTO(reservation);
}).toList();
}
@GetMapping("/passenger/{id}")
public List<ReservationPassengerDTO> getByPassengerId(@PathVariable Long id) {
return reservationService.getByPassengerId(id).stream().map(reservation -> {
return new ReservationPassengerDTO(reservation);
}).toList();
}
@PutMapping("/pay/{id}")
public ReservationPassengerDTO payReservation(@PathVariable Long id) {
return new ReservationPassengerDTO(reservationService.payReservation(id));
}
@GetMapping("{id}")
public ReservationExtendedDTO getById(@PathVariable Long id) {
return new ReservationExtendedDTO(reservationService.getById(id));
}
@PostMapping
public ReservationDTO save(@RequestBody ReservationSaveDTO reservationDTO) {
return new ReservationDTO(reservationService.save(reservationDTO));
}
@PutMapping("/cancel/{id}")
public ReservationDTO cancelReservation(@PathVariable Long id) {
return new ReservationDTO(reservationService.cancelReservation(id));
}
@DeleteMapping("{id}")
public ReservationDTO delete(@PathVariable Long id) {
return new ReservationDTO(reservationService.deleteReservation(id));
}
}
package com.hcordova.flightagencyapi.reservation.controllers;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.hcordova.flightagencyapi.reservation.domain.services.TicketTypeService;
import com.hcordova.flightagencyapi.reservation.dto.TicketTypeDTO;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping("/api/v1/ticket-types")
@RequiredArgsConstructor
public class TicketTypeController {
private final TicketTypeService ticketTypeService;
@GetMapping
public List<TicketTypeDTO> getAll() {
return ticketTypeService.getAll().stream().map(ticketType -> {
return new TicketTypeDTO(ticketType);
}).toList();
}
}
package com.hcordova.flightagencyapi.reservation.controllers;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.hcordova.flightagencyapi.reservation.domain.services.TravelClassService;
import com.hcordova.flightagencyapi.reservation.dto.TravelClassDTO;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping("/api/v1/travel-classes")
@RequiredArgsConstructor
public class TravelClassController {
private final TravelClassService travelClassService;
@GetMapping
public List<TravelClassDTO> getAll() {
return travelClassService.getAll().stream().map(travelClass -> {
return new TravelClassDTO(travelClass);
}).toList();
}
}
package com.hcordova.flightagencyapi.reservation.domain.models;
import java.time.LocalDate;
import com.hcordova.flightagencyapi.payment.domain.models.PaymentStatus;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "payments")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Payment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)
private PaymentStatus status;
@Column(nullable = false)
@Temporal(TemporalType.DATE)
private LocalDate date;
@Column(nullable = false, columnDefinition = "DECIMAL(10,2)")
private Double amount;
}
package com.hcordova.flightagencyapi.reservation.domain.models;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import com.hcordova.flightagencyapi.agent.domain.models.Agent;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
import com.hcordova.flightagencyapi.passenger.domain.models.Passenger;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "reservations")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Reservation {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Agent agent;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Passenger passenger;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private ReservationStatus status;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private TicketType ticketType;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private TravelClass travelClass;
@Column(nullable = false)
@Temporal(TemporalType.DATE)
private LocalDate createdAt;
@OneToOne(optional = false, cascade = CascadeType.ALL)
private Payment payment;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "reservations_legs",
joinColumns = @JoinColumn(name = "reservation_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "leg_id", referencedColumnName = "id"))
private List<Leg> legs = new ArrayList<>();
@Column(nullable = true)
@Temporal(TemporalType.DATE)
private LocalDate deletedAt;
}
package com.hcordova.flightagencyapi.reservation.domain.models;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "ticket_type")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class TicketType {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 30, unique = true)
private String name;
}
package com.hcordova.flightagencyapi.reservation.domain.models;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "travel_class")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class TravelClass {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 30, unique = true)
private String name;
}
package com.hcordova.flightagencyapi.reservation.domain.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.reservation.domain.models.Payment;
@Repository
public interface PaymentRepository extends JpaRepository<Payment, Long> {
}
package com.hcordova.flightagencyapi.reservation.domain.repositories;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
@Repository
public interface ReservationsRepository extends JpaRepository<Reservation, Long> {
List<Reservation> findByDeletedAtIsNullAndPassenger_Id(Long passengerId);
List<Reservation> findByDeletedAtIsNull();
Optional<Reservation> findByIdAndDeletedAtIsNull(Long id);
}
package com.hcordova.flightagencyapi.reservation.domain.repositories;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.reservation.domain.models.TicketType;
@Repository
public interface TicketTypeRepository extends JpaRepository<TicketType, Long>{
Optional<TicketType> findById(Long id);
}
package com.hcordova.flightagencyapi.reservation.domain.repositories;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.reservation.domain.models.TravelClass;
@Repository
public interface TravelClassRepository extends JpaRepository<TravelClass, Long> {
Optional<TravelClass> findById(Long id);
}
package com.hcordova.flightagencyapi.reservation.domain.services;
import java.util.List;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
import com.hcordova.flightagencyapi.reservation.dto.ReservationSaveDTO;
public interface ReservationService {
List<Reservation> getAll();
Reservation getById(Long id);
List<Reservation> getByPassengerId(Long id);
Reservation save(ReservationSaveDTO reservationDTO);
Reservation payReservation(Long id);
Reservation cancelReservation(Long id);
Reservation deleteReservation(Long id);
}
package com.hcordova.flightagencyapi.reservation.domain.services;
import java.util.List;
import com.hcordova.flightagencyapi.reservation.domain.models.TicketType;
public interface TicketTypeService {
List<TicketType> getAll();
TicketType getById(Long id);
}
package com.hcordova.flightagencyapi.reservation.domain.services;
import java.util.List;
import com.hcordova.flightagencyapi.reservation.domain.models.TravelClass;
public interface TravelClassService {
List<TravelClass> getAll();
TravelClass getById(Long id);
}
package com.hcordova.flightagencyapi.reservation.dto;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ReservationDTO {
private Long id;
private String passenger;
private String ticketType;
private String travelClass;
private String status;
public ReservationDTO(Reservation reservation) {
this.id = reservation.getId();
this.passenger = reservation.getPassenger().getUser().getName() + " " + reservation.getPassenger().getUser().getLastname();
this.ticketType = reservation.getTicketType().getName();
this.travelClass = reservation.getTravelClass().getName();
this.status = convertStatus(reservation.getStatus().getName());
}
private String convertStatus(String status) {
switch (status.toLowerCase()) {
case "registered":
return "Registrado";
case "processing_payment":
return "Procesando pago";
case "paid":
return "Pagado";
case "cancelled":
return "Cancelado";
default:
return "";
}
}
}
package com.hcordova.flightagencyapi.reservation.dto;
import java.util.List;
import com.hcordova.flightagencyapi.flight.dto.LegDTO;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
import lombok.Getter;
@Getter
public class ReservationExtendedDTO {
private Long id;
private Long passengerId;
private String passenger;
private String ticketType;
private Long airportOriginId;
private String airportOrigin;
private Long airportDestinationId;
private String airportDestination;
private String departureDate;
private Long ticketTypeId;
private String travelClass;
private Long travelClassId;
private Long flightId;
private String status;
List<LegDTO> legs;
public ReservationExtendedDTO(Reservation reservation) {
this.id = reservation.getId();
this.passengerId = reservation.getPassenger().getId();
this.passenger = reservation.getPassenger().getUser().getName() + " " + reservation.getPassenger().getUser().getLastname();
this.ticketType = reservation.getTicketType().getName();
this.ticketTypeId = reservation.getTicketType().getId();
this.airportOriginId = reservation.getLegs().get(0).getFlightSchedule().getAirportOrigin().getId();
this.airportDestinationId = reservation.getLegs().get(0).getFlightSchedule().getAirportDestination().getId();
this.departureDate = reservation.getLegs().get(0).getFlightSchedule().getDepartureDateTime().toLocalDate().toString();
this.travelClass = reservation.getTravelClass().getName();
this.travelClassId = reservation.getTravelClass().getId();
this.airportOrigin = reservation.getLegs().get(0).getFlightSchedule().getAirportOrigin().getName();
this.airportDestination = reservation.getLegs().get(0).getFlightSchedule().getAirportDestination().getName();
this.status = convertStatus(reservation.getStatus().getName());
this.flightId = reservation.getLegs().get(0).getFlightSchedule().getId();
this.legs = reservation.getLegs().stream().map(leg -> {
return new LegDTO(leg);
}).toList();
}
private String convertStatus(String status) {
switch (status) {
case "registered":
return "Registrado";
case "processing_payment":
return "Procesando pago";
case "paid":
return "Pagado";
case "cancelled":
return "Cancelado";
default:
return "";
}
}
}
package com.hcordova.flightagencyapi.reservation.dto;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ReservationPassengerDTO {
private Long id;
private String airportOrigin;
private String airportDestination;
private String reservationMade;
private String status;
private Double cost;
public ReservationPassengerDTO(Reservation reservation) {
this.id = reservation.getId();
this.airportOrigin = reservation.getLegs().get(0).getFlightSchedule().getAirportOrigin().getName();
this.airportDestination = reservation.getLegs().get(0).getFlightSchedule().getAirportDestination().getName();
this.reservationMade = reservation.getCreatedAt().toString();
this.status = convertStatus(reservation.getStatus().getName());
this.cost = reservation.getPayment().getAmount();
}
private String convertStatus(String status) {
switch (status.toLowerCase()) {
case "registered":
return "Registrado";
case "processing_payment":
return "Procesando pago";
case "paid":
return "Pagado";
case "cancelled":
return "Cancelado";
default:
return "";
}
}
}
package com.hcordova.flightagencyapi.reservation.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ReservationSaveDTO {
private Long flightId;
private Long ticketTypeId;
private Long travelClassId;
private Long passengerId;
private Long agentId;
private String reservationMade;
private Double cost;
}
package com.hcordova.flightagencyapi.reservation.dto;
import com.hcordova.flightagencyapi.reservation.domain.models.TicketType;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class TicketTypeDTO {
private Long id;
private String name;
public TicketTypeDTO(TicketType ticketType) {
this.id = ticketType.getId();
this.name = ticketType.getName();
}
}
package com.hcordova.flightagencyapi.reservation.dto;
import com.hcordova.flightagencyapi.reservation.domain.models.TravelClass;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class TravelClassDTO {
private Long id;
private String name;
public TravelClassDTO(TravelClass travelClass) {
this.id = travelClass.getId();
this.name = travelClass.getName();
}
}
package com.hcordova.flightagencyapi.reservation.services;
import java.time.LocalDate;
import java.util.List;
import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.agent.domain.services.AgentService;
import com.hcordova.flightagencyapi.flight.domain.services.FlightScheduleService;
import com.hcordova.flightagencyapi.passenger.domain.services.PassengerService;
import com.hcordova.flightagencyapi.payment.domain.models.PaymentStatus;
import com.hcordova.flightagencyapi.payment.domain.services.PaymentStatusService;
import com.hcordova.flightagencyapi.reservation.domain.models.Payment;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
import com.hcordova.flightagencyapi.reservation.domain.repositories.ReservationsRepository;
import com.hcordova.flightagencyapi.reservation.domain.services.ReservationService;
import com.hcordova.flightagencyapi.reservation.domain.services.ReservationStatusService;
import com.hcordova.flightagencyapi.reservation.domain.services.TicketTypeService;
import com.hcordova.flightagencyapi.reservation.domain.services.TravelClassService;
import com.hcordova.flightagencyapi.reservation.dto.ReservationSaveDTO;
import com.hcordova.flightagencyapi.shared.exceptions.NotFoundException;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class ReservationServiceImpl implements ReservationService {
private final ReservationsRepository reservationsRepository;
private final TicketTypeService ticketTypeService;
private final TravelClassService travelClassService;
private final AgentService agentService;
private final PassengerService passengerService;
private final FlightScheduleService flightScheduleService;
private final ReservationStatusService reservationStatusService;
private final PaymentStatusService paymentStatusService;
@Override
public List<Reservation> getAll() {
return reservationsRepository.findByDeletedAtIsNull();
}
@Override
public Reservation getById(Long id) {
return reservationsRepository.findByIdAndDeletedAtIsNull(id)
.orElseThrow(() -> new NotFoundException(String.format("Reservation with id %d not found", id)));
}
@Override
@Transactional
public Reservation save(ReservationSaveDTO reservationDTO) {
Reservation reservation = new Reservation();
var ticketType = ticketTypeService.getById(reservationDTO.getTicketTypeId());
var travelClass = travelClassService.getById(reservationDTO.getTravelClassId());
var passenger = passengerService.getById(reservationDTO.getPassengerId());
var agent = agentService.getById(reservationDTO.getAgentId());
var legs = flightScheduleService.getById(reservationDTO.getFlightId()).getLegs();
var status = reservationStatusService.findByName("registered");
legs.stream().map(leg -> leg.getReservations().add(reservation));
reservation.getLegs().addAll(legs);
try {
reservation.setCreatedAt(LocalDate.parse(reservationDTO.getReservationMade()));
} catch (Exception e) {
throw new RuntimeException("Invalid date format");
}
Payment payment = new Payment();
PaymentStatus paymentStatus = paymentStatusService.findByName("pending");
payment.setDate(LocalDate.now());
payment.setStatus(paymentStatus);
payment.setAmount(reservationDTO.getCost());
reservation.setAgent(agent);
reservation.setPassenger(passenger);
reservation.setTicketType(ticketType);
reservation.setTravelClass(travelClass);
reservation.setStatus(status);
reservation.setPayment(payment);
return reservationsRepository.save(reservation);
}
@Override
public List<Reservation> getByPassengerId(Long id) {
return reservationsRepository.findByDeletedAtIsNullAndPassenger_Id(id);
}
@Override
public Reservation payReservation(Long id) {
Reservation reservation = getById(id);
PaymentStatus paymentStatus = paymentStatusService.findByName("paid");
reservation.getPayment().setStatus(paymentStatus);
reservation.setStatus(reservationStatusService.findByName("paid"));
return reservationsRepository.save(reservation);
}
@Override
public Reservation cancelReservation(Long id) {
Reservation reservation = getById(id);
System.out.println(reservation.getStatus().getName().toLowerCase());
if (reservation.getStatus().getName().toLowerCase().equals("registered")) {
PaymentStatus paymentStatus = paymentStatusService.findByName("refunded");
reservation.getPayment().setStatus(paymentStatus);
reservation.setStatus(reservationStatusService.findByName("Cancelled"));
return reservationsRepository.save(reservation);
} else {
System.out.println(id);
throw new RuntimeException("Reservation already paid");
}
}
@Override
public Reservation deleteReservation(Long id) {
Reservation reservation = getById(id);
if (reservation.getStatus().getName().toLowerCase().equals("registered") ||
reservation.getStatus().getName().toLowerCase().equals("cancelled")) {
reservation.setDeletedAt(LocalDate.now());
return reservationsRepository.save(reservation);
} else {
throw new RuntimeException("Reservation already paid");
}
}
}
package com.hcordova.flightagencyapi.reservation.services;
import java.util.List;
import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.reservation.domain.models.TicketType;
import com.hcordova.flightagencyapi.reservation.domain.repositories.TicketTypeRepository;
import com.hcordova.flightagencyapi.reservation.domain.services.TicketTypeService;
import com.hcordova.flightagencyapi.shared.exceptions.NotFoundException;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class TicketTypeServiceImpl implements TicketTypeService {
private final TicketTypeRepository ticketTypeRepository;
@Override
public List<TicketType> getAll() {
return ticketTypeRepository.findAll();
}
@Override
public TicketType getById(Long id) {
return ticketTypeRepository.findById(id)
.orElseThrow(() -> new NotFoundException(String.format("TicketType with id %d not found", id)));
}
}
package com.hcordova.flightagencyapi.reservation.services;
import java.util.List;
import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.reservation.domain.models.TravelClass;
import com.hcordova.flightagencyapi.reservation.domain.repositories.TravelClassRepository;
import com.hcordova.flightagencyapi.reservation.domain.services.TravelClassService;
import com.hcordova.flightagencyapi.shared.exceptions.NotFoundException;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class TravelClassServiceImpl implements TravelClassService {
private final TravelClassRepository travelClassRepository;
@Override
public List<TravelClass> getAll() {
return travelClassRepository.findAll();
}
@Override
public TravelClass getById(Long id) {
return travelClassRepository.findById(id)
.orElseThrow(() -> new NotFoundException(String.format("TravelClass with id %d not found", id)));
}
}
...@@ -13,7 +13,6 @@ import org.springframework.util.StringUtils; ...@@ -13,7 +13,6 @@ import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import com.hcordova.flightagencyapi.shared.domain.services.JwtService; import com.hcordova.flightagencyapi.shared.domain.services.JwtService;
import com.hcordova.flightagencyapi.shared.domain.services.UserService;
import jakarta.servlet.FilterChain; import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
...@@ -35,9 +34,10 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { ...@@ -35,9 +34,10 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
final String jwt; final String jwt;
final String userEmail; final String userEmail;
System.out.println(request.getHeader("Authorization"));
if (!StringUtils.hasText(authHeader) || !authHeader.startsWith("Bearer ")) { if (!StringUtils.hasText(authHeader) || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response); filterChain.doFilter(request, response);
return; return ;
} }
jwt = authHeader.substring(7); jwt = authHeader.substring(7);
......
package com.hcordova.flightagencyapi.shared.config; package com.hcordova.flightagencyapi.shared.config;
import java.util.Arrays;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
...@@ -15,6 +17,9 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; ...@@ -15,6 +17,9 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
...@@ -25,17 +30,30 @@ public class SecurityConfig { ...@@ -25,17 +30,30 @@ public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthenticationFilter; private final JwtAuthenticationFilter jwtAuthenticationFilter;
private final UserDetailsService userService; private final UserDetailsService userService;
@Bean @Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable) http.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(request -> request.requestMatchers("/api/v1/auth/**") .authorizeHttpRequests(request -> request.requestMatchers("/api/v1/auth/**")
.permitAll().anyRequest().authenticated()) .permitAll().anyRequest().authenticated())
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.sessionManagement(manager -> manager.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .sessionManagement(manager -> manager.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authenticationProvider(authenticationProvider()).addFilterBefore( .authenticationProvider(authenticationProvider()).addFilterBefore(
jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build(); return http.build();
} }
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("*", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
configuration.applyPermitDefaultValues();
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean @Bean
public PasswordEncoder passwordEncoder() { public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); return new BCryptPasswordEncoder();
......
...@@ -2,7 +2,6 @@ package com.hcordova.flightagencyapi.shared.services; ...@@ -2,7 +2,6 @@ package com.hcordova.flightagencyapi.shared.services;
import java.time.LocalDate; import java.time.LocalDate;
import org.springframework.cglib.core.Local;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
......
-- INSERT INTO roles (name) VALUES ('supervisor'), ('agent'), ('passenger'); INSERT INTO roles (name) VALUES ('supervisor'), ('agent'), ('passenger');
-- INSERT INTO airports (name, location, code) INSERT INTO airports (name, location, code)
-- VALUES VALUES
-- ('Jorge Chavez International Airport', 'Lima, Peru', 'LIM'), ('Jorge Chavez International Airport', 'Lima, Peru', 'LIM'),
-- ('John F. Kennedy International Airport', 'New York, USA', 'JFK'), ('John F. Kennedy International Airport', 'New York, USA', 'JFK'),
-- ('Heathrow Airport', 'London, UK', 'LHR'), ('Heathrow Airport', 'London, UK', 'LHR'),
-- ('Charles de Gaulle Airport', 'Paris, France', 'CDG'), ('Charles de Gaulle Airport', 'Paris, France', 'CDG'),
-- ('Los Angeles International Airport', 'Los Angeles, USA', 'LAX'), ('Los Angeles International Airport', 'Los Angeles, USA', 'LAX'),
-- ('Sydney Kingsford Smith Airport', 'Sydney, Australia', 'SYD'), ('Sydney Kingsford Smith Airport', 'Sydney, Australia', 'SYD'),
-- ('Dubai International Airport', 'Dubai, UAE', 'DXB'), ('Dubai International Airport', 'Dubai, UAE', 'DXB'),
-- ('Beijing Capital International Airport', 'Beijing, China', 'PEK'), ('Beijing Capital International Airport', 'Beijing, China', 'PEK'),
-- ('Benito Juarez International Airport', 'Mexico City, Mexico', 'MEX'), ('Benito Juarez International Airport', 'Mexico City, Mexico', 'MEX'),
-- ('Frankfurt Airport', 'Frankfurt, Germany', 'FRA'), ('Frankfurt Airport', 'Frankfurt, Germany', 'FRA'),
-- ('Toronto Pearson International Airport', 'Toronto, Canada', 'YYZ'), ('Toronto Pearson International Airport', 'Toronto, Canada', 'YYZ'),
-- ('Incheon International Airport', 'Seoul, South Korea', 'ICN'), ('Incheon International Airport', 'Seoul, South Korea', 'ICN'),
-- ('Sao Paulo-Guarulhos International Airport', 'Sao Paulo, Brazil', 'GRU'), ('Sao Paulo-Guarulhos International Airport', 'Sao Paulo, Brazil', 'GRU'),
-- ('Barcelona-El Prat Airport', 'Barcelona, Spain', 'BCN'), ('Barcelona-El Prat Airport', 'Barcelona, Spain', 'BCN'),
-- ('Cairo International Airport', 'Cairo, Egypt', 'CAI'); ('Cairo International Airport', 'Cairo, Egypt', 'CAI');
\ No newline at end of file
INSERT INTO airlines (name, code) VALUES
('American Airlines', 'AA'),
('Delta Air Lines', 'DL'),
('United Airlines', 'UA'),
('Emirates', 'EK'),
('Lufthansa', 'LH'),
('British Airways', 'BA'),
('Qatar Airways', 'QR'),
('Air France', 'AF'),
('LATAM Airlines', 'LA');
INSERT INTO aircrafts (name, manufacturer, model) VALUES
('Boeing 737', 'Boeing', '737-800'),
('Airbus A320', 'Airbus', 'A320-200'),
('Boeing 787 Dreamliner', 'Boeing', '787-9'),
('Embraer E175', 'Embraer', 'E175');
-- Insertar fechas y días de la semana para noviembre
INSERT INTO ref_calendar (day_date, day_number) VALUES
('2023-11-01', 3),
('2023-11-02', 4),
('2023-11-03', 5),
('2023-11-04', 6),
('2023-11-05', 7),
('2023-11-06', 1),
('2023-11-07', 2),
('2023-11-08', 3),
('2023-11-09', 4),
('2023-11-10', 5),
('2023-11-11', 6),
('2023-11-12', 7),
('2023-11-13', 1),
('2023-11-14', 2),
('2023-11-15', 3),
('2023-11-16', 4),
('2023-11-17', 5),
('2023-11-18', 6),
('2023-11-19', 7),
('2023-11-20', 1),
('2023-11-21', 2),
('2023-11-22', 3),
('2023-11-23', 4),
('2023-11-24', 5),
('2023-11-25', 6),
('2023-11-26', 7),
('2023-11-27', 1),
('2023-11-28', 2),
('2023-11-29', 3),
('2023-11-30', 4);
-- Insertar fechas y días de la semana para diciembre
INSERT INTO ref_calendar (day_date, day_number) VALUES
('2023-12-01', 5),
('2023-12-02', 6),
('2023-12-03', 7),
('2023-12-04', 1),
('2023-12-05', 2),
('2023-12-06', 3),
('2023-12-07', 4),
('2023-12-08', 5),
('2023-12-09', 6),
('2023-12-10', 7),
('2023-12-11', 1),
('2023-12-12', 2),
('2023-12-13', 3),
('2023-12-14', 4),
('2023-12-15', 5),
('2023-12-16', 6),
('2023-12-17', 7),
('2023-12-18', 1),
('2023-12-19', 2),
('2023-12-20', 3),
('2023-12-21', 4),
('2023-12-22', 5),
('2023-12-23', 6),
('2023-12-24', 7),
('2023-12-25', 1),
('2023-12-26', 2),
('2023-12-27', 3),
('2023-12-28', 4),
('2023-12-29', 5),
('2023-12-30', 6),
('2023-12-31', 7);
INSERT INTO ticket_type (name) VALUES ('Economy'), ('Business'), ('First Class');
INSERT INTO travel_class (name) VALUES ('Economy'), ('Business'), ('First Class');
INSERT INTO reservation_status (name) VALUES ('registered'), ('processing_payment'), ('Cancelled'), ('paid');
INSERT INTO payment_status (name) VALUES ('pending'), ('paid'), ('refunded');
...@@ -64,10 +64,12 @@ ...@@ -64,10 +64,12 @@
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@angular-devkit/build-angular:dev-server",
"configurations": { "configurations": {
"production": { "production": {
"browserTarget": "flight-agency-app:build:production" "browserTarget": "flight-agency-app:build:production",
"proxyConfig": "proxy.conf.json"
}, },
"development": { "development": {
"browserTarget": "flight-agency-app:build:development" "browserTarget": "flight-agency-app:build:development",
"proxyConfig": "proxy.conf.json"
} }
}, },
"defaultConfiguration": "development" "defaultConfiguration": "development"
......
{
"/api": {
"target": "http://localhost:8085",
"secure": false
}
}
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { HomePageComponent } from './pages/home-page/home-page.component';
import { ReservationsComponent } from './pages/reservations/reservations.component'; import { ReservationsComponent } from './pages/reservations/reservations.component';
import { PassengerAddComponent } from './pages/passenger-add/passenger-add.component'; import { PassengerAddComponent } from './pages/passenger-add/passenger-add.component';
import { ReservationAddComponent } from './pages/reservation-add/reservation-add.component'; import { ReservationAddComponent } from './pages/reservation-add/reservation-add.component';
......
<div class="base__fields"> <div class="base__fields">
<div class="field field-passenger"> <div class="field field-passenger">
<shared-input-selector name="Pasajeros" [value]="getPassengerName(getControl('passenger').value)" [tableModel]="passengerModel" [tableData]="passengers" (onSelect)="onSelectedPassenger($event)"></shared-input-selector> <shared-input-selector
name="Pasajeros"
[tableModel]="passengerModel"
[tableData]="passengers"
[control]="getControl('passenger')"
fieldShow="fullname">
</shared-input-selector>
</div> </div>
<div class="field"> <div class="field">
<shared-input-dropdown name="Tipo de ticket" class="field-select" [control]="getControl('ticketType')" [data]="ticketTypes"></shared-input-dropdown> <shared-input-dropdown
name="Tipo de ticket"
class="field-select"
[control]="getControl('ticketType')"
[data]="ticketTypes">
</shared-input-dropdown>
</div> </div>
<div class="field"> <div class="field">
<shared-input-dropdown name="Tipo de pago" class="field-select" [control]="getControl('flightClass')" [data]="flightClass"></shared-input-dropdown> <shared-input-dropdown
name="Tipo de pago"
class="field-select"
[control]="getControl('flightClass')"
[data]="flightClass">
</shared-input-dropdown>
</div> </div>
</div> </div>
...@@ -16,23 +16,17 @@ import { FormControl, FormGroup } from '@angular/forms'; ...@@ -16,23 +16,17 @@ import { FormControl, FormGroup } from '@angular/forms';
}) })
export class BaseInformationComponent { export class BaseInformationComponent {
constructor() {}
public passengerModel: TableModel[] = [ public passengerModel: TableModel[] = [
{ {
name: 'id', name: 'id',
title: '#' title: '#'
}, },
{ {
name: 'name', name: 'fullname',
title: 'Nombre' title: 'Nombre'
}, },
{
name: 'secondName',
title: 'Segundo Nombre'
},
{
name: 'lastname',
title: 'Apellido'
},
{ {
name: 'email', name: 'email',
title: 'Correo' title: 'Correo'
...@@ -45,18 +39,13 @@ export class BaseInformationComponent { ...@@ -45,18 +39,13 @@ export class BaseInformationComponent {
@Input() @Input()
public group: FormGroup = new FormGroup({ public group: FormGroup = new FormGroup({
passenger: new FormControl<string | null>(null), passenger: new FormControl<number | null>(null),
ticketType: new FormControl<string | null>(null), ticketType: new FormControl<number | null>(null),
flightClass: new FormControl<string | null>(null), flightClass: new FormControl<number | null>(null),
}); });
constructor() { } getControl(name: string): FormControl<number | null> {
return this.group.get(name) as FormControl<number | null>;
getControl(name: string): FormControl<string | null> {
return this.group.get(name) as FormControl<string | null>;
}
ngOnInit(): void {
} }
@Input() @Input()
...@@ -67,15 +56,4 @@ export class BaseInformationComponent { ...@@ -67,15 +56,4 @@ export class BaseInformationComponent {
@Input() @Input()
public flightClass: DropdownElement[] = []; public flightClass: DropdownElement[] = [];
onSelectedPassenger(passenger: Passenger): void {
this.group.get('passenger')?.setValue(passenger.id);
}
getPassengerName(id: string | null): string | null {
if (id) {
const passenger = this.passengers.find(passenger => passenger.id === Number.parseInt(id));
return passenger ? `${passenger.name} ${passenger.lastname}` : null;
} return null;
}
} }
...@@ -6,8 +6,7 @@ ...@@ -6,8 +6,7 @@
name="Aeropuerto origen" name="Aeropuerto origen"
[tableModel]="airportModel" [tableModel]="airportModel"
[tableData]="airports" [tableData]="airports"
(onSelect)="onSelectAirportOrigin($event)" [control]="airportOriginControl">
[value]="getControl('airportOrigin').value">
</shared-input-selector> </shared-input-selector>
</div> </div>
<div class="field field-airport-destination"> <div class="field field-airport-destination">
...@@ -15,16 +14,18 @@ ...@@ -15,16 +14,18 @@
name="Aeropuerto destino" name="Aeropuerto destino"
[tableModel]="airportModel" [tableModel]="airportModel"
[tableData]="airports" [tableData]="airports"
(onSelect)="onSelectAirportDestination($event)" [control]="airportDestinationControl">
[value]="getControl('airportDestination').value">
</shared-input-selector> </shared-input-selector>
</div> </div>
<div class="field field-date-start"> <div class="field field-date-start">
<shared-input-calendar name="Fecha" [control]="getControl('date')"></shared-input-calendar> <shared-input-calendar
[control]="dateControl"
name="Fecha">
</shared-input-calendar>
</div> </div>
</div> </div>
<div class="search__actions"> <div class="search__actions">
<button (click)="onSearchFlights()" class="btn btn-filtrar">Filtrar</button> <button [disabled]="group.invalid" (click)="onSearchFlights()" class="btn btn-filtrar">Filtrar</button>
</div> </div>
</form> </form>
<shared-table-search [tableModel]="flightModel" [tableData]="flightResults" (onSelect)="onEventSelectFlight($event)"></shared-table-search> <shared-table-search [tableModel]="flightModel" [tableData]="flightResults" (onSelect)="onEventSelectFlight($event)"></shared-table-search>
......
...@@ -3,7 +3,7 @@ import { TableModel } from 'src/app/shared/interfaces/table-model.interface'; ...@@ -3,7 +3,7 @@ import { TableModel } from 'src/app/shared/interfaces/table-model.interface';
import { AirportsService } from '../../services/airports.service'; import { AirportsService } from '../../services/airports.service';
import { Airport } from '../../interfaces/airport.interface'; import { Airport } from '../../interfaces/airport.interface';
import { FlightService } from 'src/app/supervisor/services/flight.service'; import { FlightService } from 'src/app/supervisor/services/flight.service';
import { FormControl, FormGroup } from '@angular/forms'; import { FormControl, FormGroup, Validators } from '@angular/forms';
import { Flight } from 'src/app/supervisor/interfaces/flight.interface'; import { Flight } from 'src/app/supervisor/interfaces/flight.interface';
@Component({ @Component({
...@@ -39,17 +39,29 @@ export class FlightInformationComponent implements OnInit { ...@@ -39,17 +39,29 @@ export class FlightInformationComponent implements OnInit {
@Input() @Input()
public group: FormGroup = new FormGroup({ public group: FormGroup = new FormGroup({
airportOrigin: new FormControl<string | null>(null), airportOrigin: new FormControl<number | null>(null),
airportDestination: new FormControl<string | null>(null), airportDestination: new FormControl<number | null>(null),
date: new FormControl<string | null>(null) date: new FormControl<string | null>(null)
}); });
getControl(name: string): FormControl<string | null> { get airportOriginControl(): FormControl<number | null> {
return this.group.get(name) as FormControl<string | null>; return this.group.get('airportOrigin') as FormControl<number | null>;
} }
public airports: Airport[] = []; get airportDestinationControl(): FormControl<number | null> {
return this.group.get('airportDestination') as FormControl<number | null>;
}
get dateControl(): FormControl<string | null> {
return this.group.get('date') as FormControl<string | null>;
}
get airportOriginName(): string {
const airport = this.airports.find(airport => airport.id === this.airportOriginControl.value);
return airport?.name || '';
}
public airports: Airport[] = [];
constructor( constructor(
private airpotsService: AirportsService, private airpotsService: AirportsService,
...@@ -59,25 +71,23 @@ export class FlightInformationComponent implements OnInit { ...@@ -59,25 +71,23 @@ export class FlightInformationComponent implements OnInit {
this.airpotsService.getAll() this.airpotsService.getAll()
.subscribe(airports => this.airports = airports); .subscribe(airports => this.airports = airports);
this.flightSelected ? this.flightResults.push(this.flightSelected) : []; if (this.group.value.airportOrigin !== null && this.group.value.airportDestination !== null && this.group.value.date !== null) {
}
onSelectAirportOrigin(airport: Airport): void {
this.getControl('airportOrigin').setValue(airport.name);
}
onSelectAirportDestination(airport: Airport): void {
this.getControl('airportDestination').setValue(airport.name);
}
onSearchFlights(): void {
this.group.markAllAsTouched();
if (this.group.valid) {
this.flightService.searchFlight(this.group.value.airportOrigin, this.group.value.airportDestination, this.group.value.date) this.flightService.searchFlight(this.group.value.airportOrigin, this.group.value.airportDestination, this.group.value.date)
.subscribe(flights => { .subscribe(flights => {
this.flightResults = flights; this.flightResults = flights;
}); });
} }
this.flightSelected ? this.flightResults.push(this.flightSelected) : [];
}
onSearchFlights(): void {
const formValues = this.group.value;
this.flightService.searchFlight(formValues.airportOrigin, formValues.airportDestination, formValues.date)
.subscribe(flights => {
console.log(flights);
this.flightResults = flights;
});
} }
@Output() @Output()
......
...@@ -41,11 +41,11 @@ ...@@ -41,11 +41,11 @@
</div> </div>
<div class="flight__content-item"> <div class="flight__content-item">
<span class="content__item-label">Fecha de partida</span> <span class="content__item-label">Fecha de partida</span>
<span class="content__item_value">{{ flightSelected?.dateStart }}</span> <span class="content__item_value">{{ flightSelected?.departureDate }}</span>
</div> </div>
<div class="flight__content-item"> <div class="flight__content-item">
<span class="content__item-label">Fecha de llegada</span> <span class="content__item-label">Fecha de llegada</span>
<span class="content__item_value">{{ flightSelected?.dateEnd }}</span> <span class="content__item_value">{{ flightSelected?.arrivalDate }}</span>
</div> </div>
<div class="flight__content-item"> <div class="flight__content-item">
<span class="content__item-label">Aerolinea</span> <span class="content__item-label">Aerolinea</span>
...@@ -53,11 +53,11 @@ ...@@ -53,11 +53,11 @@
</div> </div>
<div class="flight__content-item"> <div class="flight__content-item">
<span class="content__item-label">Tipo de vuelo</span> <span class="content__item-label">Tipo de vuelo</span>
<span class="content__item_value">{{ flighType }}</span> <span class="content__item_value">{{ flightSelected?.flightType }}</span>
</div> </div>
<div class="flight__content-item"> <div class="flight__content-item">
<span class="content__item-label">Precio</span> <span class="content__item-label">Precio</span>
<span class="content__item_value">{{ totalCost }} USD</span> <span class="content__item_value">{{ flightSelected?.price }} USD</span>
</div> </div>
</div> </div>
</section> </section>
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
<h3 class="detail__header-title">Detalle de vuelo</h3> <h3 class="detail__header-title">Detalle de vuelo</h3>
</div> </div>
<div class="detail__content"> <div class="detail__content">
<shared-table-search [tableModel]="scaleModel" [tableData]="flightSelected?.scales || []"></shared-table-search> <shared-table-search [tableModel]="scaleModel" [tableData]="flightSelected?.legs || []"></shared-table-search>
</div> </div>
</section> </section>
</div> </div>
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Input, Output } from '@angular/core';
import { TableModel } from 'src/app/shared/interfaces/table-model.interface'; import { TableModel } from 'src/app/shared/interfaces/table-model.interface';
import { CostFlight } from 'src/app/supervisor/interfaces/cost-flight.interface'; import { FlightCost } from 'src/app/supervisor/interfaces/flight-cost.interface';
import { Flight } from 'src/app/supervisor/interfaces/flight.interface'; import { Flight } from 'src/app/supervisor/interfaces/flight.interface';
@Component({ @Component({
...@@ -24,11 +24,11 @@ export class SummaryInformationComponent { ...@@ -24,11 +24,11 @@ export class SummaryInformationComponent {
title: 'Destino' title: 'Destino'
}, },
{ {
name: 'dateStart', name: 'departureDateTime',
title: 'Fecha de salida' title: 'Fecha de salida'
}, },
{ {
name: 'dateEnd', name: 'arrivalDateTime',
title: 'Fecha de llegada' title: 'Fecha de llegada'
} }
] ]
...@@ -49,14 +49,10 @@ export class SummaryInformationComponent { ...@@ -49,14 +49,10 @@ export class SummaryInformationComponent {
public onChangeStep: EventEmitter<number> = new EventEmitter<number>(); public onChangeStep: EventEmitter<number> = new EventEmitter<number>();
get flighType(): string {
return this.flightSelected ? this.flightSelected.scales.length > 1 ? 'Con escalas' : 'Directo' : '';
}
get totalCost(): number | null { get totalCost(): number | null {
const costs = this.flightSelected?.costs; const costs = this.flightSelected?.costs;
const date: Date = new Date(this.flightSelected?.dateStart as string); const date: Date = new Date(this.flightSelected?.departureDate as string);
const cost: CostFlight | null = null; const cost: FlightCost | null = null;
if (costs) { if (costs) {
for (let i = 0; i < costs.length; i++) { for (let i = 0; i < costs.length; i++) {
......
export interface PassengerSave {
name: string;
lastname: string;
phone: string;
country: string;
city: string;
address: string;
email: string;
password: string;
role: string
}
export interface Passenger { export interface Passenger {
id: number; id: number;
name: string; name: string;
secondName: string; fullname?: string;
lastname: string; lastname: string;
phone: string; phone: string;
country: string; country: string;
city: string; city: string;
address: string; address: string;
email: string; email: string;
password: string; password?: string;
role?: string;
} }
export const EMPTY_PASSENGER: Passenger = { export const EMPTY_PASSENGER: Passenger = {
id: 0, id: 0,
name: '', name: '',
secondName: '',
lastname: '', lastname: '',
country: '', country: '',
city: '', city: '',
address: '', address: '',
phone: '', phone: '',
email: '', email: '',
password: ''
}; };
export interface ReservationSave {
flightId: number;
agentId: number;
passengerId: number;
ticketTypeId: number;
travelClassId: number;
reservationMade: string;
cost: number;
}
interface Reservation { export interface Reservation {
id?: number; id?: number;
agentId: number; agentId: number;
passenger?: string;
passengerId: number; passengerId: number;
passengerName: string; ticketTypeId: number;
statusCode: ReservationStatusCode; travelClassId: number;
ticketTypeCode: number; status: string;
ticketTypeName: string; airportOriginId: number;
travelClassCode: number; airporOrigin?: string;
travelClassName: string; airportDestinationId: number;
dateReservationMade: string; airportDestination?: string;
reservationMade: string;
departureDate: string;
flightId: number; flightId: number;
} }
type ReservationStatusCode = 'REGISTRADO' | 'PROCESANDO_PAGO' | 'CANCELADO' | 'PAGADO';
export { Reservation, ReservationStatusCode };
...@@ -31,11 +31,7 @@ ...@@ -31,11 +31,7 @@
gap: 16px; gap: 16px;
} }
.field-address { .field-name, .field-address, .field-email, .field-password {
grid-column: 1 / 3;
}
.field-email, .field-password {
grid-column: 1 / 3; grid-column: 1 / 3;
} }
......
...@@ -14,11 +14,6 @@ ...@@ -14,11 +14,6 @@
<label for="field-name">Nombre *</label> <label for="field-name">Nombre *</label>
<shared-input-validator [formGroup]="passengerForm" field="name" [getValidatorLength]="getPassengerValidatorLenght"></shared-input-validator> <shared-input-validator [formGroup]="passengerForm" field="name" [getValidatorLength]="getPassengerValidatorLenght"></shared-input-validator>
</div> </div>
<div class="field field-second">
<input type="text" name="secondName" formControlName="secondName" id="field-second">
<label for="field-second">Segundo nombre *</label>
<shared-input-validator [formGroup]="passengerForm" field="secondName" [getValidatorLength]="getPassengerValidatorLenght"></shared-input-validator>
</div>
<div class="field field-lastname"> <div class="field field-lastname">
<input type="text" name="lastname" formControlName="lastname" id="field-lastname"> <input type="text" name="lastname" formControlName="lastname" id="field-lastname">
<label for="field-lastname">Apellidos *</label> <label for="field-lastname">Apellidos *</label>
......
...@@ -5,6 +5,7 @@ import { PassengerService } from '../../services/passenger.service'; ...@@ -5,6 +5,7 @@ import { PassengerService } from '../../services/passenger.service';
import { EMPTY_PASSENGER, Passenger } from '../../interfaces/passenger.interface'; import { EMPTY_PASSENGER, Passenger } from '../../interfaces/passenger.interface';
import { PASSENGER_VALIDATORS, getPassengerValidatorLenght } from '../../validators/passenger.validator'; import { PASSENGER_VALIDATORS, getPassengerValidatorLenght } from '../../validators/passenger.validator';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { SecurityService } from 'src/app/security/services/security.service';
@Component({ @Component({
selector: 'app-passenger-add', selector: 'app-passenger-add',
...@@ -19,6 +20,7 @@ export class PassengerAddComponent implements OnInit { ...@@ -19,6 +20,7 @@ export class PassengerAddComponent implements OnInit {
constructor( constructor(
private location: Location, private location: Location,
private activatedRoute: ActivatedRoute, private activatedRoute: ActivatedRoute,
private securityService: SecurityService,
private passengerService: PassengerService) { } private passengerService: PassengerService) { }
ngOnInit(): void { ngOnInit(): void {
...@@ -35,7 +37,6 @@ export class PassengerAddComponent implements OnInit { ...@@ -35,7 +37,6 @@ export class PassengerAddComponent implements OnInit {
buildForm(passenger: Passenger): void { buildForm(passenger: Passenger): void {
this.passengerForm.get('name')?.setValue(passenger.name || ''); this.passengerForm.get('name')?.setValue(passenger.name || '');
this.passengerForm.get('secondName')?.setValue(passenger.secondName || '');
this.passengerForm.get('lastname')?.setValue(passenger.lastname || ''); this.passengerForm.get('lastname')?.setValue(passenger.lastname || '');
this.passengerForm.get('country')?.setValue(passenger.country || ''); this.passengerForm.get('country')?.setValue(passenger.country || '');
this.passengerForm.get('city')?.setValue(passenger.city || ''); this.passengerForm.get('city')?.setValue(passenger.city || '');
...@@ -58,7 +59,7 @@ export class PassengerAddComponent implements OnInit { ...@@ -58,7 +59,7 @@ export class PassengerAddComponent implements OnInit {
this.location.back(); this.location.back();
}); });
} else { } else {
this.passengerService.save(this.passengerForm.value) this.securityService.signup({...this.passengerForm.value, role: 'passenger'})
.subscribe(() => { .subscribe(() => {
this.passengerForm.reset(); this.passengerForm.reset();
this.location.back(); this.location.back();
......
...@@ -17,8 +17,9 @@ ...@@ -17,8 +17,9 @@
<div *ngSwitchCase="1"> <div *ngSwitchCase="1">
<agent-flight-information <agent-flight-information
(onSelectFlight)="onSelectFlight($event)" (onSelectFlight)="onSelectFlight($event)"
[group]="formFlightInformation" [flightSelected]="flightSelected" [flightSelected]="flightSelected"
[flightModel]="flightModel"> [flightModel]="flightModel"
[group]="formFlightInformation">
</agent-flight-information> </agent-flight-information>
</div> </div>
<div *ngSwitchCase="2"> <div *ngSwitchCase="2">
......
...@@ -8,11 +8,13 @@ import { Flight } from 'src/app/supervisor/interfaces/flight.interface'; ...@@ -8,11 +8,13 @@ import { Flight } from 'src/app/supervisor/interfaces/flight.interface';
import { TicketTypeService } from '../../services/ticket-type.service'; import { TicketTypeService } from '../../services/ticket-type.service';
import { TicketClassService } from '../../services/ticket-class.service'; import { TicketClassService } from '../../services/ticket-class.service';
import { DropdownElement } from 'src/app/shared/interfaces/dropdown-element-interface'; import { DropdownElement } from 'src/app/shared/interfaces/dropdown-element-interface';
import { Reservation, ReservationStatusCode } from '../../interfaces/reservation.interface'; import { Reservation } from '../../interfaces/reservation.interface';
import { ReservationsService } from '../../services/reservations.service'; import { ReservationsService } from '../../services/reservations.service';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { FlightService } from 'src/app/supervisor/services/flight.service'; import { FlightService } from 'src/app/supervisor/services/flight.service';
import { SecurityService } from 'src/app/security/services/security.service';
import { ReservationSave } from '../../interfaces/reservation-save.interface';
@Component({ @Component({
selector: 'app-reservation-add', selector: 'app-reservation-add',
...@@ -52,7 +54,7 @@ export class ReservationAddComponent implements OnInit{ ...@@ -52,7 +54,7 @@ export class ReservationAddComponent implements OnInit{
title: 'Aerolinea' title: 'Aerolinea'
}, },
{ {
name: 'aircraftType', name: 'aircraft',
title: 'Tipo de avión' title: 'Tipo de avión'
}, },
{ {
...@@ -60,11 +62,11 @@ export class ReservationAddComponent implements OnInit{ ...@@ -60,11 +62,11 @@ export class ReservationAddComponent implements OnInit{
title: 'Tipo de vuelo' title: 'Tipo de vuelo'
}, },
{ {
name: 'dateStart', name: 'departureDate',
title: 'Hora de inicio' title: 'Hora de inicio'
}, },
{ {
name: 'dateEnd', name: 'arrivalDate',
title: 'Hora de llegada' title: 'Hora de llegada'
}, },
{ {
...@@ -82,33 +84,39 @@ export class ReservationAddComponent implements OnInit{ ...@@ -82,33 +84,39 @@ export class ReservationAddComponent implements OnInit{
}); });
public formFlightInformation: FormGroup = new FormGroup({ public formFlightInformation: FormGroup = new FormGroup({
airportOrigin: new FormControl<string | null>(null, [Validators.required]), airportOrigin: new FormControl<number | null>(null, [Validators.required]),
airportDestination: new FormControl<string | null>(null, [Validators.required]), airportDestination: new FormControl<number | null>(null, [Validators.required]),
date: new FormControl<string | null>(null, [Validators.required]) date: new FormControl<string | null>(null, [Validators.required])
}); });
public passengers: Passenger[] = [];
public ticketTypes: DropdownElement[] = [];
public flightClass: DropdownElement[] = [];
get passengerName(): string { get passengerName(): string {
const passengerId = this.formBaseInformation.get('passenger')?.value; if (this.formBaseInformation.value) {
const passenger = this.passengers.find(passenger => passenger.id === passengerId); const passenger = this.passengers.find(passenger => passenger.id == this.formBaseInformation.value.passenger);
return passenger ? passenger.name + ' ' + passenger.lastname: ''; return passenger ? `${passenger?.name} ${passenger?.lastname}` : "";
}
return "";
} }
get ticketTypeName(): string { get ticketTypeName(): string {
const ticketTypeId = this.formBaseInformation.get('ticketType')?.value; if (this.formBaseInformation.value) {
const ticketType = this.ticketTypes.find(ticketType => ticketType.value === ticketTypeId); const ticketType = this.ticketTypes.find(ticketType => ticketType.value == this.formBaseInformation.value.ticketType);
return ticketType ? ticketType.text : ''; return ticketType ? ticketType.text : "";
}
return "";
} }
get flightClassName(): string { get flightClassName(): string {
const flightClassId = this.formBaseInformation.get('flightClass')?.value; if (this.formBaseInformation.value) {
const flightClass = this.flightClass.find(flightClass => flightClass.value === flightClassId); const flightClass = this.flightClass.find(flightClass => flightClass.value == this.formBaseInformation.value.flightClass);
return flightClass ? flightClass.text : ''; return flightClass ? flightClass.text : "";
}
return "";
} }
public passengers: Passenger[] = [];
public ticketTypes: DropdownElement[] = [];
public flightClass: DropdownElement[] = [];
get isInvalidThisStep(): boolean { get isInvalidThisStep(): boolean {
if (this.stepIndex == 0) return this.formBaseInformation.invalid; if (this.stepIndex == 0) return this.formBaseInformation.invalid;
if (this.stepIndex == 1) return this.formFlightInformation.invalid || this.flightSelected === null; if (this.stepIndex == 1) return this.formFlightInformation.invalid || this.flightSelected === null;
...@@ -121,7 +129,8 @@ export class ReservationAddComponent implements OnInit{ ...@@ -121,7 +129,8 @@ export class ReservationAddComponent implements OnInit{
private reservationsService: ReservationsService, private reservationsService: ReservationsService,
private flightService: FlightService, private flightService: FlightService,
private location: Location, private location: Location,
private activatedRoute: ActivatedRoute) { } private activatedRoute: ActivatedRoute,
private securityService: SecurityService) { }
ngOnInit(): void { ngOnInit(): void {
this.activatedRoute.params this.activatedRoute.params
...@@ -130,14 +139,15 @@ export class ReservationAddComponent implements OnInit{ ...@@ -130,14 +139,15 @@ export class ReservationAddComponent implements OnInit{
this.reservationsService.getById(params['id']) this.reservationsService.getById(params['id'])
.subscribe(reservation => { .subscribe(reservation => {
this.formBaseInformation.get('passenger')?.setValue(reservation.passengerId); this.formBaseInformation.get('passenger')?.setValue(reservation.passengerId);
this.formBaseInformation.get('ticketType')?.setValue(reservation.travelClassCode.toString()); this.formBaseInformation.get('ticketType')?.setValue(reservation.ticketTypeId);
this.formBaseInformation.get('flightClass')?.setValue(reservation.ticketTypeCode.toString()); this.formBaseInformation.get('flightClass')?.setValue(reservation.travelClassId);
this.flightService.getById(reservation.flightId) this.formFlightInformation.get('airportOrigin')?.setValue(reservation.airportOriginId);
.subscribe(flight => { this.formFlightInformation.get('airportDestination')?.setValue(reservation.airportDestinationId);
this.flightSelected = flight; this.formFlightInformation.get('date')?.setValue(reservation.departureDate);
this.formFlightInformation.get('airportOrigin')?.setValue(flight.airportOrigin); this.flightService.searchFlight(reservation.airportOriginId, reservation.airportDestinationId, reservation.departureDate)
this.formFlightInformation.get('airportDestination')?.setValue(flight.airportDestination); .subscribe(flights => {
this.formFlightInformation.get('date')?.setValue(flight.dateStart); // this.flightResults = flights;
this.flightSelected = flights.find(flight => flight.id === reservation.flightId) || null;
}) })
}) })
} }
...@@ -152,14 +162,14 @@ export class ReservationAddComponent implements OnInit{ ...@@ -152,14 +162,14 @@ export class ReservationAddComponent implements OnInit{
this.ticketTypesService.getAll() this.ticketTypesService.getAll()
.subscribe(ticketTypes => { .subscribe(ticketTypes => {
ticketTypes.map(ticketType => { ticketTypes.map(ticketType => {
this.ticketTypes.push({ text: ticketType.name, value: ticketType.id.toString() }); this.ticketTypes.push({ text: ticketType.name, value: ticketType.id});
}); });
}); });
this.ticketClassService.getAll() this.ticketClassService.getAll()
.subscribe(flightClass => { .subscribe(flightClass => {
flightClass.map(flight => { flightClass.map(flight => {
this.flightClass.push({ text: flight.name, value: flight.id.toString() }); this.flightClass.push({ text: flight.name, value: flight.id });
}) })
}); });
} }
...@@ -198,19 +208,18 @@ export class ReservationAddComponent implements OnInit{ ...@@ -198,19 +208,18 @@ export class ReservationAddComponent implements OnInit{
} }
onSaveBooking(): void { onSaveBooking(): void {
const reservation: Reservation = { const reservation: ReservationSave = {
agentId: 1, agentId: this.securityService.currentUser?.id || 0,
passengerId: this.formBaseInformation.value.passenger, passengerId: this.formBaseInformation.value.passenger,
passengerName: this.passengerName, travelClassId: parseInt(this.formBaseInformation.value.ticketType),
travelClassCode: parseInt(this.formBaseInformation.value.ticketType), ticketTypeId: parseInt(this.formBaseInformation.value.flightClass),
travelClassName: this.ticketTypeName, reservationMade: this.formFlightInformation.value.date,
ticketTypeCode: parseInt(this.formBaseInformation.value.flightClass), flightId: this.flightSelected?.id || 0,
ticketTypeName: this.flightClassName, cost: this.flightSelected?.price || 0
statusCode: 'REGISTRADO',
dateReservationMade: new Date().toLocaleDateString(),
flightId: this.flightSelected?.id || 0
}; };
console.log(reservation);
this.reservationsService.save(reservation) this.reservationsService.save(reservation)
.subscribe(() => { .subscribe(() => {
this.formBaseInformation.reset(); this.formBaseInformation.reset();
......
.btn-add {
border: 1px solid #ccc;
color: #676a6c;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
width: 32px;
height: 32px;
box-shadow: 0 5px 5px -3px #0003, 0 8px 10px 1px #00000024, 0 3px 14px 2px #0000001f;
}
...@@ -3,12 +3,25 @@ ...@@ -3,12 +3,25 @@
title="Reservas" title="Reservas"
icon="bi-bookmarks-fill" icon="bi-bookmarks-fill"
message="Este gestor permite realizar reservas de vuelos"> message="Este gestor permite realizar reservas de vuelos">
<shared-table <shared-table-custom
[tableData]="tableData" [tableData]="tableData"
[tableModel]="tableModel" [tableModel]="tableModel"
(onReloadData)="getAll()" [tableAction]="actions">
(onDialogResult)="onDelete($event)" <div class="more-actions">
newRouter="new" <button [routerLink]="'new'" class="btn btn-add">
editRouter="edit"> <span class="bi bi-file-earmark"></span>
</shared-table> </button>
</div>
</shared-table-custom>
<shared-delete-dialog
*ngIf="openDeleteDialog"
(onDialogResult)="onHandlerResult($event)">
</shared-delete-dialog>
<shared-confirm-dialog
title="Cancelar reserva"
message="¿Esta seguro que desea cancelar la reserva?"
icon="bi-bookmark-x-fill"
*ngIf="openCancelDialog"
(onDialogResult)="onHandleCancel($event)">
</shared-confirm-dialog>
</shared-mail-box> </shared-mail-box>
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { TableModel } from 'src/app/shared/interfaces/table-model.interface'; import { TableModel } from 'src/app/shared/interfaces/table-model.interface';
import { BookingService } from '../../services/booking.service';
import { Booking } from '../../interfaces/booking.interface';
import { ResultDelete } from 'src/app/shared/interfaces/result-delete.interface'; import { ResultDelete } from 'src/app/shared/interfaces/result-delete.interface';
import { Reservation } from '../../interfaces/reservation.interface'; import { Reservation } from '../../interfaces/reservation.interface';
import { ReservationsService } from '../../services/reservations.service'; import { ReservationsService } from '../../services/reservations.service';
import { TableAction } from 'src/app/shared/interfaces/table-action.interface';
import { Router } from '@angular/router';
@Component({ @Component({
selector: 'app-reservations', selector: 'app-reservations',
...@@ -15,30 +15,57 @@ export class ReservationsComponent implements OnInit{ ...@@ -15,30 +15,57 @@ export class ReservationsComponent implements OnInit{
tableData: Reservation[] = []; tableData: Reservation[] = [];
openDeleteDialog: boolean = false;
openCancelDialog: boolean = false;
actions: TableAction[] = [
{
title: 'Editar',
icon: 'bi-pencil-square',
disabled: (item) => item.status === 'Pagado',
action: (item) => { this.router.navigate(['/agents/reservations/edit', item.id]); }
},
{
title: 'Eliminar',
icon: 'bi-trash',
disabled: (item) => item.status === 'Pagado',
action: (item) => { this.openDeleteDialog = true; this.reservationSelected = item; }
},
{
title: "Cancelar",
icon: "bi-x-circle",
disabled: (item) => item.status === 'Pagado' || item.status === 'Cancelado',
action: (item) => { this.openCancelDialog = true; this.reservationSelected = item; }
}
]
reservationSelected: Reservation | null = null;
tableModel: TableModel[] = [ tableModel: TableModel[] = [
{ {
name: 'id', name: 'id',
title: '#' title: '#'
}, },
{ {
name: 'passengerName', name: 'passenger',
title: 'Pasajero' title: 'Pasajero'
}, },
{ {
name: 'ticketTypeName', name: 'ticketType',
title: 'Tipo de Ticket' title: 'Tipo de ticket'
}, },
{ {
name: 'travelClassName', name: 'travelClass',
title: 'Clase' title: 'Clase de viaje'
}, },
{ {
name: 'statusCode', name: 'status',
title: 'Estado' title: 'Estado'
} }
]; ];
constructor(private reservationsService: ReservationsService) { } constructor(private reservationsService: ReservationsService,
private router: Router) { }
ngOnInit(): void { ngOnInit(): void {
this.getAll(); this.getAll();
...@@ -54,4 +81,20 @@ export class ReservationsComponent implements OnInit{ ...@@ -54,4 +81,20 @@ export class ReservationsComponent implements OnInit{
this.reservationsService.delete(result.id) this.reservationsService.delete(result.id)
.subscribe(() => this.getAll()); .subscribe(() => this.getAll());
} }
onHandlerResult(result: boolean): void {
if (result) {
this.reservationsService.delete(this.reservationSelected?.id!)
.subscribe(() => this.getAll());
}
this.openDeleteDialog = false;
}
onHandleCancel(result: boolean): void {
if (result) {
this.reservationsService.cancelReservation(this.reservationSelected?.id!)
.subscribe(() => this.getAll());
}
this.openCancelDialog = false;
}
} }
...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core'; ...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { Airport } from '../interfaces/airport.interface'; import { Airport } from '../interfaces/airport.interface';
import { headers } from 'src/app/shared/utils/header.util';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class AirportsService { export class AirportsService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
private BASE_URL: string = 'http://localhost:3000/airports'; private BASE_URL: string = 'http://localhost:8085/api/v1/airports';
getAll(): Observable<Airport[]> { getAll(): Observable<Airport[]> {
return this.http.get<Airport[]>(this.BASE_URL); return this.http.get<Airport[]>(this.BASE_URL, { headers });
} }
} }
...@@ -2,30 +2,31 @@ import { Injectable } from '@angular/core'; ...@@ -2,30 +2,31 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Passenger } from '../interfaces/passenger.interface'; import { Passenger } from '../interfaces/passenger.interface';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { headers } from 'src/app/shared/utils/header.util';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class PassengerService { export class PassengerService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
URL_BASE: string = 'http://localhost:3000/passengers'; URL_BASE: string = 'http://localhost:8085/api/v1/passengers';
getAll(): Observable<Passenger[]> { getAll(): Observable<Passenger[]> {
return this.http.get<Passenger[]>(this.URL_BASE); return this.http.get<Passenger[]>(this.URL_BASE, { headers });
} }
getById(id: number): Observable<Passenger> { getById(id: number): Observable<Passenger> {
return this.http.get<Passenger>(`${this.URL_BASE}/${id}`); return this.http.get<Passenger>(`${this.URL_BASE}/${id}`, { headers });
} }
save(passenger: Passenger): Observable<Passenger> { save(passenger: Passenger): Observable<Passenger> {
return this.http.post<Passenger>(this.URL_BASE, passenger); return this.http.post<Passenger>(this.URL_BASE, passenger, { headers });
} }
edit(id: number, passenger: Passenger): Observable<Passenger> { edit(id: number, passenger: Passenger): Observable<Passenger> {
return this.http.put<Passenger>(`${this.URL_BASE}/${id}`, passenger); return this.http.put<Passenger>(`${this.URL_BASE}/${id}`, passenger, { headers });
} }
delete(id: number): Observable<Passenger> { delete(id: number): Observable<Passenger> {
return this.http.delete<Passenger>(`${this.URL_BASE}/${id}`); return this.http.delete<Passenger>(`${this.URL_BASE}/${id}`, { headers });
} }
} }
...@@ -2,27 +2,38 @@ import { Injectable } from '@angular/core'; ...@@ -2,27 +2,38 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Reservation } from '../interfaces/reservation.interface'; import { Reservation } from '../interfaces/reservation.interface';
import { Observable, tap } from 'rxjs'; import { Observable, tap } from 'rxjs';
import { headers } from 'src/app/shared/utils/header.util';
import { ReservationSave } from '../interfaces/reservation-save.interface';
import { ReservationDetail } from 'src/app/passenger/interfaces/reservation-detail.interface';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class ReservationsService { export class ReservationsService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
URL_BASE: string = 'http://localhost:3000/reservations'; URL_BASE: string = 'http://localhost:8085/api/v1/reservations';
getAll(): Observable<Reservation[]> { getAll(): Observable<Reservation[]> {
return this.http.get<Reservation[]>(this.URL_BASE); return this.http.get<Reservation[]>(this.URL_BASE, { headers});
} }
getById(id: number): Observable<Reservation> { getById(id: number): Observable<Reservation> {
return this.http.get<Reservation>(`${this.URL_BASE}/${id}`); return this.http.get<Reservation>(`${this.URL_BASE}/${id}`, { headers });
} }
getByPassengerId(id: number): Observable<Reservation[]> { getByPassengerId(id: number): Observable<ReservationDetail[]> {
return this.http.get<Reservation[]>(`${this.URL_BASE}?passengerId=${id}`); return this.http.get<ReservationDetail[]>(`${this.URL_BASE}/passenger/${id}`, { headers });
} }
save(reservation: Reservation): Observable<Reservation> { payReservation(id: number): Observable<ReservationDetail> {
return this.http.post<Reservation>(this.URL_BASE, reservation); return this.http.put<ReservationDetail>(`${this.URL_BASE}/pay/${id}`, null, { headers });
}
cancelReservation(id: number): Observable<ReservationDetail> {
return this.http.put<ReservationDetail>(`${this.URL_BASE}/cancel/${id}`, null, { headers });
}
save(reservation: ReservationSave): Observable<Reservation> {
return this.http.post<Reservation>(this.URL_BASE, reservation, { headers });
} }
edit(id: number, reservation: Reservation): Observable<Reservation> { edit(id: number, reservation: Reservation): Observable<Reservation> {
...@@ -30,6 +41,6 @@ export class ReservationsService { ...@@ -30,6 +41,6 @@ export class ReservationsService {
} }
delete(id: number): Observable<Reservation> { delete(id: number): Observable<Reservation> {
return this.http.delete<Reservation>(`${this.URL_BASE}/${id}`); return this.http.delete<Reservation>(`${this.URL_BASE}/${id}`, { headers });
} }
} }
...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core'; ...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { FlightClass } from '../interfaces/flight-class.interface'; import { FlightClass } from '../interfaces/flight-class.interface';
import { headers } from 'src/app/shared/utils/header.util';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class TicketClassService { export class TicketClassService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
private BASE_URL: string = 'http://localhost:3000/ticketClasses'; private BASE_URL: string = 'http://localhost:8085/api/v1/travel-classes';
getAll(): Observable<FlightClass[]> { getAll(): Observable<FlightClass[]> {
return this.http.get<FlightClass[]>(this.BASE_URL); return this.http.get<FlightClass[]>(this.BASE_URL, { headers });
} }
} }
...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core'; ...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { TicketType } from '../interfaces/ticket-type.interface'; import { TicketType } from '../interfaces/ticket-type.interface';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { headers } from 'src/app/shared/utils/header.util';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class TicketTypeService { export class TicketTypeService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
private BASE_URL: string = 'http://localhost:3000/ticketTypes'; private BASE_URL: string = 'http://localhost:8085/api/v1/ticket-types';
getAll(): Observable<TicketType[]> { getAll(): Observable<TicketType[]> {
return this.http.get<TicketType[]>(this.BASE_URL); return this.http.get<TicketType[]>(this.BASE_URL, { headers });
} }
} }
import { FormGroup, FormControl, Validators } from "@angular/forms"; import { FormGroup, FormControl, Validators } from "@angular/forms";
const nameLenght = { min: 3, max: 20 }; const nameLenght = { min: 3, max: 20 };
const secondNameLenght = { min: 0, max: 20 };
const lastnameLenght = { min: 3, max: 30 }; const lastnameLenght = { min: 3, max: 30 };
const countryLenght = { min: 3, max: 30 }; const countryLenght = { min: 3, max: 30 };
const cityLenght = { min: 3, max: 30 }; const cityLenght = { min: 3, max: 30 };
...@@ -12,7 +11,6 @@ const passwordLenght = { min: 3, max: 45 }; ...@@ -12,7 +11,6 @@ const passwordLenght = { min: 3, max: 45 };
export const PASSENGER_VALIDATORS = new FormGroup({ export const PASSENGER_VALIDATORS = new FormGroup({
name: new FormControl('', [Validators.required, Validators.minLength(nameLenght.min), Validators.maxLength(nameLenght.max)]), name: new FormControl('', [Validators.required, Validators.minLength(nameLenght.min), Validators.maxLength(nameLenght.max)]),
secondName: new FormControl('', [Validators.maxLength(secondNameLenght.max)]),
lastname: new FormControl('', [Validators.required, Validators.minLength(lastnameLenght.min), Validators.maxLength(lastnameLenght.max)]), lastname: new FormControl('', [Validators.required, Validators.minLength(lastnameLenght.min), Validators.maxLength(lastnameLenght.max)]),
country: new FormControl('', [Validators.required, Validators.minLength(countryLenght.min), Validators.maxLength(countryLenght.max)]), country: new FormControl('', [Validators.required, Validators.minLength(countryLenght.min), Validators.maxLength(countryLenght.max)]),
city: new FormControl('', [Validators.required, Validators.minLength(cityLenght.min), Validators.maxLength(cityLenght.max)]), city: new FormControl('', [Validators.required, Validators.minLength(cityLenght.min), Validators.maxLength(cityLenght.max)]),
...@@ -26,8 +24,6 @@ export const getPassengerValidatorLenght = (field: string) => { ...@@ -26,8 +24,6 @@ export const getPassengerValidatorLenght = (field: string) => {
switch (field) { switch (field) {
case 'name': case 'name':
return nameLenght; return nameLenght;
case 'secondName':
return secondNameLenght;
case 'lastname': case 'lastname':
return lastnameLenght; return lastnameLenght;
case 'country': case 'country':
......
import { ReservationStatusCode } from "src/app/agent/interfaces/reservation.interface";
export interface ReservationDetail { export interface ReservationDetail {
id: number; id: number;
origin: string; aiportOrigin: string;
destination: string; airportDestination: string;
date: string; reservationMade: string;
status: ReservationStatusCode; arrivalDate: string;
status: string;
cost: number; cost: number;
} }
...@@ -68,3 +68,15 @@ input:focus + label { ...@@ -68,3 +68,15 @@ input:focus + label {
color: white; color: white;
font-size: 12px; font-size: 12px;
} }
.btn-add {
border: 1px solid #ccc;
color: #676a6c;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
width: 32px;
height: 32px;
box-shadow: 0 5px 5px -3px #0003, 0 8px 10px 1px #00000024, 0 3px 14px 2px #0000001f;
}
...@@ -11,6 +11,16 @@ ...@@ -11,6 +11,16 @@
[onClickItem]="onClickItem"> [onClickItem]="onClickItem">
</shared-table-custom> </shared-table-custom>
<shared-delete-dialog
*ngIf="openDialogDelete"
(onDialogResult)="onDeleteItem($event)">
</shared-delete-dialog>
<shared-confirm-dialog
*ngIf="openDialogCancel"
(onDialogResult)="onCancelItem($event)">
</shared-confirm-dialog>
<shared-dialog <shared-dialog
(onCloseDialog)="onTogleDialogPay()" (onCloseDialog)="onTogleDialogPay()"
[isActivated]="openDialogPay" [isActivated]="openDialogPay"
...@@ -50,7 +60,7 @@ ...@@ -50,7 +60,7 @@
</shared-input-text> </shared-input-text>
</div> </div>
<div class="pay_actions"> <div class="pay_actions">
<button (click)="onTogleDialogPay()" class="btn btn-back"> <button (click)="onSave()" class="btn btn-back">
Cancelar Cancelar
</button> </button>
<button [disabled]="formGroup.invalid" class="btn btn-pay" (click)="onSave()"> <button [disabled]="formGroup.invalid" class="btn btn-pay" (click)="onSave()">
......
...@@ -5,8 +5,7 @@ import { TableAction } from 'src/app/shared/interfaces/table-action.interface'; ...@@ -5,8 +5,7 @@ import { TableAction } from 'src/app/shared/interfaces/table-action.interface';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { FormControl, FormGroup, Validators } from '@angular/forms'; import { FormControl, FormGroup, Validators } from '@angular/forms';
import { ReservationsService } from 'src/app/agent/services/reservations.service'; import { ReservationsService } from 'src/app/agent/services/reservations.service';
import { FlightService } from 'src/app/supervisor/services/flight.service'; import { SecurityService } from 'src/app/security/services/security.service';
import { Reservation } from 'src/app/agent/interfaces/reservation.interface';
@Component({ @Component({
selector: 'passenger-my-reservations', selector: 'passenger-my-reservations',
...@@ -19,22 +18,41 @@ export class MyReservationsComponent implements OnInit { ...@@ -19,22 +18,41 @@ export class MyReservationsComponent implements OnInit {
{ {
title: 'Editar', title: 'Editar',
icon: 'bi-pencil-square', icon: 'bi-pencil-square',
action: (item) => { console.log(item); } disabled: (_) => true,
action: (_) => { }
}, },
{ {
title: 'Eliminar', title: 'Eliminar',
icon: 'bi-trash', icon: 'bi-trash',
action: (item) => { console.log(item); } disabled: (_) => true,
action: (item) => { this.openDialogDelete = !this.openDialogDelete; this.reservationSelected = item; }
},
{
title: "Cancelar",
icon: "bi-x-circle",
disabled: (item) => item.status === 'Pagado' || item.status === 'Cancelado',
action: (item) => { this.openDialogCancel = true; this.reservationSelected = item }
}, },
{ {
title: "Pagar", title: "Pagar",
icon: "bi-cash", icon: "bi-cash",
disabled: (item) => item.status === 'Pagado' || item.status === 'Cancelado',
action: (item) => { this.onTogleDialogPay(); this.reservationSelected = item; } action: (item) => { this.onTogleDialogPay(); this.reservationSelected = item; }
} }
]; ];
public cancelReservation(item: any): void {
this.reservationService.cancelReservation(item.id)
.subscribe( _ => {
this.getAll();
})
}
public reservationSelected: ReservationDetail | null = null; public reservationSelected: ReservationDetail | null = null;
public reservation: Reservation | null = null; public reservation: ReservationDetail | null = null;
public openDialogDelete: boolean = false;
public openDialogCancel: boolean = false;
public tableModel: TableModel[] = [ public tableModel: TableModel[] = [
{ {
...@@ -42,15 +60,15 @@ export class MyReservationsComponent implements OnInit { ...@@ -42,15 +60,15 @@ export class MyReservationsComponent implements OnInit {
title: '#', title: '#',
}, },
{ {
name: 'origin', name: 'airportOrigin',
title: 'Origen', title: 'Origen',
}, },
{ {
name: 'destination', name: 'airportDestination',
title: 'Destino', title: 'Destino',
}, },
{ {
name: 'date', name: 'reservationMade',
title: 'Fecha', title: 'Fecha',
}, },
{ {
...@@ -59,7 +77,7 @@ export class MyReservationsComponent implements OnInit { ...@@ -59,7 +77,7 @@ export class MyReservationsComponent implements OnInit {
}, },
{ {
name: 'cost', name: 'cost',
title: 'Costo', title: 'Costo (USD)',
} }
] ]
public tableData: ReservationDetail[] = []; public tableData: ReservationDetail[] = [];
...@@ -77,14 +95,13 @@ export class MyReservationsComponent implements OnInit { ...@@ -77,14 +95,13 @@ export class MyReservationsComponent implements OnInit {
}); });
onSave(): void { onSave(): void {
if (this.formGroup.valid && this.reservation && this.reservationSelected) { if (this.formGroup.valid && this.reservationSelected) {
this.reservation.statusCode = 'PROCESANDO_PAGO'; this.reservationService.payReservation(this.reservationSelected.id)
this.reservationSelected.status = 'PROCESANDO_PAGO'; .subscribe( reservation => {
this.reservationService.edit(this.reservationSelected!.id, this.reservation) this.tableData = this.tableData.map(item => item.id === reservation.id ? reservation : item);
.subscribe(() => {
this.formGroup.reset(); this.formGroup.reset();
this.onTogleDialogPay(); this.onTogleDialogPay();
}); })
} }
} }
...@@ -92,26 +109,17 @@ export class MyReservationsComponent implements OnInit { ...@@ -92,26 +109,17 @@ export class MyReservationsComponent implements OnInit {
constructor(private router: Router, constructor(private router: Router,
private reservationService: ReservationsService, private reservationService: ReservationsService,
private flightService: FlightService) {} private securityService: SecurityService) {}
ngOnInit(): void { ngOnInit(): void {
this.reservationService.getByPassengerId(4) this.getAll();
}
getAll(): void {
const id = this.securityService.currentUser?.id!;
this.reservationService.getByPassengerId(id)
.subscribe(response => { .subscribe(response => {
response.forEach(reservation => { this.tableData = response;
this.reservation = reservation;
this.flightService.getById(reservation.flightId)
.subscribe((flight) => {
const reservationDetail: ReservationDetail = {
id: reservation.id!,
origin: flight.airportOrigin,
destination: flight.airportDestination,
date: reservation.dateReservationMade,
status: reservation.statusCode,
cost: flight.costs[0].cost
}
this.tableData.push(reservationDetail);
})
})
}) })
} }
...@@ -122,4 +130,21 @@ export class MyReservationsComponent implements OnInit { ...@@ -122,4 +130,21 @@ export class MyReservationsComponent implements OnInit {
onTogleDialogPay(): void { onTogleDialogPay(): void {
this.openDialogPay = !this.openDialogPay; this.openDialogPay = !this.openDialogPay;
} }
onDeleteItem(result: boolean): void {
if (result) {
console.log(this.reservationSelected?.id!);
// this.reservationService.delete(this.reservationSelected?.id!)
// .subscribe(() => {
// this.tableData = this.tableData.filter(item => item.id !== this.reservationSelected?.id!);
// this.openDialogDelete = false;
// })
} this.openDialogDelete = false;
}
onCancelItem(result: boolean): void {
if (result) {
this.cancelReservation(this.reservationSelected?.id!);
} this.openDialogCancel = false;
}
} }
// To parse this data:
//
// import { Convert, AgentAuthorize } from "./file";
//
// const agentAuthorize = Convert.toAgentAuthorize(json);
//
// These functions will throw an error if the JSON doesn't
// match the expected interface, even if the JSON is valid.
export interface AgentAuthorize {
name: string;
lastname: string;
detail: string;
email: string;
password: string;
userId: number;
id: number;
user: User;
}
export interface User {
id: number;
email: string;
password: string;
role: string;
}
// Converts JSON strings to/from your types
// and asserts the results of JSON.parse at runtime
export class Convert {
public static toAgentAuthorize(json: string): AgentAuthorize {
return cast(JSON.parse(json), r("AgentAuthorize"));
}
public static agentAuthorizeToJson(value: AgentAuthorize): string {
return JSON.stringify(uncast(value, r("AgentAuthorize")), null, 2);
}
}
function invalidValue(typ: any, val: any, key: any, parent: any = ''): never {
const prettyTyp = prettyTypeName(typ);
const parentText = parent ? ` on ${parent}` : '';
const keyText = key ? ` for key "${key}"` : '';
throw Error(`Invalid value${keyText}${parentText}. Expected ${prettyTyp} but got ${JSON.stringify(val)}`);
}
function prettyTypeName(typ: any): string {
if (Array.isArray(typ)) {
if (typ.length === 2 && typ[0] === undefined) {
return `an optional ${prettyTypeName(typ[1])}`;
} else {
return `one of [${typ.map(a => { return prettyTypeName(a); }).join(", ")}]`;
}
} else if (typeof typ === "object" && typ.literal !== undefined) {
return typ.literal;
} else {
return typeof typ;
}
}
function jsonToJSProps(typ: any): any {
if (typ.jsonToJS === undefined) {
const map: any = {};
typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ });
typ.jsonToJS = map;
}
return typ.jsonToJS;
}
function jsToJSONProps(typ: any): any {
if (typ.jsToJSON === undefined) {
const map: any = {};
typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ });
typ.jsToJSON = map;
}
return typ.jsToJSON;
}
function transform(val: any, typ: any, getProps: any, key: any = '', parent: any = ''): any {
function transformPrimitive(typ: string, val: any): any {
if (typeof typ === typeof val) return val;
return invalidValue(typ, val, key, parent);
}
function transformUnion(typs: any[], val: any): any {
// val must validate against one typ in typs
const l = typs.length;
for (let i = 0; i < l; i++) {
const typ = typs[i];
try {
return transform(val, typ, getProps);
} catch (_) {}
}
return invalidValue(typs, val, key, parent);
}
function transformEnum(cases: string[], val: any): any {
if (cases.indexOf(val) !== -1) return val;
return invalidValue(cases.map(a => { return l(a); }), val, key, parent);
}
function transformArray(typ: any, val: any): any {
// val must be an array with no invalid elements
if (!Array.isArray(val)) return invalidValue(l("array"), val, key, parent);
return val.map(el => transform(el, typ, getProps));
}
function transformDate(val: any): any {
if (val === null) {
return null;
}
const d = new Date(val);
if (isNaN(d.valueOf())) {
return invalidValue(l("Date"), val, key, parent);
}
return d;
}
function transformObject(props: { [k: string]: any }, additional: any, val: any): any {
if (val === null || typeof val !== "object" || Array.isArray(val)) {
return invalidValue(l(ref || "object"), val, key, parent);
}
const result: any = {};
Object.getOwnPropertyNames(props).forEach(key => {
const prop = props[key];
const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined;
result[prop.key] = transform(v, prop.typ, getProps, key, ref);
});
Object.getOwnPropertyNames(val).forEach(key => {
if (!Object.prototype.hasOwnProperty.call(props, key)) {
result[key] = transform(val[key], additional, getProps, key, ref);
}
});
return result;
}
if (typ === "any") return val;
if (typ === null) {
if (val === null) return val;
return invalidValue(typ, val, key, parent);
}
if (typ === false) return invalidValue(typ, val, key, parent);
let ref: any = undefined;
while (typeof typ === "object" && typ.ref !== undefined) {
ref = typ.ref;
typ = typeMap[typ.ref];
}
if (Array.isArray(typ)) return transformEnum(typ, val);
if (typeof typ === "object") {
return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val)
: typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val)
: typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val)
: invalidValue(typ, val, key, parent);
}
// Numbers can be parsed by Date but shouldn't be.
if (typ === Date && typeof val !== "number") return transformDate(val);
return transformPrimitive(typ, val);
}
function cast<T>(val: any, typ: any): T {
return transform(val, typ, jsonToJSProps);
}
function uncast<T>(val: T, typ: any): any {
return transform(val, typ, jsToJSONProps);
}
function l(typ: any) {
return { literal: typ };
}
function a(typ: any) {
return { arrayItems: typ };
}
function u(...typs: any[]) {
return { unionMembers: typs };
}
function o(props: any[], additional: any) {
return { props, additional };
}
function m(additional: any) {
return { props: [], additional };
}
function r(name: string) {
return { ref: name };
}
const typeMap: any = {
"AgentAuthorize": o([
{ json: "name", js: "name", typ: "" },
{ json: "lastname", js: "lastname", typ: "" },
{ json: "detail", js: "detail", typ: "" },
{ json: "email", js: "email", typ: "" },
{ json: "password", js: "password", typ: "" },
{ json: "userId", js: "userId", typ: 0 },
{ json: "id", js: "id", typ: 0 },
{ json: "user", js: "user", typ: r("User") },
], false),
"User": o([
{ json: "id", js: "id", typ: 0 },
{ json: "email", js: "email", typ: "" },
{ json: "password", js: "password", typ: "" },
{ json: "role", js: "role", typ: "" },
], false),
};
// To parse this data:
//
// import { Convert, PassengerAuthorize } from "./file";
//
// const passengerAuthorize = Convert.toPassengerAuthorize(json);
//
// These functions will throw an error if the JSON doesn't
// match the expected interface, even if the JSON is valid.
export interface PassengerAuthorize {
name: string;
secondName: string;
lastname: string;
country: string;
city: string;
address: string;
phone: string;
email: string;
password: string;
userId: number;
id: number;
user: User;
}
export interface User {
id: number;
email: string;
password: string;
role: string;
}
// Converts JSON strings to/from your types
// and asserts the results of JSON.parse at runtime
export class Convert {
public static toPassengerAuthorize(json: string): PassengerAuthorize {
return cast(JSON.parse(json), r("PassengerAuthorize"));
}
public static passengerAuthorizeToJson(value: PassengerAuthorize): string {
return JSON.stringify(uncast(value, r("PassengerAuthorize")), null, 2);
}
}
function invalidValue(typ: any, val: any, key: any, parent: any = ''): never {
const prettyTyp = prettyTypeName(typ);
const parentText = parent ? ` on ${parent}` : '';
const keyText = key ? ` for key "${key}"` : '';
throw Error(`Invalid value${keyText}${parentText}. Expected ${prettyTyp} but got ${JSON.stringify(val)}`);
}
function prettyTypeName(typ: any): string {
if (Array.isArray(typ)) {
if (typ.length === 2 && typ[0] === undefined) {
return `an optional ${prettyTypeName(typ[1])}`;
} else {
return `one of [${typ.map(a => { return prettyTypeName(a); }).join(", ")}]`;
}
} else if (typeof typ === "object" && typ.literal !== undefined) {
return typ.literal;
} else {
return typeof typ;
}
}
function jsonToJSProps(typ: any): any {
if (typ.jsonToJS === undefined) {
const map: any = {};
typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ });
typ.jsonToJS = map;
}
return typ.jsonToJS;
}
function jsToJSONProps(typ: any): any {
if (typ.jsToJSON === undefined) {
const map: any = {};
typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ });
typ.jsToJSON = map;
}
return typ.jsToJSON;
}
function transform(val: any, typ: any, getProps: any, key: any = '', parent: any = ''): any {
function transformPrimitive(typ: string, val: any): any {
if (typeof typ === typeof val) return val;
return invalidValue(typ, val, key, parent);
}
function transformUnion(typs: any[], val: any): any {
// val must validate against one typ in typs
const l = typs.length;
for (let i = 0; i < l; i++) {
const typ = typs[i];
try {
return transform(val, typ, getProps);
} catch (_) {}
}
return invalidValue(typs, val, key, parent);
}
function transformEnum(cases: string[], val: any): any {
if (cases.indexOf(val) !== -1) return val;
return invalidValue(cases.map(a => { return l(a); }), val, key, parent);
}
function transformArray(typ: any, val: any): any {
// val must be an array with no invalid elements
if (!Array.isArray(val)) return invalidValue(l("array"), val, key, parent);
return val.map(el => transform(el, typ, getProps));
}
function transformDate(val: any): any {
if (val === null) {
return null;
}
const d = new Date(val);
if (isNaN(d.valueOf())) {
return invalidValue(l("Date"), val, key, parent);
}
return d;
}
function transformObject(props: { [k: string]: any }, additional: any, val: any): any {
if (val === null || typeof val !== "object" || Array.isArray(val)) {
return invalidValue(l(ref || "object"), val, key, parent);
}
const result: any = {};
Object.getOwnPropertyNames(props).forEach(key => {
const prop = props[key];
const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined;
result[prop.key] = transform(v, prop.typ, getProps, key, ref);
});
Object.getOwnPropertyNames(val).forEach(key => {
if (!Object.prototype.hasOwnProperty.call(props, key)) {
result[key] = transform(val[key], additional, getProps, key, ref);
}
});
return result;
}
if (typ === "any") return val;
if (typ === null) {
if (val === null) return val;
return invalidValue(typ, val, key, parent);
}
if (typ === false) return invalidValue(typ, val, key, parent);
let ref: any = undefined;
while (typeof typ === "object" && typ.ref !== undefined) {
ref = typ.ref;
typ = typeMap[typ.ref];
}
if (Array.isArray(typ)) return transformEnum(typ, val);
if (typeof typ === "object") {
return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val)
: typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val)
: typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val)
: invalidValue(typ, val, key, parent);
}
// Numbers can be parsed by Date but shouldn't be.
if (typ === Date && typeof val !== "number") return transformDate(val);
return transformPrimitive(typ, val);
}
function cast<T>(val: any, typ: any): T {
return transform(val, typ, jsonToJSProps);
}
function uncast<T>(val: T, typ: any): any {
return transform(val, typ, jsToJSONProps);
}
function l(typ: any) {
return { literal: typ };
}
function a(typ: any) {
return { arrayItems: typ };
}
function u(...typs: any[]) {
return { unionMembers: typs };
}
function o(props: any[], additional: any) {
return { props, additional };
}
function m(additional: any) {
return { props: [], additional };
}
function r(name: string) {
return { ref: name };
}
const typeMap: any = {
"PassengerAuthorize": o([
{ json: "name", js: "name", typ: "" },
{ json: "secondName", js: "secondName", typ: "" },
{ json: "lastname", js: "lastname", typ: "" },
{ json: "country", js: "country", typ: "" },
{ json: "city", js: "city", typ: "" },
{ json: "address", js: "address", typ: "" },
{ json: "phone", js: "phone", typ: "" },
{ json: "email", js: "email", typ: "" },
{ json: "password", js: "password", typ: "" },
{ json: "userId", js: "userId", typ: 0 },
{ json: "id", js: "id", typ: 0 },
{ json: "user", js: "user", typ: r("User") },
], false),
"User": o([
{ json: "id", js: "id", typ: 0 },
{ json: "email", js: "email", typ: "" },
{ json: "password", js: "password", typ: "" },
{ json: "role", js: "role", typ: "" },
], false),
};
export interface SecurityResponse { export interface SecurityResponse {
accessToken: string;
user: User;
}
interface User {
id: number; id: number;
name: string;
lastname: string;
email: string; email: string;
role: string; role: string;
} }
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment