passport-static / src /formats.py
Hztech's picture
done
cd964f2 verified
Raw History Blame Contribute Delete
10.4 kB
import pandas as pd
import os
import logging
from datetime import datetime, date
logger = logging.getLogger(__name__)
def calculate_passenger_type(dob_str):
"""
Calculate passenger type based on age from date of birth.
Age groups:
- Infants: 0-1 year (0-11 months)
- Children: 1-17 years
- Adults: 18+ years
Returns:
For Fly Dubai: "Infant", "Child", "Adult"
For Iraqi/Fly Baghdad: "INF", "CHD", "ADT"
"""
if not dob_str:
return "Adult", "ADT" # Default to adult if no DOB
try:
# Parse the date (assuming DD/MM/YYYY format)
dob = datetime.strptime(dob_str, '%d/%m/%Y').date()
today = date.today()
# Calculate age in years
age_years = today.year - dob.year
if today.month < dob.month or (today.month == dob.month and today.day < dob.day):
age_years -= 1
# Calculate age in months for more accurate infant check
age_months = (today.year - dob.year) * 12 + (today.month - dob.month)
if today.day < dob.day:
age_months -= 1
# Determine passenger type based on age
if age_months < 12: # Less than 12 months - Infant
return "Infant", "INF"
elif age_years < 18: # 1-17 years - Child
return "Child", "CHD"
else: # 18+ years - Adult
return "Adult", "ADT"
except (ValueError, TypeError):
return "Adult", "ADT" # Default to adult if date parsing fails
def format_fly_dubai(data_list):
"""
Formats data for Fly Dubai template (previously Iraqi Airways).
Columns: TYPE, TITLE, FIRST NAME, LAST NAME, DOB (DD/MM/YYYY), GENDER
Example: Adult MR FirstNameOne LastNameOne 13/8/2015 Male
"""
formatted_rows = []
for item in data_list:
sex = item.get('sex', '').upper()
# Map Gender to Male/Female
gender_full = "Male" if sex == 'M' else "Female"
title = "MR" if sex == 'M' else "MRS"
# Calculate passenger type based on age
raw_dob = item.get('date_of_birth', '')
# Convert MRZ date (YYMMDD) to DD/MM/YYYY for age calculation
ddmmyyyy_dob = ''
if raw_dob and len(raw_dob) == 6: # YYMMDD format
try:
from datetime import datetime
mrz_date = datetime.strptime(raw_dob, '%y%m%d').date()
ddmmyyyy_dob = mrz_date.strftime('%d/%m/%Y')
except:
ddmmyyyy_dob = raw_dob
else:
ddmmyyyy_dob = raw_dob
passenger_type, _ = calculate_passenger_type(ddmmyyyy_dob)
row = {
"TYPE": passenger_type,
"TITLE": title,
"FIRST NAME": item.get('name', ''),
"LAST NAME": item.get('surname', ''),
"DOB (DD/MM/YYYY)": ddmmyyyy_dob,
"GENDER": gender_full
}
formatted_rows.append(row)
return pd.DataFrame(formatted_rows)
from datetime import datetime
def _to_ddmmmyy(date_str):
"""Converts DD/MM/YYYY to DDMMMYY format, e.g., 13NOV84."""
if not date_str:
return ""
try:
# Parse from DD/MM/YYYY
dt_obj = datetime.strptime(date_str, '%d/%m/%Y')
# Format to DDMMMYY with strict zero padding for day
# %d should do it, but to be safe we can use string formatting
day = dt_obj.strftime('%d')
month_year = dt_obj.strftime('%b%y').upper()
return f"{day}{month_year}"
except ValueError:
return date_str # Return original if parsing fails
def format_iraqi(data_list):
"""
Formats data for Iraqi template (previously Flydubai).
- Date of Birth: DDMMMYY (e.g., 13NOV84)
- Passport Expiry Date: DDMMMYY (e.g., 13NOV84)
"""
formatted_rows = []
for item in data_list:
sex = item.get('sex', '').upper()
title = "MR" if sex == 'M' else "MRS"
first_middle = item.get('name', '')
# Get date data for age calculation
raw_dob = item.get('date_of_birth', '')
raw_expiry = item.get('expiration_date', '')
# Calculate passenger type based on age
# The date might be in DDMMMYY format (18NOV16) or YYMMDD format (161118)
ddmmyyyy_dob = ''
if raw_dob:
try:
# First try YYMMDD format (MRZ raw format) - 6 chars
if len(raw_dob) == 6:
mrz_date = datetime.strptime(raw_dob, '%y%m%d').date()
ddmmyyyy_dob = mrz_date.strftime('%d/%m/%Y')
else:
# Try DDMMMYY format (already formatted) - 7+ chars
formatted_date = datetime.strptime(raw_dob, '%d%b%y').date()
ddmmyyyy_dob = formatted_date.strftime('%d/%m/%Y')
except:
ddmmyyyy_dob = raw_dob
else:
ddmmyyyy_dob = raw_dob
_, ptc_code = calculate_passenger_type(ddmmyyyy_dob)
# Use the dates as-is since they're already formatted
dob_formatted = raw_dob
expiry_formatted = raw_expiry
row = {
"Last Name": item.get('surname', ''),
"First Name and Middle Name": first_middle,
"Title": title,
"PTC": ptc_code, # Passenger Type Code based on age
"Gender": sex,
"Date of Birth": dob_formatted,
"Passport Last Name": item.get('surname', ''),
"Passport First Name": first_middle,
"Passport Middle Name": "",
"Passport Number": item.get('passport_number', ''),
"Passport Nationality": item.get('nationality', '')[:3],
"Passport Issue Country": item.get('country', '')[:3],
"Passport Expiry Date": expiry_formatted,
# Empty fields
"Visa Number": "", "Visa Type": "", "Visa Issue Date": "", "Place of Birth": "",
"Visa Place of Issue": "", "Visa Country of Application": "", "Address Type": "",
"Address Country": "", "Address Details": "", "Address City": "",
"Address State": "", "Address Zip Code": ""
}
formatted_rows.append(row)
return pd.DataFrame(formatted_rows)
def format_fly_baghdad(data_list):
"""
Formats data for Fly Baghdad template.
Columns: Sequence, Traveling With, Pax Type, Title, First Name, Last Name, Gender,
DOB (dd/mm/yyyy), Nationality, Passport Number, Passport Expiry (dd/mm/yyyy),
Passport Issued Country
"""
from config.settings import COUNTRY_CODES
# Create a mapping for quick lookup
country_map = {c['alpha-3']: c['name'].upper() for c in COUNTRY_CODES}
formatted_rows = []
for i, item in enumerate(data_list):
sex = item.get('sex', '').upper()
gender_full = "MALE" if sex == 'M' else "FEMALE"
title = "MR" if sex == 'M' else "MRS"
# Get and format DOB
raw_dob = item.get('date_of_birth', '')
ddmmyyyy_dob = ''
if raw_dob and len(raw_dob) == 6:
try:
mrz_date = datetime.strptime(raw_dob, '%y%m%d').date()
ddmmyyyy_dob = mrz_date.strftime('%d/%m/%Y')
except:
ddmmyyyy_dob = raw_dob
else:
ddmmyyyy_dob = raw_dob
# Get and format Expiry
raw_expiry = item.get('expiration_date', '')
ddmmyyyy_expiry = ''
if raw_expiry and len(raw_expiry) == 6:
try:
mrz_date = datetime.strptime(raw_expiry, '%y%m%d').date()
ddmmyyyy_expiry = mrz_date.strftime('%d/%m/%Y')
except:
ddmmyyyy_expiry = raw_expiry
else:
ddmmyyyy_expiry = raw_expiry
_, ptc_code = calculate_passenger_type(ddmmyyyy_dob)
# Map nationality and country
nat_code = item.get('nationality', '')[:3].upper()
country_code = item.get('country', '')[:3].upper()
nationality = country_map.get(nat_code, nat_code)
issued_country = country_map.get(country_code, country_code)
row = {
"Sequence": i + 1,
"Traveling With": "",
"Pax Type": ptc_code,
"Title": title,
"First Name": item.get('name', ''),
"Last Name": item.get('surname', ''),
"Gender": gender_full,
"DOB (dd/mm/yyyy)": ddmmyyyy_dob,
"Nationality": nationality,
"Passport Number": item.get('passport_number', ''),
"Passport Expiry (dd/mm/yyyy)": ddmmyyyy_expiry,
"Passport Issued Country": issued_country
}
formatted_rows.append(row)
return pd.DataFrame(formatted_rows)
def export_to_spreadsheet(data_list, output_file, format='excel'):
"""
Exports a list of dictionaries to a spreadsheet (Excel or CSV).
"""
if not data_list:
logger.warning("No data to export.")
return False
try:
df = pd.DataFrame(data_list)
# Ensure output directory exists
os.makedirs(os.path.dirname(output_file), exist_ok=True)
if format.lower() == 'excel' or output_file.endswith('.xlsx'):
if not output_file.endswith('.xlsx'):
output_file += '.xlsx'
df.to_excel(output_file, index=False)
logger.info(f"Data exported to {output_file}")
elif format.lower() == 'csv' or output_file.endswith('.csv'):
if not output_file.endswith('.csv'):
output_file += '.csv'
df.to_csv(output_file, index=False)
logger.info(f"Data exported to {output_file}")
else:
logger.error(f"Unsupported format: {format}")
return False
return True
except Exception as e:
logger.error(f"Failed to export data: {e}")
return False