Files
Implementation_ITSA/Reference Data/python_project/scripts/check_proteus_custom_fields.py
AzureAD\SylvainDUVERNAY 078843f991 Initial commit
2026-02-13 14:23:19 +01:00

239 lines
8.5 KiB
Python

from proteus import config, Model
import psycopg2
# XML-RPC Configuration (default connection method)
HTTPS = 'https://'
SERVER_URL = 'itsa.open-squared.tech'
DATABASE_NAME = 'tradon'
USERNAME = 'admin'
PASSWORD = 'dsproject'
# PostgreSQL Configuration (for direct database inspection)
DB_HOST = '72.61.163.139'
DB_PORT = 5433
DB_USER = 'postgres'
DB_PASSWORD = 'dsproject'
print("="*80)
print("CUSTOM FIELDS IDENTIFICATION FOR purchase.purchase")
print("="*80)
# Connect to Tryton via XML-RPC
print(f"\nConnecting via XML-RPC to {SERVER_URL}...")
config.set_xmlrpc(f'{HTTPS}{USERNAME}:{PASSWORD}@{SERVER_URL}/{DATABASE_NAME}/')
print("✓ Connected successfully\n")
Purchase = Model.get('purchase.purchase')
# Get all fields that Proteus sees
proteus_fields = sorted([key for key in dir(Purchase)
if not key.startswith('_')
and key not in ['create', 'delete', 'save', 'find',
'copy', 'read', 'write', 'search']])
print(f"1. FIELDS VISIBLE TO PROTEUS: {len(proteus_fields)} fields")
print("-"*80)
# Standard Tryton purchase.purchase fields (from base module)
standard_purchase_fields = {
'id', 'create_date', 'create_uid', 'write_date', 'write_uid',
'company', 'party', 'invoice_party', 'invoice_address',
'payment_term', 'warehouse', 'currency', 'description',
'comment', 'state', 'purchase_date', 'invoice_method',
'lines', 'invoices', 'invoices_ignored', 'invoices_recreated',
'invoice_lines', 'invoice_lines_ignored', 'moves',
'shipment_state', 'invoice_state', 'number', 'reference',
'shipments', 'shipment_returns', 'rec_name', 'origin',
'untaxed_amount', 'tax_amount', 'total_amount',
'untaxed_amount_cache', 'tax_amount_cache', 'total_amount_cache',
'delivery_date', 'party_lang', 'contact', 'xml_id'
}
# Identify potential custom fields
potential_custom_fields = [f for f in proteus_fields if f not in standard_purchase_fields]
print(f"\n2. POTENTIAL CUSTOM FIELDS: {len(potential_custom_fields)} fields")
print("-"*80)
for field in potential_custom_fields:
print(f" - {field}")
# Connect to PostgreSQL to get actual table columns
print(f"\n3. COLUMNS IN POSTGRESQL TABLE 'purchase_purchase'")
print("-"*80)
try:
conn = psycopg2.connect(
dbname=DATABASE_NAME,
host=DB_HOST,
port=DB_PORT,
user=DB_USER,
password=DB_PASSWORD
)
cursor = conn.cursor()
# Get all columns from purchase_purchase table
cursor.execute("""
SELECT
column_name,
data_type,
character_maximum_length,
is_nullable,
column_default
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'purchase_purchase'
ORDER BY ordinal_position;
""")
db_columns = cursor.fetchall()
print(f"Total columns in database: {len(db_columns)}\n")
# Standard columns that typically exist in purchase_purchase
standard_db_columns = {
'id', 'create_date', 'create_uid', 'write_date', 'write_uid',
'company', 'party', 'invoice_party', 'invoice_address',
'payment_term', 'warehouse', 'currency', 'description',
'comment', 'state', 'purchase_date', 'invoice_method',
'number', 'reference', 'delivery_date', 'contact',
'shipment_state', 'invoice_state', 'origin',
'untaxed_amount_cache', 'tax_amount_cache', 'total_amount_cache'
}
db_column_names = [col[0] for col in db_columns]
custom_db_columns = [col for col in db_columns if col[0] not in standard_db_columns]
print("Custom columns in database:")
for col in custom_db_columns:
col_name, data_type, max_length, nullable, default = col
length_info = f"({max_length})" if max_length else ""
print(f" - {col_name:<30} {data_type}{length_info:<15} NULL: {nullable}")
# Compare: Fields in Proteus vs Columns in DB
print(f"\n4. COMPARISON: PROTEUS vs DATABASE")
print("-"*80)
# Fields in Proteus but NOT as direct columns in DB (might be related fields, functions, etc.)
proteus_only = set(potential_custom_fields) - set(db_column_names)
if proteus_only:
print(f"\nFields in Proteus but NOT as columns in DB ({len(proteus_only)}):")
print("(These might be Many2One, One2Many, Function fields, etc.)")
for field in sorted(proteus_only):
print(f" - {field}")
# Columns in DB but NOT visible in Proteus (these are the problem!)
db_only = set([col[0] for col in custom_db_columns]) - set(proteus_fields)
if db_only:
print(f"\n⚠️ COLUMNS IN DATABASE BUT NOT VISIBLE IN PROTEUS ({len(db_only)}):")
print("(These fields MUST be added to the Python model!)")
for field in sorted(db_only):
print(f" - {field}")
# Fields that exist in BOTH Proteus and DB
both = set(potential_custom_fields) & set([col[0] for col in custom_db_columns])
if both:
print(f"\n✓ Custom fields properly defined in BOTH Proteus and DB ({len(both)}):")
for field in sorted(both):
print(f" - {field}")
cursor.close()
conn.close()
except Exception as e:
print(f"Error connecting to PostgreSQL: {e}")
# Test persistence of custom fields
print(f"\n5. TESTING FIELD PERSISTENCE")
print("-"*80)
try:
# Find a draft purchase to test
drafts = Purchase.find([('state', '=', 'draft')], limit=1)
if drafts:
test_purchase = drafts[0]
test_id = test_purchase.id
print(f"Testing with purchase ID: {test_id}")
print("\nTesting custom fields (attempting to set and save):\n")
# Test a sample of custom fields
test_fields = {}
# Add fields to test if they exist
if 'reference' in potential_custom_fields:
test_fields['reference'] = 'TEST_REF'
if 'crop' in potential_custom_fields:
test_fields['crop'] = 'TEST_CROP'
if 'forex' in potential_custom_fields:
test_fields['forex'] = 'TEST_FOREX'
if 'broker' in potential_custom_fields:
test_fields['broker'] = 'TEST_BROKER'
if 'certif' in potential_custom_fields:
test_fields['certif'] = 'TEST_CERT'
if 'wb' in potential_custom_fields:
test_fields['wb'] = 'TEST_WB'
for field_name, test_value in test_fields.items():
try:
original_value = getattr(test_purchase, field_name, None)
setattr(test_purchase, field_name, test_value)
test_purchase.save()
# Reload
reloaded = Purchase(test_id)
new_value = getattr(reloaded, field_name, None)
if new_value == test_value:
print(f"{field_name}: PERSISTS correctly")
# Restore original value
setattr(reloaded, field_name, original_value)
reloaded.save()
else:
print(f"{field_name}: Does NOT persist (expected: '{test_value}', got: '{new_value}')")
except Exception as e:
print(f"{field_name}: Error - {str(e)[:60]}")
else:
print("No draft purchases found for testing")
except Exception as e:
print(f"Error during persistence testing: {e}")
print("\n" + "="*80)
print("SUMMARY & RECOMMENDATIONS")
print("="*80)
print("""
Next steps for your colleague:
1. Review the "⚠️ COLUMNS IN DATABASE BUT NOT VISIBLE IN PROTEUS" section
→ These fields exist in PostgreSQL but are missing from the Python model
2. Review fields that "Does NOT persist" in the testing section
→ These fields are visible but not working correctly
3. Add missing fields to your custom Tryton module:
File: modules/your_custom_module/purchase.py
from trytond.pool import PoolMeta
from trytond.model import fields
class Purchase(metaclass=PoolMeta):
__name__ = 'purchase.purchase'
# Add each missing field with appropriate type:
custom_field = fields.Char('Custom Field')
custom_number = fields.Integer('Custom Number')
custom_date = fields.Date('Custom Date')
custom_many2one = fields.Many2One('other.model', 'Reference')
# etc...
4. Increment module version in tryton.cfg
5. Update module: trytond-admin -d tradon -u your_custom_module
6. Restart Tryton server
7. Re-run this script to verify all fields work correctly
""")