[main] Prod Creds
All checks were successful
Build, Push, and Deploy to Nomad / docker-nomad (push) Successful in 1m10s

This commit is contained in:
Henrik Jess
2025-01-14 19:51:29 +01:00
parent 5de92fa7a1
commit e1207362de
4 changed files with 630 additions and 18 deletions

View File

@@ -0,0 +1,95 @@
import json
from datetime import datetime
from amadeus import Client, ResponseError
from pprint import pprint
# OopCompanion:suppressRename
class AmadeusClient:
def __init__(self, client_id: str, client_secret: str):
"""
Initialize the Amadeus API client.
"""
self.client = Client(
client_id = client_id,
client_secret = client_secret
)
def find_cheapest_flights(self, origin: str, destination: str, departure_date: str, adults: int = 1):
"""
Find the cheapest flights from the origin to the destination on a specific date.
:param origin: The IATA code for the origin location.
:param destination: The IATA code for the destination location.
:param departure_date: The date of departure in YYYY-MM-DD format.
:param adults: Number of adult passengers.
:return: Flight offers data.
"""
try:
response = self.client.shopping.flight_offers_search.get(
originLocationCode = origin,
destinationLocationCode = destination,
departureDate = departure_date,
adults = adults,
max=250,
nonStop="true"
)
return response.data
except ResponseError as error:
raise error
# Example usage
if __name__ == "__main__":
client_id = 'uxDqIh36xPAUvpXnXynwAnH86pGBdIch'
client_secret = 'xTSLooNZpJWantb5'
amadeus_client = AmadeusClient( client_id, client_secret )
try:
#flights = amadeus_client.find_cheapest_flights(
# origin = 'LIS',
# destination = 'CPH',
# departure_date = '2025-01-15',
# adults = 1,
#)
#pprint( flights )
#with open( "flights.json", "w" ) as file:
# json.dump( flights, file, indent = 4 )
with open( "flights.json", "r" ) as file:
flights = json.load( file )
for flight_offer in flights:
itineraries = flight_offer.get( 'itineraries', [] )
result = []
price = flight_offer.get( 'price', { } ).get( 'total', 0 )
for itinerary in itineraries:
segments = itinerary.get( 'segments', [] )
for segment in segments:
numberOfStops = segment.get( 'numberOfStops', -1 )
if numberOfStops == 0:
departure = segment.get( 'departure', { } )
arrival = segment.get( 'arrival', { } )
travel_time = datetime.fromisoformat( str(arrival['at']) ) - datetime.fromisoformat( str(departure['at']) )
result.append( {
"departure": {
"iataCode": departure.get( "iataCode" ),
"at": departure.get( "at" ),
},
"arrival": {
"iataCode": arrival.get( "iataCode" ),
"at": arrival.get( "at" ),
}
,
"travel_time": {
"time":travel_time,
}
} )
pprint( result )
except ResponseError as error:
print( f"An error occurred: {error}" )

View File

