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>
587 lines
12 KiB
Markdown
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`
|