ferrero-opentext/Python-Version/PPR_SIDE_BY_SIDE.md
nickviljoen f83b4fae3e PPR Environment: Use SIMPLE metadata structure for tabular fields
Key Changes:
- Updated metadata_extractor_mvp.py to use SIMPLE structure for all tabular fields
- All tabular fields now use direct value objects (no MetadataTableFieldRow wrapper)
- MAIN_LANGUAGES, ASSETCOMPLIANCE, MARKETING_TAG, CREATIVEX all use SIMPLE structure
- Master Asset ID field updated to SIMPLE structure
- Date fields now use type 'string' instead of 'long'
- Matches DAM reference structure from asset_representation.json

Added Files:
- metadata_extractor_mvp_PROD.py: PROD-specific version with same SIMPLE structure
- Backup files for safety
- Analysis and comparison documentation

Environment:
- Tested and working in PPR environment (ppr.dam.ferrero.com)
- All tabular fields match DAM-supplied reference structure
- Successful uploads confirmed

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-23 16:52:50 +02:00

12 KiB

PPR Payload - Side-by-Side Comparison

This document shows EXACT structural comparisons between the reference file and code-generated structures.


1. MAIN_LANGUAGES (Tabular Field)

Reference Structure

{
  "id": "MAIN_LANGUAGES",
  "parent_table_id": "FERRERO.TABULAR.FIELD.MAIN LANGUAGES",
  "type": "com.artesia.metadata.MetadataTableField",
  "values": [
    {
      "cascading_domain_value": false,
      "domain_value": true,
      "value": {
        "field_value": {
          "type": "string",
          "value": "DE"
        },
        "type": "com.artesia.metadata.DomainValue"
      }
    }
  ]
}

Code-Generated Structure

# Generated by: _add_missing_fields() at lines 267-285
{
    'id': 'MAIN_LANGUAGES',
    'parent_table_id': 'FERRERO.TABULAR.FIELD.MAIN LANGUAGES',
    'type': 'com.artesia.metadata.MetadataTableField',
    'values': [
        {
            'cascading_domain_value': False,  # Becomes false in JSON
            'domain_value': True,              # Becomes true in JSON
            'value': {
                'field_value': {
                    'type': 'string',
                    'value': language  # From parsed filename
                },
                'type': 'com.artesia.metadata.DomainValue'
            }
        }
    ]
}

Comparison Result

PERFECT MATCH

  • All properties present
  • Correct types
  • Correct nesting
  • Only difference: actual language value (dynamic)

2. FERRERO.FIELD.ASSETCOMPLIANCE (Tabular Field)

Reference Structure

{
  "id": "FERRERO.FIELD.ASSETCOMPLIANCE",
  "parent_table_id": "FERRERO.TABULAR.FIELD.ASSETCOMPLIANCE",
  "type": "com.artesia.metadata.MetadataTableField",
  "values": [
    {
      "cascading_domain_value": false,
      "domain_value": true,
      "is_locked": false,
      "value": {
        "field_value": {
          "type": "string",
          "value": "-"
        },
        "type": "com.artesia.metadata.DomainValue"
      }
    }
  ]
}

Code-Generated Structure

# Generated by: _add_missing_fields() at lines 313-332
{
    'id': 'FERRERO.FIELD.ASSETCOMPLIANCE',
    'parent_table_id': 'FERRERO.TABULAR.FIELD.ASSETCOMPLIANCE',
    'type': 'com.artesia.metadata.MetadataTableField',
    'values': [
        {
            'cascading_domain_value': False,
            'domain_value': True,
            'is_locked': False,
            'value': {
                'type': 'com.artesia.metadata.DomainValue',  # Note: order differs
                'field_value': {
                    'type': 'string',
                    'value': default_value  # From config
                }
            }
        }
    ]
}

Comparison Result

PERFECT MATCH

  • All properties present (including is_locked)
  • Correct types
  • Correct nesting
  • Property order differs (field_value vs type) - NOT SIGNIFICANT

3. MARKETING_TAG (Tabular Field)

Reference Structure

{
  "id": "MARKETING_TAG",
  "parent_table_id": "FERRERO.TABULAR.FIELD.MARKETING_TAG",
  "type": "com.artesia.metadata.MetadataTableField",
  "values": [
    {
      "cascading_domain_value": false,
      "domain_value": true,
      "is_locked": false,
      "value": {
        "field_value": {
          "type": "string",
          "value": "Tag"
        },
        "type": "com.artesia.metadata.DomainValue"
      }
    }
  ]
}

Code-Generated Structure