@@ -7,7 +7,8 @@ from flight_types import *
class FlightFilter:
def __init__(self, api_key, api_secret):
self.amadeus = Client(client_id=api_key, client_secret=api_secret, hostname="production")
#self.amadeus = Client(client_id=api_key, client_secret=api_secret, hostname="production")
self.amadeus = Client( client_id = api_key, client_secret = api_secret )
def get_flight_offers(self, request_body):
"""
@@ -119,12 +120,12 @@ class FlightFilter:
# Usage example
if __name__ == "__main__":
#api_key = "uxDqIh36xPAUvpXnXynwAnH86pGBdIch"
#api_secret = "xTSLooNZpJWantb5"
api_key = "uxDqIh36xPAUvpXnXynwAnH86pGBdIch"
api_secret = "xTSLooNZpJWantb5"
# PROD PROD PROD PROD PROD PROD PROD PROD PROD PROD
api_key = "ABRGQv6U7IWAYxwwmjqAOPUDGvuFMSjw"
api_secret = "BcwpSKf3FICJIxaw"
#api_key = "ABRGQv6U7IWAYxwwmjqAOPUDGvuFMSjw"
#api_secret = "BcwpSKf3FICJIxaw"
flight_filter = FlightFilter(api_key, api_secret)
@@ -146,7 +147,7 @@ if __name__ == "__main__":
"originLocationCode": "CPH",
"destinationLocationCode": "OPO",
"departureDateTimeRange": {
"date": "2025-03-06",
"date": "2025-03-03",
"time": "20:30:00"
}
}
@@ -155,21 +156,15 @@ if __name__ == "__main__":
{"id": "1", "travelerType": "ADULT"}
],
"sources": ["GDS"],
"searchCriteria": {
"excludeAllotments": True,
"addOneWayOffers": True,
"maxFlightOffers": 50,
"allowAlternativeFareOptions": True,
}
}
# Fetch flights
flights = flight_filter.get_flight_offers(request_body)
with open("json_data.json", "w") as file:
json.dump(flights, file)
#with open("json_data.json", "w") as file:
# json.dump(flights, file)
#
#DEBUG
#with open("json_data.json", "r") as file:
# with open("json_data.json", "r") as file:
# flights = json.load(file)
#print(f"Raw flights data: {flights}")
@@ -187,7 +182,7 @@ if __name__ == "__main__":
arrival = seg.get("arrival").get("iataCode")
print(f"{departure} -> {arrival}")
if (departure, arrival) in (("OPO", "CPH"), ("CPH", "OPO")):
print( f"{departure} -> {arrival}" )
print( f"-->> {departure} -> {arrival} <<--" )

View File

@@ -0,0 +1,522 @@
[
{
"type": "flight-offer",
"id": "1",
"source": "GDS",
"instantTicketingRequired": false,
"nonHomogeneous": false,
"oneWay": false,
"isUpsellOffer": false,
"lastTicketingDate": "2025-01-15",
"lastTicketingDateTime": "2025-01-15",
"numberOfBookableSeats": 9,
"itineraries": [
{
"duration": "PT3H45M",
"segments": [
{
"departure": {
"iataCode": "LIS",
"terminal": "1",
"at": "2025-01-15T07:05:00"
},
"arrival": {
"iataCode": "CPH",
"terminal": "3",
"at": "2025-01-15T11:50:00"
},
"carrierCode": "TP",
"number": "752",
"aircraft": {
"code": "320"
},
"operating": {
"carrierCode": "TP"
},
"duration": "PT3H45M",
"id": "1",
"numberOfStops": 0,
"blacklistedInEU": false
}
]
}
],
"price": {
"currency": "EUR",
"total": "116.62",
"base": "70.00",
"fees": [
{
"amount": "0.00",
"type": "SUPPLIER"
},
{
"amount": "0.00",
"type": "TICKETING"
}
],
"grandTotal": "116.62",
"additionalServices": [
{
"amount": "65.00",
"type": "CHECKED_BAGS"
}
]
},
"pricingOptions": {
"fareType": [
"PUBLISHED"
],
"includedCheckedBagsOnly": false
},
"validatingAirlineCodes": [
"TP"
],
"travelerPricings": [
{
"travelerId": "1",
"fareOption": "STANDARD",
"travelerType": "ADULT",
"price": {
"currency": "EUR",
"total": "116.62",
"base": "70.00"
},
"fareDetailsBySegment": [
{
"segmentId": "1",
"cabin": "ECONOMY",
"fareBasis": "EF0DSC04",
"brandedFare": "DISCOUNT",
"brandedFareLabel": "DISCOUNT",
"class": "E",
"includedCheckedBags": {
"quantity": 0
},
"amenities": [
{
"description": "FIRST BAG UP TO 23KG AND 158CM",
"isChargeable": true,
"amenityType": "BAGGAGE",
"amenityProvider": {
"name": "BrandedFare"
}
},
{
"description": "SECOND BAG UP TO 23KG AND158CM",
"isChargeable": true,
"amenityType": "BAGGAGE",
"amenityProvider": {
"name": "BrandedFare"
}
},
{
"description": "EXTRA LEG ROOM OR FRONT SEAT",
"isChargeable": true,
"amenityType": "PRE_RESERVED_SEAT",
"amenityProvider": {
"name": "BrandedFare"
}
},
{
"description": "SEAT RESERVATION",
"isChargeable": true,
"amenityType": "PRE_RESERVED_SEAT",
"amenityProvider": {
"name": "BrandedFare"
}
}
]
}
]
}
]
},
{
"type": "flight-offer",
"id": "2",
"source": "GDS",
"instantTicketingRequired": false,
"nonHomogeneous": false,
"oneWay": false,
"isUpsellOffer": false,
"lastTicketingDate": "2025-01-15",
"lastTicketingDateTime": "2025-01-15",
"numberOfBookableSeats": 9,
"itineraries": [
{
"duration": "PT3H45M",
"segments": [
{
"departure": {
"iataCode": "LIS",
"terminal": "1",
"at": "2025-01-15T19:00:00"
},
"arrival": {
"iataCode": "CPH",
"terminal": "3",
"at": "2025-01-15T23:45:00"
},
"carrierCode": "TP",
"number": "756",
"aircraft": {
"code": "320"
},
"operating": {
"carrierCode": "TP"
},
"duration": "PT3H45M",
"id": "3",
"numberOfStops": 0,
"blacklistedInEU": false
}
]
}
],
"price": {
"currency": "EUR",
"total": "116.62",
"base": "70.00",
"fees": [
{
"amount": "0.00",
"type": "SUPPLIER"
},
{
"amount": "0.00",
"type": "TICKETING"
}
],
"grandTotal": "116.62",
"additionalServices": [
{
"amount": "65.00",
"type": "CHECKED_BAGS"
}
]
},
"pricingOptions": {
"fareType": [
"PUBLISHED"
],
"includedCheckedBagsOnly": false
},
"validatingAirlineCodes": [
"TP"
],
"travelerPricings": [
{
"travelerId": "1",
"fareOption": "STANDARD",
"travelerType": "ADULT",
"price": {
"currency": "EUR",
"total": "116.62",
"base": "70.00"
},
"fareDetailsBySegment": [
{
"segmentId": "3",
"cabin": "ECONOMY",
"fareBasis": "EF0DSC04",
"brandedFare": "DISCOUNT",
"brandedFareLabel": "DISCOUNT",
"class": "E",
"includedCheckedBags": {
"quantity": 0
},
"amenities": [
{
"description": "FIRST BAG UP TO 23KG AND 158CM",
"isChargeable": true,
"amenityType": "BAGGAGE",
"amenityProvider": {
"name": "BrandedFare"
}
},
{
"description": "SECOND BAG UP TO 23KG AND158CM",
"isChargeable": true,
"amenityType": "BAGGAGE",
"amenityProvider": {
"name": "BrandedFare"
}
},
{
"description": "EXTRA LEG ROOM OR FRONT SEAT",
"isChargeable": true,
"amenityType": "PRE_RESERVED_SEAT",
"amenityProvider": {
"name": "BrandedFare"
}
},
{
"description": "SEAT RESERVATION",
"isChargeable": true,
"amenityType": "PRE_RESERVED_SEAT",
"amenityProvider": {
"name": "BrandedFare"
}
}
]
}
]
}
]
},
{
"type": "flight-offer",
"id": "3",
"source": "GDS",
"instantTicketingRequired": false,
"nonHomogeneous": false,
"oneWay": false,
"isUpsellOffer": false,
"lastTicketingDate": "2025-01-14",
"lastTicketingDateTime": "2025-01-14",
"numberOfBookableSeats": 7,
"itineraries": [
{
"duration": "PT3H45M",
"segments": [
{
"departure": {
"iataCode": "LIS",
"terminal": "1",
"at": "2025-01-15T07:05:00"
},
"arrival": {
"iataCode": "CPH",
"terminal": "3",
"at": "2025-01-15T11:50:00"
},
"carrierCode": "SK",
"number": "8904",
"aircraft": {
"code": "320"
},
"operating": {
"carrierCode": "TP"
},
"duration": "PT3H45M",
"id": "2",
"numberOfStops": 0,
"blacklistedInEU": false
}
]
}
],
"price": {
"currency": "EUR",
"total": "141.12",
"base": "85.00",
"fees": [
{
"amount": "0.00",
"type": "SUPPLIER"
},
{
"amount": "0.00",
"type": "TICKETING"
}
],
"grandTotal": "141.12"
},
"pricingOptions": {
"fareType": [
"PUBLISHED"
],
"includedCheckedBagsOnly": true
},
"validatingAirlineCodes": [
"SK"
],
"travelerPricings": [
{
"travelerId": "1",
"fareOption": "STANDARD",
"travelerType": "ADULT",
"price": {
"currency": "EUR",
"total": "141.12",
"base": "85.00"
},
"fareDetailsBySegment": [
{
"segmentId": "2",
"cabin": "ECONOMY",
"fareBasis": "LLPTOSM",
"brandedFare": "GOSMART",
"brandedFareLabel": "SAS GO SMART",
"class": "L",
"includedCheckedBags": {
"quantity": 1
},
"amenities": [
{
"description": "PRE RESERVED SEAT ASSIGNMENT",
"isChargeable": true,
"amenityType": "PRE_RESERVED_SEAT",
"amenityProvider": {
"name": "BrandedFare"
}
},
{
"description": "FOOD AND BEVERAGE",
"isChargeable": true,
"amenityType": "MEAL",
"amenityProvider": {
"name": "BrandedFare"
}
},
{
"description": "CHANGEABLE TICKET",
"isChargeable": true,
"amenityType": "BRANDED_FARES",
"amenityProvider": {
"name": "BrandedFare"
}
},
{
"description": "UPGRADE",
"isChargeable": true,
"amenityType": "UPGRADES",
"amenityProvider": {
"name": "BrandedFare"
}
}
]
}
]
}
]
},
{
"type": "flight-offer",
"id": "4",
"source": "GDS",
"instantTicketingRequired": false,
"nonHomogeneous": false,
"oneWay": false,
"isUpsellOffer": false,
"lastTicketingDate": "2025-01-14",
"lastTicketingDateTime": "2025-01-14",
"numberOfBookableSeats": 7,
"itineraries": [
{
"duration": "PT3H45M",
"segments": [
{
"departure": {
"iataCode": "LIS",
"terminal": "1",
"at": "2025-01-15T19:00:00"
},
"arrival": {
"iataCode": "CPH",
"terminal": "3",
"at": "2025-01-15T23:45:00"
},
"carrierCode": "SK",
"number": "8922",
"aircraft": {
"code": "320"
},
"operating": {
"carrierCode": "TP"
},
"duration": "PT3H45M",
"id": "4",
"numberOfStops": 0,
"blacklistedInEU": false
}
]
}
],
"price": {
"currency": "EUR",
"total": "141.12",
"base": "85.00",
"fees": [
{
"amount": "0.00",
"type": "SUPPLIER"
},
{
"amount": "0.00",
"type": "TICKETING"
}
],
"grandTotal": "141.12"
},
"pricingOptions": {
"fareType": [
"PUBLISHED"
],
"includedCheckedBagsOnly": true
},
"validatingAirlineCodes": [
"SK"
],
"travelerPricings": [
{
"travelerId": "1",
"fareOption": "STANDARD",
"travelerType": "ADULT",
"price": {
"currency": "EUR",
"total": "141.12",
"base": "85.00"
},
"fareDetailsBySegment": [
{
"segmentId": "4",
"cabin": "ECONOMY",
"fareBasis": "LLPTOSM",
"brandedFare": "GOSMART",
"brandedFareLabel": "SAS GO SMART",
"class": "L",
"includedCheckedBags": {
"quantity": 1
},
"amenities": [
{
"description": "PRE RESERVED SEAT ASSIGNMENT",
"isChargeable": true,
"amenityType": "PRE_RESERVED_SEAT",
"amenityProvider": {
"name": "BrandedFare"
}
},
{
"description": "FOOD AND BEVERAGE",
"isChargeable": true,
"amenityType": "MEAL",
"amenityProvider": {
"name": "BrandedFare"
}
},
{
"description": "CHANGEABLE TICKET",
"isChargeable": true,
"amenityType": "BRANDED_FARES",
"amenityProvider": {
"name": "BrandedFare"
}
},
{
"description": "UPGRADE",
"isChargeable": true,
"amenityType": "UPGRADES",
"amenityProvider": {
"name": "BrandedFare"
}
}
]
}
]
}
]
}
]

File diff suppressed because one or more lines are too long