Initial commit
This commit is contained in:
0
Reference Data/python_project/helpers/__init__.py
Normal file
0
Reference Data/python_project/helpers/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
78
Reference Data/python_project/helpers/config.py
Normal file
78
Reference Data/python_project/helpers/config.py
Normal 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
|
||||
332
Reference Data/python_project/helpers/migration_mapping.py
Normal file
332
Reference Data/python_project/helpers/migration_mapping.py
Normal 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)
|
||||
1158
Reference Data/python_project/helpers/tryton_helpers.py
Normal file
1158
Reference Data/python_project/helpers/tryton_helpers.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user