Initial commit

This commit is contained in:
AzureAD\SylvainDUVERNAY
2026-02-13 14:23:19 +01:00
commit 078843f991
80 changed files with 23994 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
import psycopg2
from proteus import config
# CSV file paths
EMPLOYEE_CSV = 'loaders/employees.csv'
PARTIES_CSV = 'loaders/parties.csv'
CUSTOMER_STOCK_LOCATIONS_CSV = 'loaders/customer_stock_locations.csv'
SUPPLIER_STOCK_LOCATIONS_CSV = 'loaders/supplier_stock_locations.csv'
SERVICES_CSV = 'loaders/services.csv'
VESSELS_CSV = 'loaders/vessels.csv'
PURCHASE_CONTRACTS_CSV = 'loaders/Purchase_Contracts_with_mapping.csv'
PURCHASE_FEES_CSV = 'loaders/purchase_fees.csv'
SALE_CONTRACTS_CSV = 'loaders/Sale_Contracts_with_mapping.csv'
# XML-RPC Configuration (for Proteus interaction)
HTTPS = 'https://'
SERVER_URL = 'itsa.open-squared.tech'
DATABASE_NAME = 'tradon'
USERNAME = 'admin'
PASSWORD = 'dsproject'
# PostgreSQL Configuration (for direct database access if needed)
DB_HOST = '72.61.163.139'
DB_PORT = 5433
DB_USER = 'postgres'
DB_PASSWORD = 'dsproject'
# Database connection configuration for direct PostgreSQL access
# Used by migration mapper and custom field updates
DB_CONFIG = {
'host': DB_HOST, # Your PostgreSQL host
'port': DB_PORT, # Your PostgreSQL port
'database': DATABASE_NAME, # Your Tryton database name
'user': DB_USER, # Your database user
'password': DB_PASSWORD # Your database password
}
# Function to connect to Tryton via XML-RPC
def connect_to_tryton():
"""Establish connection to Tryton via XML-RPC"""
print(f"Server: {HTTPS}{SERVER_URL}")
print(f"Database: {DATABASE_NAME}")
print(f"Username: {USERNAME}")
try:
connection = config.set_xmlrpc(f'{HTTPS}{USERNAME}:{PASSWORD}@{SERVER_URL}/{DATABASE_NAME}/')
print("✓ Connected successfully!\n")
return connection
except Exception as e:
print(f"✗ Connection failed: {e}")
print("\nTroubleshooting:")
print(" - Verify the server URL is correct and accessible")
print(" - Check that the Tryton server is running")
print(" - Verify username and password are correct")
print(" - Make sure you can access the server in a browser")
raise
def get_db_connection():
"""Get PostgreSQL database connection"""
try:
connection = psycopg2.connect(
host=DB_HOST,
port=DB_PORT,
database=DATABASE_NAME,
user=DB_USER,
password=DB_PASSWORD
)
return connection
except Exception as e:
print(f"✗ Database connection failed: {e}")
raise

View File

