Initial commit
This commit is contained in:
@@ -0,0 +1,239 @@
|
||||
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
|
||||
""")
|
||||
Reference in New Issue
Block a user