NextERP-scripts/scripts/update_contact.py

192 lines
7.1 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import odoorpc
import argparse
import sys
from tqdm import tqdm
def parse_arguments():
parser = argparse.ArgumentParser(
description="Update contacts to add salesperson and their manager as followers"
)
parser.add_argument("--host", required=True, help="Odoo server host")
parser.add_argument("--port", type=int, default=8069, help="Odoo server port")
parser.add_argument("--db", required=True, help="Database name")
parser.add_argument("--user", required=True, help="Username")
parser.add_argument("--password", required=True, help="Password")
parser.add_argument(
"--limit", type=int, help="Limit the number of contacts to process"
)
parser.add_argument(
"--batch-size", type=int, default=100, help="Batch size for processing"
)
return parser.parse_args()
def main():
args = parse_arguments()
# Connect to Odoo
print(f"Connecting to {args.host}:{args.port}, database {args.db}...")
try:
odoo = odoorpc.ODOO(args.host, port=args.port)
odoo.login(args.db, args.user, args.password)
print("Connected successfully")
except Exception as e:
print(f"Connection failed: {e}")
sys.exit(1)
# Get all contacts with salespersons
contact_domain = [("user_id", "!=", False)]
# Get total count
contact_count = odoo.env["res.partner"].search_count(contact_domain)
print(f"Found {contact_count} contacts with assigned salespersons")
# Apply limit if specified
if args.limit and args.limit > 0:
print(f"Processing only {args.limit} contacts due to limit argument")
contact_count = min(contact_count, args.limit)
# Search contacts
contact_ids = odoo.env["res.partner"].search(contact_domain, limit=args.limit)
# Process in batches to avoid memory issues
batch_size = args.batch_size
total_updated = 0
# Pre-fetch user and employee data
print("Pre-fetching user and employee data...")
user_partner_cache = {} # Maps user_id to partner_id
user_manager_partners_cache = {} # Maps user_id to list of manager partner_ids
# Setup progress bar
total_batches = (len(contact_ids) + batch_size - 1) // batch_size
pbar = tqdm(total=total_batches, desc="Processing batches")
for i in range(0, len(contact_ids), batch_size):
batch_ids = contact_ids[i : i + batch_size]
batch_contacts = odoo.env["res.partner"].browse(batch_ids)
batch_updated = 0
# Collect all salesperson IDs in this batch
salesperson_ids = [
contact.user_id.id for contact in batch_contacts if contact.user_id
]
unique_salesperson_ids = list(set(salesperson_ids))
# Bulk fetch salesperson partner IDs if not in cache
new_user_ids = [
uid for uid in unique_salesperson_ids if uid not in user_partner_cache
]
if new_user_ids:
users = odoo.env["res.users"].browse(new_user_ids)
for user in users:
user_partner_cache[user.id] = user.partner_id.id
# Bulk fetch employee data for salespeople not in cache
new_employee_fetch = [
uid
for uid in unique_salesperson_ids
if uid not in user_manager_partners_cache
]
if new_employee_fetch:
# Find employee records for these users
employee_domain = [("user_id", "in", new_employee_fetch)]
employee_ids = odoo.env["hr.employee"].search(employee_domain)
# Map employee records to their user_ids for easier lookup
employee_by_user = {}
for emp_id in employee_ids:
emp = odoo.env["hr.employee"].browse(emp_id)
if emp.user_id:
employee_by_user[emp.user_id.id] = emp
# Process each salesperson that needs manager data
for salesperson_id in new_employee_fetch:
user_manager_partners_cache[salesperson_id] = []
# Skip if no employee record found
if salesperson_id not in employee_by_user:
continue
# Start with the employee record
current_employee = employee_by_user[salesperson_id]
# Walk up the management chain
while current_employee.parent_id:
manager = current_employee.parent_id
if manager.user_id:
# Cache the manager's partner ID if not already cached
if manager.user_id.id not in user_partner_cache:
manager_user = odoo.env["res.users"].browse(
manager.user_id.id
)
user_partner_cache[manager.user_id.id] = (
manager_user.partner_id.id
)
# Add this manager's partner ID to the salesperson's manager list
user_manager_partners_cache[salesperson_id].append(
user_partner_cache[manager.user_id.id]
)
# Move up the chain
current_employee = manager
# Process each contact in the batch
updates_by_partner = {}
for contact in batch_contacts:
salesperson_id = contact.user_id.id
if not salesperson_id:
continue
# Get the salesperson's partner ID
salesperson_partner_id = user_partner_cache.get(salesperson_id)
if not salesperson_partner_id:
continue
# Get the manager partner IDs for this salesperson
manager_partner_ids = user_manager_partners_cache.get(salesperson_id, [])
# Combine salesperson and manager partner IDs
partner_ids = [salesperson_partner_id] + manager_partner_ids
# Get current followers
current_followers = [f.partner_id.id for f in contact.message_follower_ids]
# Only add partners that are not already followers
partners_to_add = [p for p in partner_ids if p not in current_followers]
if partners_to_add:
updates_by_partner[contact.id] = partners_to_add
# Batch process the updates
for contact_id, partners in updates_by_partner.items():
try:
odoo.env["res.partner"].browse(contact_id).message_subscribe(
partner_ids=partners
)
print(f"Updated contact {contact.name} with partners {partners}")
batch_updated += 1
except Exception as e:
contact_name = odoo.env["res.partner"].browse(contact_id).name
print(f"Error updating contact {contact_name} (ID: {contact_id}): {e}")
total_updated += batch_updated
pbar.update(1)
pbar.set_postfix({"updated": batch_updated, "total_updated": total_updated})
pbar.close()
print(
f"Process completed. Updated {total_updated} out of {contact_count} contacts."
)
if __name__ == "__main__":
main()