# Generated by: _add_missing_fields() at lines 313-332
{
    'id': 'MARKETING_TAG',
    'parent_table_id': 'FERRERO.TABULAR.FIELD.MARKETING_TAG',
    'type': 'com.artesia.metadata.MetadataTableField',
    'values': [
        {
            'cascading_domain_value': False,
            'domain_value': True,
            'is_locked': False,
            'value': {
                'type': 'com.artesia.metadata.DomainValue',
                'field_value': {
                    'type': 'string',
                    'value': default_value
                }
            }
        }
    ]
}

Comparison Result

PERFECT MATCH

  • All properties present
  • Correct types
  • Correct nesting

4. FERRERO.TAB.FIELD.CREATIVEX (Cascading Domain - Tabular)

Reference Structure

{
  "id": "FERRERO.TAB.FIELD.CREATIVEX",
  "parent_table_id": "FERRERO.TABULAR.FIELD.CREATIVEX",
  "type": "com.artesia.metadata.MetadataTableField",
  "values": [
    {
      "cascading_domain_value": true,
      "domain_value": false,
      "is_locked": false,
      "value": {
        "field_value": {
          "type": "string",
          "value": "FB - Biz Disco Feed^50"
        },
        "type": "com.artesia.metadata.CascadingDomainValue"
      }
    }
  ]
}

Code-Generated Structure

# Generated by: _update_creativex_fields() at lines 670-678
{
    "type": "com.artesia.metadata.MetadataTableField",
    "id": "FERRERO.TAB.FIELD.CREATIVEX",
    "parent_table_id": "FERRERO.TABULAR.FIELD.CREATIVEX",
    "values": [
        {
            "cascading_domain_value": True,   # Note: True not False!
            "domain_value": False,             # Note: False not True!
            "is_locked": False,
            "value": {
                "type": "com.artesia.metadata.CascadingDomainValue",  # Special type
                "field_value": {
                    "type": "string",
                    "value": f"{platform}^{score}"  # e.g., "FB - Biz Disco Feed^50"
                }
            }
        }
    ]
}

Comparison Result

PERFECT MATCH

  • Correctly uses CascadingDomainValue (not regular DomainValue)
  • Correctly sets cascading_domain_value: true
  • Correctly sets domain_value: false
  • Format: Platform^Score matches exactly

5. FERRERO.MASTERASSETIDS (Tabular Field)

Reference Structure

{
  "id": "FERRERO.MASTERASSETIDS",
  "parent_table_id": "FERRERO.TABULAR.FIELD.MASTERASSETIDS",
  "type": "com.artesia.metadata.MetadataTableField",
  "values": [
    {
      "cascading_domain_value": false,
      "domain_value": true,
      "is_locked": false,
      "value": {

        "field_value": {
          "type": "string",
          "value": "b5e69f3efdd81cd3a604708ed10c55a466d68b0e"
        },
        "type": "com.artesia.metadata.DomainValue"
      }
    }
  ]
}

(Note: Extra whitespace before "field_value" in reference - not significant)

Code-Generated Structure

# Generated by: _add_master_asset_id_field() at lines 771-789
{
    'id': 'FERRERO.MASTERASSETIDS',
    'parent_table_id': 'FERRERO.TABULAR.FIELD.MASTERASSETIDS',
    'type': 'com.artesia.metadata.MetadataTableField',
    'values': [
        {
            'cascading_domain_value': False,
            'domain_value': True,
            'is_locked': False,
            'value': {
                'type': 'com.artesia.metadata.DomainValue',
                'field_value': {
                    'type': 'string',
                    'value': master_opentext_id  # DAM Asset ID of master
                }
            }
        }
    ]
}

Comparison Result

PERFECT MATCH

  • All properties present
  • Correct parent/child relationship
  • Only difference: whitespace (not significant)

6. Date Field (FERRERO.FIELD.ASSET VALIDITY START PERIOD)

Reference Structure

{
  "value": {
    "type": "string",
    "value": "01/22/2026"
  }
}

Code-Generated Structure

# Generated by: _set_date_field_value() at lines 567-605
{
    'value': {
        'type': 'string',  # Not date object - string!
        'value': start_date_str  # MM/DD/YYYY format
    }
}

Comparison Result

PERFECT MATCH

  • Uses string type (not date object)
  • Format: MM/DD/YYYY (US format)
  • Simple two-level nesting

7. Domain Field (FERRERO.FIELD.MKTG.ASSET TYPE)

Reference Structure

{
  "cascading_domain_value": false,
  "domain_value": true,
  "is_locked": false,
  "value": {
    "active_from": "",
    "active_to": "",
    "display_value": "heroimage",
    "expired_value": false,
    "field_value": {
      "type": "string",
      "value": "heroimage"
    },
    "type": "com.artesia.metadata.DomainValue"
  }
}

