import gradio as gr import pandas as pd from datetime import datetime import pytz import openpyxl def process_file(file): file_name = file.name.lower() try: if file_name.endswith('.csv'): # CSV files do not have multiple sheets. return "Error: Please upload an Excel file with a UPS sheet.", None elif file_name.endswith(('.xls', '.xlsx', '.xlsm')): # Only read data from the "UPS" sheet. df = pd.read_excel(file.name, sheet_name="UPS") else: return f"Unsupported file format: {file_name}", None except Exception as e: return f"Error reading file: {str(e)}", None # Define the new header list as specified. output_headers = [ "Contact Name", "Company or Name", "Country", "Address 1", "Address 2", "Address 3", "City", "State/Prov/Other", "Postal Code", "Telephone", "Ext", "Residential Ind", "Consignee Email", "Packaging Type", "Customs Value", "Weight", "Length", "Width", "Height", "Unit of Measure", "Description of Goods", "Documents of No Commercial Value", "GNIFC", "Pkg Decl Value", "Service", "Delivery Confirm", "Shipper Release", "Ret of Documents", "Saturday Deliver", "Carbon Neutral", "Large Package", "Addl handling", "Reference 1", "Reference 2", "Reference 3", "QV Notif 1-Addr", "QV Notif 1-Ship", "QV Notif 1-Excp", "QV Notif 1-Delv", "QV Notif 2-Addr", "QV Notif 2-Ship", "QV Notif 2-Excp", "QV Notif 2-Delv", "QV Notif 3-Addr", "QV Notif 3-Ship", "QV Notif 3-Excp", "QV Notif 3-Delv", "QV Notif 4-Addr", "QV Notif 4-Ship", "QV Notif 4-Excp", "QV Notif 4-Delv", "QV Notif 5-Addr", "QV Notif 5-Ship", "QV Notif 5-Excp", "QV Notif 5-Delv", "QV Notif Msg", "QV Failure Addr", "UPS Premium Care", "ADL Location ID", "ADL Media Type", "ADL Language", "ADL Notification Addr", "ADL Failure Addr", "ADL COD Value", "ADL Deliver to Addressee", "ADL Shipper Media Type", "ADL Shipper Language", "ADL Shipper Notification Addr", "ADL Direct Delivery Only", "Electronic Package Release Authentication", "Lithium Ion Alone", "Lithium Ion In Equipment", "Lithium Ion With_Equipment", "Lithium Metal Alone", "Lithium Metal In Equipment", "Lithium Metal With Equipment", "Weekend Commercial Delivery", "Dry Ice Weight", "Merchandise Description", "UPS SurePost®Limited Quantity/Lithium Battery" ] # Create an output DataFrame with the new header list. output_df = pd.DataFrame("", index=range(len(df)), columns=output_headers) # Mapping from input file to output based on provided rules: # 1. Shipping First Name + Shipping Last Name + Shipping Company -> Contact Name and Company or Name if {"Shipping First Name", "Shipping Last Name", "Shipping Company"}.issubset(df.columns): first_name = df["Shipping First Name"].fillna("").astype(str).str.strip() last_name = df["Shipping Last Name"].fillna("").astype(str).str.strip() company = df["Shipping Company"].fillna("").astype(str).str.strip() combined = (first_name + " " + last_name + " " + company).str.strip() output_df["Contact Name"] = combined output_df["Company or Name"] = combined # 2. Shipping Country Code -> Country if "Shipping Country Code" in df.columns: output_df["Country"] = df["Shipping Country Code"].fillna("").astype(str).str.strip() # 3. Shipping Address 1 -> Address 1 if "Shipping Address 1" in df.columns: output_df["Address 1"] = df["Shipping Address 1"].fillna("").astype(str).str.strip() # 4. Shipping Address 2 -> Address 2 if "Shipping Address 2" in df.columns: output_df["Address 2"] = df["Shipping Address 2"].fillna("").astype(str).str.strip() # 5. Shipping City -> City if "Shipping City" in df.columns: output_df["City"] = df["Shipping City"].fillna("").astype(str).str.strip() # 6. Shipping Province -> State/Prov/Other if "Shipping Province" in df.columns: output_df["State/Prov/Other"] = df["Shipping Province"].fillna("").astype(str).str.strip() # Convert full US state names to their 2-letter abbreviations if applicable. us_states = { 'alabama': 'AL', 'alaska': 'AK', 'arizona': 'AZ', 'arkansas': 'AR', 'california': 'CA', 'colorado': 'CO', 'connecticut': 'CT', 'delaware': 'DE', 'florida': 'FL', 'georgia': 'GA', 'hawaii': 'HI', 'idaho': 'ID', 'illinois': 'IL', 'indiana': 'IN', 'iowa': 'IA', 'kansas': 'KS', 'kentucky': 'KY', 'louisiana': 'LA', 'maine': 'ME', 'maryland': 'MD', 'massachusetts': 'MA', 'michigan': 'MI', 'minnesota': 'MN', 'mississippi': 'MS', 'missouri': 'MO', 'montana': 'MT', 'nebraska': 'NE', 'nevada': 'NV', 'new hampshire': 'NH', 'new jersey': 'NJ', 'new mexico': 'NM', 'new york': 'NY', 'north carolina': 'NC', 'north dakota': 'ND', 'ohio': 'OH', 'oklahoma': 'OK', 'oregon': 'OR', 'pennsylvania': 'PA', 'rhode island': 'RI', 'south carolina': 'SC', 'south dakota': 'SD', 'tennessee': 'TN', 'texas': 'TX', 'utah': 'UT', 'vermont': 'VT', 'virginia': 'VA', 'washington': 'WA', 'west virginia': 'WV', 'wisconsin': 'WI', 'wyoming': 'WY' } def convert_state(state): if state: state_lower = state.lower() return us_states.get(state_lower, state) return state output_df["State/Prov/Other"] = output_df["State/Prov/Other"].apply(convert_state) # 7. Shipping ZIP -> Postal Code if "Shipping ZIP" in df.columns: output_df["Postal Code"] = df["Shipping ZIP"].fillna("").astype(str).str.strip() # 8. Shipping Address Phone -> Telephone if "Shipping Address Phone" in df.columns: output_df["Telephone"] = df["Shipping Address Phone"].fillna("").astype(str).str.strip() # 9. Email -> Consignee Email if "Email" in df.columns: output_df["Consignee Email"] = df["Email"].fillna("").astype(str).str.strip() # 10. Total Weight -> Weight (divide by 1000) if "Total Weight" in df.columns: def convert_weight(x): try: if pd.isna(x) or x == "": return "" return float(x) / 1000 except: return "" output_df["Weight"] = df["Total Weight"].apply(convert_weight) # Fixed value mapping (applied for rows with data in Contact Name) mask = output_df["Contact Name"].notna() & (output_df["Contact Name"] != "") output_df.loc[mask, "Packaging Type"] = "2" output_df.loc[mask, "Unit of Measure"] = "KG" output_df.loc[mask, "Description of Goods"] = "Eyes Beauty Color Cosmetics" output_df.loc[mask, "Service"] = "7" # Delete duplicate rows based on "Contact Name", keeping the first occurrence. output_df = output_df.drop_duplicates(subset=["Contact Name"], keep="first") # Generate the output file name using the current Hong Kong date. hk_timezone = pytz.timezone("Asia/Hong_Kong") current_date_hk = datetime.now(hk_timezone).strftime("%y%m%d") output_file_name = f"UPS {current_date_hk}.csv" # Save the output DataFrame to a CSV file without the header. output_df.to_csv(output_file_name, index=False, header=False) return output_df, output_file_name with gr.Blocks(title="Shipping - UPS") as demo: gr.Markdown("# Shipping - UPS") with gr.Row(): file_input = gr.File(label="Upload Excel File with a UPS sheet") process_button = gr.Button("Process Data") with gr.Row(): output_data = gr.DataFrame() output_file_component = gr.File(label="Download Processed File") process_button.click(fn=process_file, inputs=[file_input], outputs=[output_data, output_file_component]) # Updated hyperlink block with separate sections for Shipping Tools and Administration Tools. gr.HTML( """

Shipping Tools

DHL | EC-Ship | Fedex | UPS

Administration Tools

Email Template | Google Merchant | Order Processing
""" ) demo.launch()