#!/usr/bin/env python3
"""
Comprehensive employee import script with full CSV field mapping
"""
import csv
import sys
import os
import time
from datetime import datetime
# Add the src directory to Python path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
from odoo_mcp.odoo_client import get_odoo_client
from csv_to_odoo_field_mapping import map_csv_row_to_odoo_employee, get_department_mapping, get_job_mapping, get_country_mapping
def get_existing_employee_names(client):
"""Get list of existing employee names in Odoo"""
print("Fetching existing employees...")
employees = client.search_read('hr.employee', [], ['name'], limit=1000)
existing_names = set(emp['name'] for emp in employees)
print(f"Found {len(existing_names)} existing employees")
return existing_names
def create_or_get_department(client, project_name, dept_mapping):
"""Create department if it doesn't exist, return department ID"""
if not project_name:
return None
project_key = project_name.lower().strip()
if project_key in dept_mapping:
return dept_mapping[project_key]
# Create new department
try:
dept_data = {
'name': project_name.strip(),
'complete_name': project_name.strip()
}
result = client.create_record('hr.department', dept_data)
if isinstance(result, list) and len(result) > 0:
dept_id = result[0]
dept_mapping[project_key] = dept_id
print(f"Created new department: {project_name} (ID: {dept_id})")
return dept_id
except Exception as e:
print(f"Error creating department '{project_name}': {e}")
return None
def create_or_get_job_position(client, job_title, job_mapping):
"""Create job position if it doesn't exist, return job ID"""
if not job_title:
return None
job_key = job_title.lower().strip()
if job_key in job_mapping:
return job_mapping[job_key]
# Create new job position
try:
job_data = {
'name': job_title.strip(),
}
result = client.create_record('hr.job', job_data)
if isinstance(result, list) and len(result) > 0:
job_id = result[0]
job_mapping[job_key] = job_id
print(f"Created new job position: {job_title} (ID: {job_id})")
return job_id
except Exception as e:
print(f"Error creating job position '{job_title}': {e}")
return None
def get_country_id(client, nationality, country_mapping):
"""Get country ID from nationality"""
if not nationality:
return None
nationality_key = nationality.lower().strip()
# Common nationality mappings
nationality_to_country = {
'bangladesh': 'bangladesh',
'bangladeshi': 'bangladesh',
'india': 'india',
'indian': 'india',
'pakistan': 'pakistan',
'pakistani': 'pakistan',
'nepal': 'nepal',
'nepali': 'nepal',
'philippines': 'philippines',
'filipino': 'philippines',
'egypt': 'egypt',
'egyptian': 'egypt',
'sudan': 'sudan',
'sudanese': 'sudan',
'yemen': 'yemen',
'yemeni': 'yemen',
'saudi arabia': 'saudi arabia',
'saudi': 'saudi arabia',
}
country_name = nationality_to_country.get(nationality_key, nationality_key)
return country_mapping.get(country_name)
def find_supervisor_id(client, supervisor_email):
"""Find supervisor employee ID by email"""
if not supervisor_email or '@' not in supervisor_email:
return None
try:
supervisors = client.search_read('hr.employee', [('work_email', '=', supervisor_email)], ['id'])
if supervisors:
return supervisors[0]['id']
except Exception as e:
print(f"Error finding supervisor '{supervisor_email}': {e}")
return None
def create_employee_from_csv_row(client, row, dept_mapping, job_mapping, country_mapping):
"""Create an employee record from CSV row data with comprehensive mapping"""
try:
# Get base employee data using field mapping
employee_data = map_csv_row_to_odoo_employee(row, client)
# Handle department mapping
if row.get('Project'):
dept_id = create_or_get_department(client, row['Project'], dept_mapping)
if dept_id:
employee_data['department_id'] = dept_id
# Handle job position mapping
if row.get('Profession'):
job_id = create_or_get_job_position(client, row['Profession'], job_mapping)
if job_id:
employee_data['job_id'] = job_id
# Handle country mapping for nationality
if row.get('Nationality'):
country_id = get_country_id(client, row['Nationality'], country_mapping)
if country_id:
employee_data['country_of_birth'] = country_id
# Handle supervisor mapping
if row.get('Supervisor'):
supervisor_id = find_supervisor_id(client, row['Supervisor'])
if supervisor_id:
employee_data['parent_id'] = supervisor_id
# Create work email if not provided
if not employee_data.get('work_email') and employee_data.get('name'):
name_parts = employee_data['name'].lower().split()
if len(name_parts) > 1:
email = f"{name_parts[0]}.{name_parts[-1]}@barqapp.com"
else:
email = f"{name_parts[0]}@barqapp.com"
employee_data['work_email'] = email
print(f"Creating employee: {employee_data['name']}")
print(f" Fields: {len(employee_data)} mapped fields")
result = client.create_record('hr.employee', employee_data)
if isinstance(result, list) and len(result) > 0:
employee_id = result[0]
return employee_id
else:
print(f"Failed to create employee '{employee_data['name']}': {result}")
return None
except Exception as e:
print(f"Error creating employee '{row.get('Name', 'Unknown')}': {str(e)}")
import traceback
traceback.print_exc()
return None
def import_employees_with_comprehensive_mapping(test_mode=False, limit=10):
"""Import employees with comprehensive field mapping"""
csv_file = '/Users/ramizmohamed/Downloads/Asset Managment - COURIER MASTER SHEET (1).csv'
try:
# Initialize Odoo client
print("Connecting to Odoo...")
client = get_odoo_client()
print("Connected successfully!")
# Get existing employees to avoid duplicates
existing_names = get_existing_employee_names(client)
# Get mapping tables
print("Loading mapping tables...")
dept_mapping = get_department_mapping(client)
job_mapping = get_job_mapping(client)
country_mapping = get_country_mapping(client)
print(f"Loaded {len(dept_mapping)} departments, {len(job_mapping)} jobs, {len(country_mapping)} countries")
# Read CSV file
print(f"Reading CSV file: {csv_file}")
created_count = 0
failed_count = 0
skipped_count = 0
processed_count = 0
with open(csv_file, 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row_num, row in enumerate(reader, start=2): # Start from 2 since row 1 is headers
# Only process active employees
if row['Status'].strip().lower() == 'active':
employee_name = row['Name'].strip()
# Skip if employee already exists
if employee_name in existing_names:
print(f"Skipping row {row_num}: {employee_name} (already exists)")
skipped_count += 1
continue
print(f"\nProcessing row {row_num}: {employee_name}")
employee_id = create_employee_from_csv_row(client, row, dept_mapping, job_mapping, country_mapping)
if employee_id:
created_count += 1
print(f"✓ Created employee '{employee_name}' with ID: {employee_id}")
existing_names.add(employee_name) # Add to avoid duplicates in this run
else:
failed_count += 1
print(f"✗ Failed to create employee '{employee_name}'")
processed_count += 1
# Test mode: only process limited number
if test_mode and processed_count >= limit:
print(f"\nTest mode: processed {limit} employees")
break
# Small pause to avoid overwhelming the server
if processed_count % 20 == 0:
print(f"Processed {processed_count} employees, pausing...")
time.sleep(1)
print(f"\n=== Final Import Summary ===")
print(f"Successfully created: {created_count} employees")
print(f"Failed to create: {failed_count} employees")
print(f"Skipped (already exist): {skipped_count} employees")
print(f"Total processed: {processed_count} active employees")
except Exception as e:
print(f"Error during import: {str(e)}")
import traceback
traceback.print_exc()
if __name__ == '__main__':
# Test with a few employees first
print("=== COMPREHENSIVE EMPLOYEE IMPORT ===")
print("This script will import ALL CSV fields to their corresponding Odoo fields")
print()
test_mode = input("Run in test mode? (y/n): ").lower().startswith('y')
if test_mode:
limit = int(input("How many employees to test? (default 5): ") or "5")
import_employees_with_comprehensive_mapping(test_mode=True, limit=limit)
else:
confirm = input("Import ALL remaining active employees? (y/n): ").lower().startswith('y')
if confirm:
import_employees_with_comprehensive_mapping(test_mode=False)
else:
print("Import cancelled.")