Code-Generated Structure

# Generated by: _set_field_value() for domain fields at lines 543-558
{
    'value': {
        'type': 'com.artesia.metadata.DomainValue',
        'active_to': '',
        'active_from': '',
        'field_value': {
            'type': 'string',
            'value': value
        },
        'display_value': value,  # Same as field_value
        'expired_value': False
    },
    'is_locked': False,
    'domain_value': True,
    'cascading_domain_value': False
}

Comparison Result

PERFECT MATCH

  • All 10 properties present
  • Correct DomainValue wrapper
  • display_value = field_value.value (as expected)
  • active_from/active_to empty strings (correct)
  • expired_value = false (correct)

8. Text Field (ARTESIA.FIELD.ASSET DESCRIPTION)

Reference Structure

{
  "value": {
    "type": "string",
    "value": "PPRTEST"
  }
}

Code-Generated Structure

# Generated by: _set_field_value() for text fields at lines 537-538
{
    'value': {
        'type': 'string',
        'value': value
    }
}

Comparison Result

PERFECT MATCH

  • Simple two-level nesting
  • String type
  • No extra wrappers

9. System Field (ARTESIA.FIELD.ASSET NAME)

Reference Structure

{
  "cascading_domain_value": false,
  "domain_value": false,
  "is_locked": false,
  "value": {
    "type": "string",
    "value": "ROC_PPRTEST_EHI_4x5_DE_de.jpg"
  }
}

Code-Generated Structure

# Generated by: _set_field_value() for text fields at lines 537-538
{
    'value': {
        'type': 'string',
        'value': value
    }
}

Comparison Result

⚠️ MINOR DIFFERENCE

  • Missing: cascading_domain_value, domain_value, is_locked at top level
  • Impact: None (system field, likely added by DAM)
  • Recommendation: Optional - add wrappers for consistency

Suggested Enhancement:

{
    'cascading_domain_value': False,
    'domain_value': False,
    'is_locked': False,
    'value': {
        'type': 'string',
        'value': value
    }
}

10. System Field (ARTESIA.FIELD.ASSET_ID)

Reference Structure

{
  "cascading_domain_value": false,
  "domain_value": false,
  "is_locked": false,
  "value": {
    "type": "string",
    "value": "b5e69f3efdd81cd3a604708ed10c55a466d68b0e"
  }
}

Code-Generated Structure

# Same as ASSET NAME
{
    'value': {
        'type': 'string',
        'value': value
    }
}

Comparison Result

⚠️ MINOR DIFFERENCE (same as ASSET NAME)


Property Order Comparison

Example: Tabular Field Value Object

Reference:

{
  "field_value": {...},
  "type": "com.artesia.metadata.DomainValue"
}

Code:

{
  "type": "com.artesia.metadata.DomainValue",
  "field_value": {...}
}

Significance: NONE - JSON objects are unordered


Example: Domain Field Value Object

Reference:

{
  "active_from": "",
  "active_to": "",
  "display_value": "...",
  "expired_value": false,
  "field_value": {...},
  "type": "..."
}

Code:

{
  "type": "...",
  "active_to": "",
  "active_from": "",
  "field_value": {...},
  "display_value": "...",
  "expired_value": false
}

Significance: NONE - JSON objects are unordered


Summary of Differences

Field Type Structure Match Notes
Tabular (5 fields) PERFECT All match exactly
Domain (3 fields) PERFECT All properties present
Date (2 fields) PERFECT String type correct
Text (2 fields) PERFECT Simple structure
System (2 fields) ⚠️ MINOR Missing wrapper properties*

*Only difference: missing cascading_domain_value, domain_value, is_locked wrappers


Boolean Serialization

Python to JSON:

Python: True   JSON: true
Python: False  JSON: false

Handled automatically by json.dumps()


Conclusion

14/14 fields analyzed

Structural matches:

  • 12/14 PERFECT (85.7%)
  • ⚠️ 2/14 MINOR DIFFERENCE (14.3%)
  • 0/14 CRITICAL ISSUES (0%)

Overall Assessment: EXCELLENT - Production Ready

The code generates PPR payloads that match the client's reference structure in all critical aspects. The only minor differences are in system fields and are not expected to cause issues.


Files:

  • Detailed Report: PPR_COMPARISON_REPORT.md
  • Quick Summary: PPR_COMPARISON_SUMMARY.md
  • This Document: PPR_SIDE_BY_SIDE.md
  • Analysis Tool: compare_ppr_structure.py