@@ -0,0 +1,332 @@
# helpers/migration_mapping.py
from datetime import date
import psycopg2
from psycopg2.extras import execute_values
import logging
logger = logging.getLogger(__name__)
class MigrationMapper:
"""Handle migration mapping records between source system and Tryton"""
def __init__(self, db_config):
"""
Initialize with database configuration
Args:
db_config: dict with keys: host, port, database, user, password
"""
self.db_config = db_config
self.connection = None
def __enter__(self):
"""Context manager entry - establish database connection"""
self.connection = psycopg2.connect(**self.db_config)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""Context manager exit - close database connection"""
if self.connection:
if exc_type is None:
self.connection.commit()
else:
self.connection.rollback()
self.connection.close()
def save_mapping(self, object_type, source_id, tryton_model, tryton_id, recon_key):
"""
Save a single migration mapping record
Args:
object_type: Type of object being migrated (e.g., 'sale_contract')
source_id: ID from source system
tryton_model: Tryton model name (e.g., 'sale.sale')
tryton_id: Tryton record ID
recon_key: Reconciliation key for matching (e.g., contract number)
"""
mappings = [{
'object_type': object_type,
'source_id': source_id,
'tryton_model': tryton_model,
'tryton_id': tryton_id,
'recon_key': recon_key
}]
self.save_mappings_batch(mappings)
def save_mappings_batch(self, mappings):
"""
Save multiple migration mapping records in batch
Args:
mappings: List of dicts with keys:
- object_type: Type of object being migrated
- source_id: ID from source system
- tryton_model: Tryton model name
- tryton_id: Tryton record ID
- recon_key: Reconciliation key for matching
"""
if not mappings:
logger.warning("No mappings to save")
return
cursor = self.connection.cursor()
# Prepare data for batch insert
values = [
(
[mapping['object_type']], # Array with single element
[mapping['source_id']], # Array with single element
[mapping['tryton_model']], # Array with single element
mapping['tryton_id'],
[mapping['recon_key']], # Array with single element
date.today()
)
for mapping in mappings
]
try:
# Use execute_values for efficient batch insert
# ON CONFLICT DO NOTHING prevents duplicates
execute_values(
cursor,
"""
INSERT INTO public.os_migration_mapping
(object_type, source_id, tryton_model, tryton_id, recon_key, write_date)
VALUES %s
ON CONFLICT DO NOTHING
""",
values,
template="(%s, %s, %s, %s, %s, %s)"
)
logger.info(f"Saved {len(mappings)} migration mapping records")
except Exception as e:
logger.error(f"Error saving migration mappings: {e}")
raise
finally:
cursor.close()
def get_tryton_id(self, object_type, source_id):
"""
Retrieve Tryton ID for a given source system ID
Args:
object_type: Type of object
source_id: ID from source system
Returns:
int: Tryton ID or None if not found
"""
cursor = self.connection.cursor()
try:
cursor.execute(
"""
SELECT tryton_id
FROM public.os_migration_mapping
WHERE %s = ANY(object_type)
AND %s = ANY(source_id)
ORDER BY write_date DESC
LIMIT 1
""",
(object_type, source_id)
)
result = cursor.fetchone()
return result[0] if result else None
finally:
cursor.close()
def get_source_id(self, object_type, tryton_id):
"""
Retrieve source system ID for a given Tryton ID
Args:
object_type: Type of object
tryton_id: Tryton record ID
Returns:
str: Source ID or None if not found
"""
cursor = self.connection.cursor()
try:
cursor.execute(
"""
SELECT source_id[1]
FROM public.os_migration_mapping
WHERE %s = ANY(object_type)
AND tryton_id = %s
ORDER BY write_date DESC
LIMIT 1
""",
(object_type, tryton_id)
)
result = cursor.fetchone()
return result[0] if result else None
finally:
cursor.close()
def get_mapping_by_recon_key(self, object_type, recon_key):
"""
Retrieve mapping by reconciliation key
Args:
object_type: Type of object
recon_key: Reconciliation key
Returns:
dict: Mapping record or None if not found
"""
cursor = self.connection.cursor()
try:
cursor.execute(
"""
SELECT
object_type[1] as object_type,
source_id[1] as source_id,
tryton_model[1] as tryton_model,
tryton_id,
recon_key[1] as recon_key,
write_date
FROM public.os_migration_mapping
WHERE %s = ANY(object_type)
AND %s = ANY(recon_key)
ORDER BY write_date DESC
LIMIT 1
""",
(object_type, recon_key)
)
result = cursor.fetchone()
if result:
return {
'object_type': result[0],
'source_id': result[1],
'tryton_model': result[2],
'tryton_id': result[3],
'recon_key': result[4],
'write_date': result[5]
}
return None
finally:
cursor.close()
def delete_mappings_by_source(self, object_type, source_ids):
"""
Delete mappings by source IDs (useful for re-import)
Args:
object_type: Type of object
source_ids: List of source IDs to delete
Returns:
int: Number of records deleted
"""
if not source_ids:
return 0
cursor = self.connection.cursor()
try:
# Delete records where source_id matches any in the list
cursor.execute(
"""
DELETE FROM public.os_migration_mapping
WHERE %s = ANY(object_type)
AND source_id[1] = ANY(%s)
""",
(object_type, source_ids)
)
deleted_count = cursor.rowcount
logger.info(f"Deleted {deleted_count} migration mapping records")
return deleted_count
finally:
cursor.close()
def get_all_mappings(self, object_type=None):
"""
Retrieve all mappings, optionally filtered by object type
Args:
object_type: Optional object type filter
Returns:
list: List of mapping dicts
"""
cursor = self.connection.cursor()
try:
if object_type:
cursor.execute(
"""
SELECT
object_type[1] as object_type,
source_id[1] as source_id,
tryton_model[1] as tryton_model,
tryton_id,
recon_key[1] as recon_key,
write_date
FROM public.os_migration_mapping
WHERE %s = ANY(object_type)
ORDER BY write_date DESC
""",
(object_type,)
)
else:
cursor.execute(
"""
SELECT
object_type[1] as object_type,
source_id[1] as source_id,
tryton_model[1] as tryton_model,
tryton_id,
recon_key[1] as recon_key,
write_date
FROM public.os_migration_mapping
ORDER BY write_date DESC
"""
)
results = cursor.fetchall()
return [
{
'object_type': row[0],
'source_id': row[1],
'tryton_model': row[2],
'tryton_id': row[3],
'recon_key': row[4],
'write_date': row[5]
}
for row in results
]
finally:
cursor.close()
# Simplified standalone function for quick integration
def save_migration_mapping(db_config, object_type, source_id, tryton_model,
tryton_id, recon_key):
"""
Standalone function to save a single migration mapping
Args:
db_config: dict with database connection parameters
object_type: Type of object being migrated
source_id: ID from source system
tryton_model: Tryton model name
tryton_id: Tryton record ID
recon_key: Reconciliation key for matching
"""
with MigrationMapper(db_config) as mapper:
mapper.save_mapping(object_type, source_id, tryton_model, tryton_id, recon_key)

File diff suppressed because it is too large Load Diff