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

587 lines
12 KiB
Markdown

# 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
```json
{
"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
```python
# 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
```json
{
"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
```python
# 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
```json
{
"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
```python
# 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
```json
{
"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
```python
# 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
```json
{
"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
```python
# 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
```json
{
"value": {
"type": "string",
"value": "01/22/2026"
}
}
```
### Code-Generated Structure
```python
# 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
```json
{
"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
```python
# 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
```json
{
"value": {
"type": "string",
"value": "PPRTEST"
}
}
```
### Code-Generated Structure
```python
# 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
```json
{
"cascading_domain_value": false,
"domain_value": false,
"is_locked": false,
"value": {
"type": "string",
"value": "ROC_PPRTEST_EHI_4x5_DE_de.jpg"
}
}
```
### Code-Generated Structure
```python
# 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:**
```python
{
'cascading_domain_value': False,
'domain_value': False,
'is_locked': False,
'value': {
'type': 'string',
'value': value
}
}
```
---
## 10. System Field (ARTESIA.FIELD.ASSET_ID)
### Reference Structure
```json
{
"cascading_domain_value": false,
"domain_value": false,
"is_locked": false,
"value": {
"type": "string",
"value": "b5e69f3efdd81cd3a604708ed10c55a466d68b0e"
}
}
```
### Code-Generated Structure
```python
# 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:**
```json
{
"field_value": {...},
"type": "com.artesia.metadata.DomainValue"
}
```
**Code:**
```json
{
"type": "com.artesia.metadata.DomainValue",
"field_value": {...}
}
```
**Significance:****NONE** - JSON objects are unordered
---
### Example: Domain Field Value Object
**Reference:**
```json
{
"active_from": "",
"active_to": "",
"display_value": "...",
"expired_value": false,
"field_value": {...},
"type": "..."
}
```
**Code:**
```json
{
"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
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`