Commit graph

44 commits

Author SHA1 Message Date
nickviljoen
9e92db185a Feature: Apply naming-tool pre-upload metadata overrides on A2→A3 upload
The naming tool's metadata editor saves pre-upload overrides to the
override_metadata table (shared ferrero_tracking DB), but until now the
Python upload pipeline never read from it — every edit was being saved
but never applied to DAM. This wires up the consumer side so user edits
land on the uploaded asset.

- database.py: get_override_metadata() / mark_override_applied(),
  resilient to a missing override_metadata table on dev DBs
- metadata_extractor_mvp.py: OVERRIDE_FIELD_MAP (mirrors the naming
  tool's editor-field → DAM-field-ID map) + _apply_override_fields().
  Applied after master/filename/forced/CreativeX values but before
  asset_type_overrides so EOL/LTD compliance still wins. Empty editor
  values are skipped (leaves inherited value alone). Validity ISO
  dates normalised to MM/DD/YYYY for DAM
- a2_to_a3_upload_polling.py: lookup before building the asset rep,
  pass override_fields into build_mvp_asset_representation, mark
  applied only after confirmed upload success

Override priority: user edit > master metadata > forced defaults >
hardcoded today+365 validity — so the team's per-asset validity
period (e.g. 1 month) now flows through end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 12:06:06 +02:00
nickviljoen
c12aef0eb1 Fix: Populate MAIN_LANGUAGES in folder-only mode (-N) uploads
Folder-only mode deep-copies the asset template with MAIN_LANGUAGES.values=[]
and never repopulated it from language_code, so the DAM rejected -N uploads
(SND/voiceover) with "Cannot set null value for a required field: MAIN_LANGUAGES".
Now mirrors the full-inheritance path's tabular values structure.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 21:19:09 +02:00
nickviljoen
b74c9c68aa Fix: EOL/LTD asset type overrides — IP Rights, CreativeX, descriptions
- LTD DAM code confirmed by client: licensingtranslationdocument (was placeholder)
- EOL + LTD: IP Rights forced to "No" (was "Yes")
- EOL + LTD: Remove CreativeX URL and score (not applicable to legal asset types)
- EOL: Description forced to "Legal Studio Name"
- Reorder _apply_asset_type_overrides() to run after _update_creativex_fields()
  so overrides have true final precedence (Box CreativeX was clobbering removals)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 13:24:19 +02:00
nickviljoen
0f49cc6cbc Enhancement: SDA (Supporting Documents for Approval) asset type
Adds SDA as a new asset type for License claim translations supporting
the EOL (External Legal Opinion) workflow.

- SDA maps to externallegalopinion in DAM (same as EOL).
- Field overrides match EOL (Agency = "-", Prod Company = "-",
  Languages = Global, IP Right = Yes, Licensing = No, validity dates
  removed) plus a fixed Description: "Translation of License claim -
  For approval purposes only".
- Added asset_type_overrides section to field_mappings_ppr.yaml; it
  was missing, so EOL overrides weren't actually applying on PPR.
  Both EOL and SDA blocks are now defined for both PPR and PROD.
- _apply_asset_type_overrides now appends a simple string field when
  the override targets a field not yet in mvp_fields, so the SDA
  description is set even if the filename has no subject_title.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 16:08:03 +02:00
nickviljoen
33e71be453 Fix: Template-based folder-only mode for -N flag uploads
Folder-only mode (-N suffix files) was sending minimal metadata that DAM
rejected with "unmarshalling parameter" error. Now uses a reference
asset_representation_template.json as the base for all metadata fields,
ensuring the full field structure (column_name, data_type, domain_id, etc.)
the DAM API requires. Also fixes default/forced value handling to use
DomainValue format for domained fields from the template.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:53:10 +02:00
nickviljoen
5905f3262a Fix: Folder-only mode metadata format for PROD DAM compatibility
Folder-only mode (-N suffix files) was sending simplified metadata that
PROD DAM rejected with "unmarshalling parameter" error. Updated to use
DomainValue format for domained fields, correct asset type field ID
(FERRERO.FIELD.MKTG.ASSET TYPE), asset type code mapping (e.g. SND→sound),
validity dates, and forced values from config.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 12:31:02 +02:00
nickviljoen
96b33fa084 Fix: Correct MARKETING_TAG parent_table_id in folder-only mode
Was generating FERRERO.TABULAR.FIELD.MARKETING_TAG (underscore) but DAM
expects FERRERO.TABULAR.FIELD.MARKETING.TAG (dot). Added explicit mapping
for tabular field parent table IDs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:13:11 +02:00
nickviljoen
6bc1b397d0 Fix: Use simple value structure for non-domain default fields in folder-only mode
VIDEO_POST_PROD_COMPANY and AUDIO_POST_PROD_COMPANY are not domain fields
but were being wrapped with DomainValue, causing unmarshalling errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:07:21 +02:00
nickviljoen
6e0bb08a5f Fix: Add type field to folder-only mode (-N) metadata values for DAM API
The _build_fields_from_filename method was using {"value": "..."} without
the required {"type": "string", "value": "..."} structure, causing
unmarshalling errors on the DAM API for -N suffix uploads.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:03:02 +02:00
nickviljoen
faa33cf44f Fix: Use DomainValue wrapper for non-tabular default fields in folder-only mode (-N)
Fixes unmarshalling error on DAM upload when using -N suffix files. The API
requires the DomainValue structure when domain_value is true.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:30:46 +02:00
nickviljoen
8299a87180 Fix: Update MAIN_LANGUAGES values array for tabular fields in DAM upload
The filename_updates logic was only updating field['value'] (singular) but for
tabular fields like MAIN_LANGUAGES, the DAM reads from field['values'] (plural
array). This caused the master's original language (e.g. "Global") to persist
instead of the correct language from the filename (e.g. "PL").

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:26:31 +02:00
nickviljoen
74141689e6 Enable FERRERO.MASTERASSETIDS and multi-master support for PROD
Remove PPR-only gates so PROD supports the same MASTERASSETIDS tabular
field and multi-master ID parsing as PPR. DAM deployment scheduled for
Feb 18 — do not push until then.

Changes:
- filename_parser: Remove is_ppr check, allow multi-master ID parsing in PROD
- a2_to_a3: Populate master_opentext_ids for single-master PROD case
- dam_client: Remove PPR-only skip on domain registration
- metadata_extractor_mvp: Update docstrings only

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:12:30 +02:00
nickviljoen
636b555d9d Fix: Define master_opentext_ids variable in A2→A3 and add multi-master support
The PROD a2_to_a3 script referenced master_opentext_ids without defining it,
causing NameError for all file uploads. Brings in multi-master tracking ID
support from PPR: filename parser handles multiple IDs (PPR) or single ID
(PROD), metadata extractor supports MASTERASSETIDS tabular field.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 11:37:18 +02:00
nickviljoen
04eccab9e7 Enhancement: Add environment-specific configurations and metadata improvements
This commit includes critical updates for PPR deployment:

1. Environment-Specific Field Mappings:
   - Created field_mappings_ppr.yaml with agency code "Oliver"
   - Created field_mappings_prod.yaml with agency code "0000221659"
   - Updated config_loader.py to auto-detect environment based on DAM URL
   - Enables seamless deployment between PPR and PROD environments

2. Metadata Extractor Enhancements:
   - Added MetadataTable extraction support for nested fields
   - Enables extraction of "Type of Video & Static Right" multi-value field
   - Added logic to apply defaults to existing but empty fields
   - Fixed agency name display_value handling for domain fields

3. Default Values Added:
   - VIDEO_POST_PROD_COMPANY: "Oliver Marketing Ltd"
   - AUDIO_POST_PROD_COMPANY: "Oliver Marketing Ltd"
   - PROD_COMPANY (Production House): "-"

These changes ensure:
- Correct agency codes per environment (PPR/PROD)
- Proper extraction of nested tabular fields
- Default values for empty production company fields
- Seamless deployment workflow

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-28 20:41:21 +02:00
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
DJP
5a2273459c Fix: Restore MAIN_LANGUAGES and defaults to exact working structure from before Jan 19 changes 2026-01-20 08:37:41 -05:00
DJP
827a90ae71 Fix: Restore field_value wrapper to MAIN_LANGUAGES and defaults - revert to working structure 2026-01-20 08:06:52 -05:00
DJP
e77a385cce Fix: Remove field_value wrapper from MAIN_LANGUAGES to resolve null value error 2026-01-19 12:07:43 -05:00
DJP
a74d0914f9 Fix: Change date field type from 'date' to 'string' for MM/DD/YYYY format 2026-01-19 11:59:13 -05:00
DJP
4279bbc229 Fix: Correct JSON nesting for MAIN_LANGUAGES and Default Tabular Fields 2026-01-19 11:55:58 -05:00
DJP
c01b69e2fb Fix: Add MetadataTableFieldRow wrapper to all Tabular Fields (MAIN_LANGUAGES, CreativeX, Defaults) 2026-01-19 11:50:33 -05:00
DJP
4a1a4fffa0 Fix: Update Asset Validity date format to MM/DD/YYYY 2026-01-19 11:38:23 -05:00
DJP
fae3111467 Fix: Update Asset Validity date format to YYYY-MM-DD 2026-01-19 11:23:33 -05:00
DJP
e2c2719055 Fix: Add MetadataTableFieldRow wrapper to Tabular Master Asset ID field 2026-01-19 10:51:20 -05:00
DJP
4b5cb0a98a Fix: Correct inner column ID for Tabular Master Asset ID field 2026-01-19 10:45:47 -05:00
DJP
ee6afe0888 Feat: Configurable Master Asset ID & Fix Date Type 2026-01-19 09:40:55 -05:00
DJP
0f984f3d7b Fix: Update asset validity date format to ISO-8601 string 2026-01-16 13:53:41 -05:00
DJP
222a53f466 Fix date field type error for ASSET VALIDITY START/END PERIOD
- Convert dates to milliseconds since epoch (Unix timestamp × 1000)
- Change field type from 'string' to 'long' for DATE fields
- Add _set_date_field_value() helper method for proper date handling
- Fixes 'java.lang.String was specified. Expecting java.util.Date' error
- Applies to A2->A3 uploads
2025-12-19 23:02:55 -05:00
DJP
599d468e44 Add Master Asset ID field to A2→A3 uploads
- Added ARTESIA.FIELD.ASSET_ID to MVP fields in field_mappings.yaml
- Updated metadata_extractor_mvp.py to accept master_opentext_id parameter
- Added _add_master_asset_id_field() and _get_field_id() helper methods
- Modified a2_to_a3_upload_polling.py to pass master asset's opentext_id
- Field is populated with original master asset's DAM ID for derivative tracking
- Field is omitted for new assets (tracking ID with -N suffix)
- Covers both A2→A3 standard derivatives and A5→A6 reworked assets
2025-12-15 17:28:30 -05:00
DJP
bce739d116 feat: Automatically set asset validity dates in the metadata extractor and update the agency name in field mappings. 2025-12-03 14:28:59 -05:00
DJP
c1f338022c fix: Ensure type field is added when updating CreativeX URL
- Modified _set_field_value to include 'type': 'string' in all code paths
- Adds type field when updating existing CreativeX URL field
- Ensures consistent structure whether creating or updating field
2025-11-25 09:14:25 -05:00
DJP
80316cad32 fix: Add missing type field to CreativeX URL metadata
- Added 'type': 'string' to FERRERO.FIELD.CREATIVEX LINK value structure
- Fixes DAM validation error for CreativeX URL field
- Structure now matches DAM requirements
2025-11-25 09:11:41 -05:00
DJP
548c30344b feat: Support multiple CreativeX platforms in metadata
- Updated creativex_scoring_storing.py to map multiple placements to platforms
- Modified get_mapped_platform to get_mapped_platforms (returns list)
- Updated a2_to_a3_upload_polling.py to retrieve platforms list from DB
- Enhanced metadata_extractor_mvp.py to build multi-value CreativeX field
- Added DAM-CX mappings.csv for channel/placement to platform mapping
- Supports single channel with multiple placements generating multiple Platform^Score values
2025-11-24 14:44:11 -05:00
DJP
0bf3c34cd0 Add asset type mapping from 3-letter codes to DAM codes
Maps frontend naming tool 3-letter codes (EHI, IMG, TVC) to DAM's
lowercase descriptive codes (heroimage, keyvisual, tvc) for uploads.

New File: config/asset_type_mappings.yaml
- 45 asset type mappings from DAM lookup domains
- Maps 3-letter codes to DAM codes
- E-Commerce types: EHI→heroimage, EBS→beautyshot, etc.
- Standard types: IMG→keyvisual, TVC→tvc, etc.
- Expandable as new asset types added

Field Mappings Update (field_mappings.yaml):
- Added FERRERO.FIELD.MKTG.ASSET TYPE to filename_updates
- Source: asset_type (from parsed filename)
- Required: true

Metadata Extractor Updates (metadata_extractor_mvp.py):
- Added _load_asset_type_mappings() method
- Added _map_asset_type() method
- Integrated mapping into _update_fields()
- Logs mappings: "Asset type mapping: EHI -> heroimage"
- Warns if no mapping found (may fail DAM validation)

Example Flow:
1. Filename: ROC_TEST-E2E2_EHI_1x1_DE_de.png
2. Parse: asset_type = "EHI"
3. Map: EHI → "heroimage"
4. Update field: FERRERO.FIELD.MKTG.ASSET TYPE = "heroimage"
5. DAM accepts "heroimage" (valid domain value)

Without Mapping (before):
- Field value: "EHI"
- DAM validation: FAILS (EHI not in domain)

With Mapping (after):
- Field value: "heroimage"
- DAM validation: PASSES 

Complete Mapping List (45 types):
E-Commerce: ECA, ECB, EBS, EBR, EEM, EHI, EIL, EOP, EUG, EWB
Standard: 3RT, APC, BBK, BRC, BSG, CKV, CID, DAT, FLA, FNT, GDT,
         GRG, IMG, FPO, LGL, LOG, MLF, OLV, PAW, PKI, POS, PDM,
         PRI, QRC, SND, SIP, SGL, TVC, VIE

DAM Answer: Uses descriptive lowercase codes, not 3-letter codes.
Frontend uses 3-letter for brevity, backend maps to DAM format.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 13:08:01 -05:00
DJP
d1ab8551e5 Add asset type filename update and make field updates configurable
Enables asset type to be updated from derivative filename and refactors
_update_fields() to use filename_updates configuration dynamically.

Field Mappings Configuration (field_mappings.yaml):

Added to filename_updates:
- FERRERO.FIELD.MKTG.ASSET TYPE:
    source: asset_type
    required: true

Now updates from derivative filename:
- ROC_TEST-E2E2_EHI_1x1_DE_de.png → Asset Type = "EHI"

Metadata Extractor Refactor (metadata_extractor_mvp.py):

Old _update_fields():
- Hardcoded field updates (ASSET NAME, DESCRIPTION, STATE)
- Not using filename_updates configuration
- Required code changes to add new fields

New _update_fields():
- Dynamically processes filename_updates from config
- Supports transform: uppercase/lowercase
- Supports any source field from parsed_filename
- Uses forced_values from config (was hardcoded before)
- Add new fields via config, no code changes needed

Configuration-Driven Updates:
- ARTESIA.FIELD.ASSET NAME ← clean_filename
- ARTESIA.FIELD.ASSET DESCRIPTION ← subject_title
- FERRERO.FIELD.MKTG.ASSET TYPE ← asset_type (NEW)
- MAIN_LANGUAGES ← language_code (uppercase)
- FERRERO.FIELD.STATE ← "Local" (forced value)

Benefits:
- Asset type now correctly populated from filename
- Configuration-driven (add fields without code changes)
- Cleaner code (uses config instead of hardcoded logic)
- Forced values also configurable
- Easier to maintain and extend

Example:
Filename: ROC_TEST-E2E2_EHI_1x1_DE_de.png
Parsed asset_type: "EHI"
Field FERRERO.FIELD.MKTG.ASSET TYPE updated to: "EHI"

Impact:
All A2→A3 uploads will now have correct Asset Type from derivative
filename instead of inheriting from master (which may be different).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 12:58:10 -05:00
DJP
15eb47fc43 Add CreativeX fields to asset representation if missing from master metadata
Fixes issue where CreativeX score field was not appearing in final upload
because it didn't exist in the master metadata from DAM.

Problem:
- Master metadata from A1→A2 doesn't include CREATIVEX fields (new fields)
- _update_creativex_fields() only UPDATED existing fields
- If field not present, it logged error but didn't add the field
- Result: CREATIVEX score missing from upload, only URL appeared

Solution:
- Check if CREATIVEX Score field exists in mvp_fields
- If NOT found: Create and append field with proper structure
- If found: Update value as before
- Same logic for CREATIVEX URL field

Field Structures Created:

CREATIVEX Score (FERRERO.TAB.FIELD.CREATIVEX):
- Type: MetadataTableField (tabular field)
- Parent: FERRERO.TABULAR.FIELD.PLATFORMRATING
- Data type: INTEGER
- Value structure: {'value': {'value': score}}

CREATIVEX URL (FERRERO.FIELD.CREATIVEX LINK):
- Type: MetadataField (regular field)
- Data type: CHAR
- Value structure: {'value': {'value': url}}

Logging:
- Changed from ERROR to WARNING when field not found
- Logs "adding it now" instead of just error
- Confirms field added with value

Impact:
Both CreativeX fields will now appear in uploads even if master
metadata doesn't have them (common for older campaigns downloaded
before CreativeX integration).

Testing:
Run with --dryrun to verify both CREATIVEX fields in JSON output.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 12:44:17 -05:00
DJP
2fef8878cd Add verbose debugging to _set_field_value for CreativeX troubleshooting
Adds detailed logging to trace exactly how field values are being set
and diagnose why CreativeX score/URL aren't appearing in final JSON.

Changes to _set_field_value():
- Logs field ID being updated
- Logs current field['value'] structure BEFORE setting
- Logs which code path is taken (nested vs created)
- Logs field['value'] structure AFTER setting
- Shows full JSON structure at each step

Output Example:
_set_field_value called for: FERRERO.TAB.FIELD.CREATIVEX with value: 85
Current field['value']: {
  "is_locked": false,
  "domain_value": false,
  ...
}
Created field['value'] = {'value': {'value': 85}}
After setting, field['value']: {
  "value": {
    "value": 85
  }
}

Purpose:
Diagnose why CreativeX fields show empty value dicts in asset
representation even though logs say "Set CREATIVEX Score to: 0".

This verbose logging will show:
1. What the field structure looks like before we set it
2. Which code path is executed
3. What the field structure looks like after we set it
4. Whether the value is actually being placed in the right location

Run with --dryrun to see full debug output without uploading.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 12:16:53 -05:00
DJP
d3722d1bb2 Fix CreativeX URL logging to say 'from database' not 'from Box'
Corrects misleading log messages and adds debugging for URL field.

Changes:
- Changed: "Updating CreativeX URL from Box"
- To: "Updating CreativeX URL from database"
- Added url_field_found flag
- Added URL field structure logging
- Added error handling with traceback
- Logs error if URL field not found in mvp_fields

Now both CreativeX fields log correctly:
- "Updating CreativeX Score from database: 0"
- "Updating CreativeX URL from database: https://..."

Accurate logging shows data source is PostgreSQL creativex_scores
table, not Box metadata templates (which are no longer used).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 12:11:58 -05:00
DJP
899d15322b Improve CreativeX field value setting with better error handling
Enhances _set_field_value() to handle empty value structures and
adds detailed logging for debugging CreativeX field issues.

Changes to metadata_extractor_mvp.py:

_set_field_value() Enhancement:
- Handles empty nested dicts by creating value structure
- If field['value']['value'] is empty dict, creates {'value': value}
- If field['value'] is empty dict, creates {'value': {'value': value}}
- Preserves existing behavior for populated structures

CreativeX Score Field Debugging:
- Added score_field_found flag to detect if field exists in mvp_fields
- Logs field structure before attempting to set value
- Shows dict keys to understand nesting
- Catches and logs full traceback on errors
- Errors if CREATIVEX Score field not found in mvp_fields
- Changed log: "from Box" → "from database" (accurate)

CreativeX URL Field:
- Existing logic preserved
- Uses same enhanced _set_field_value()

Purpose:
Diagnose why CreativeX score not appearing in asset representation
even though logs show "Set CREATIVEX Score to: 0"

Next Steps:
Run with --dryrun to see field structure logging and verify values
are being set correctly in the JSON output.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 12:11:22 -05:00
DJP
60a2f09e42 Add CreativeX fields to MVP and fix score update logic
Added CreativeX fields to MVP fields list:
- FERRERO.TAB.FIELD.CREATIVEX (CreativeX Score from Box)
- FERRERO.FIELD.CREATIVEX LINK (CreativeX URL from Box)

Fixed _update_creativex_fields method:
- Now actually SETS CreativeX Score value (was only logging before)
- Uses _set_field_value() to update the field
- Added try/except for tabular field structure handling
- Both score and URL now properly set from Box metadata

Flow:
1. Box metadata retrieved from Ferrero-DAM-Metadata template
2. creativexScore and creativexUrl extracted
3. Passed to metadata extractor
4. Applied to MVP fields during upload
5. CreativeX data preserved from Box → DAM

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 13:54:39 -05:00
DJP
d5c71b4c45 Add country code mapping system (ISO -> DAM codes)
- Created config/country_code_mappings.yaml with 165 country mappings
- ISO codes (used in filenames) now map to DAM-specific codes
- Codes under review set to XX as placeholder
- Added load_country_code_mappings() to config_loader.py
- Updated MetadataExtractorMVP to load and apply country mappings
- Added _map_country_code() and _get_field_value() helper methods
- Country mapping applies in both full and folder-only modes

Key mappings:
- BD (Bangladesh) -> BG (DAM code, though appears incorrect)
- DE (Germany) -> DE (same)
- IT (Italy) -> IT (same)
- Most codes under review -> XX (placeholder)

Mapping file can be edited without code changes - updates apply automatically

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 19:15:26 -05:00
DJP
914a178dc5 Implement V2 naming convention updates and folder structure support
Major changes:
1. Updated filename_parser.py for new V2 naming convention:
   - Spot version now accepts only MST or REF (optional)
   - Duration field is now optional
   - Tracking ID supports -N suffix for folder-only mode
   - Reduced minimum required parts from 9 to 7
   - Improved asset type detection logic

2. Added recursive folder scanning to box_client.py:
   - New list_folder_files_recursive() method
   - Skips first-level job/batch folders
   - Preserves folder structure from 2nd level onwards
   - Skips hidden folders (starting with . or _)

3. Updated A2→A3 upload workflow:
   - Uses recursive folder scanning
   - Extracts and logs tracking mode (full vs folder_only)
   - Handles subfolder paths for DAM uploads
   - Shows folder distribution in logs

4. Added folder-only mode to metadata_extractor_mvp.py:
   - New tracking_mode parameter (full/folder_only)
   - folder_only mode builds metadata entirely from filename
   - New _build_fields_from_filename() method

5. Added DAM subfolder creation to dam_client.py:
   - New get_or_create_subfolder_path() method
   - Creates matching folder structure in DAM
   - Helper methods _find_subfolder_by_name() and _create_folder()

Folder structure behavior:
- Box: DAM-UPLOAD/1234567/Europe/Germany/file.mp4
- DAM: 01. Final Assets/Europe/Germany/file.mp4
- Job folder (1234567) is skipped, structure preserved from 2nd level

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 18:33:35 -05:00
DJP
80d5757bbb Add Box metadata extraction for CreativeX fields in A2→A3 workflow
Major Feature: Box Metadata Integration

box_client.py:
 Added get_file_metadata() method
 Reads 'Ferrero-DAM-Metadata' template from Box files
 Extracts 'CreativeX Score' and 'CreativeX URL' fields
 Returns dict with score and url

a2_to_a3_upload_polling.py:
 Calls box.get_file_metadata() before download
 Logs Box metadata retrieved
 Passes box_metadata to build_mvp_asset_representation()

metadata_extractor_mvp.py:
 Added box_metadata parameter to build_mvp_asset_representation()
 Added _update_creativex_fields() method
 Updates FERRERO.FIELD.CREATIVEX LINK with URL from Box
 Logs CreativeX Score (tabular field - needs special handling)

Flow:
1. File uploaded to Box by agency
2. Agency adds metadata using Ferrero-DAM-Metadata template
3. Script reads CreativeX Score and URL from Box metadata
4. Updates MVP fields with Box metadata values
5. Uploads to DAM with CreativeX data

Field Mapping:
- Box: 'CreativeX URL' → DAM: FERRERO.FIELD.CREATIVEX LINK
- Box: 'CreativeX Score' → DAM: FERRERO.TAB.FIELD.CREATIVEX (logged, needs structure)

Next: Test with file that has Box metadata template applied

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 14:26:00 -05:00
DJP
b4e004c822 Complete Python automation implementation - All components built
MAJOR MILESTONE: Complete Python automation system created!

Components Implemented:
 Box Client (box_client.py)
   - JWT authentication via boxsdk
   - Upload with tracking ID suffix
   - Download files
   - Campaign folder creation
   - Connection testing

 Database Client (database.py)
   - PostgreSQL connection pooling
   - generate_unique_tracking_id()
   - store_master_asset() with full_metadata JSONB
   - get_master_asset(tracking_id)
   - check_campaign_upload_complete() - ALL-DONE CHECK!
   - store_derivative_asset()
   - Connection testing

 Filename Parser (filename_parser.py)
   - V2 naming convention parser (ported from PHP)
   - parse_filename() - 10 components
   - strip_upload_components() - Remove Job# and Tracking ID
   - Strict validation with detailed errors

 Metadata Extractor MVP (metadata_extractor_mvp.py)
   - Extract 28 MVP fields from master
   - Update fields from V2 filename (Description, Language, State)
   - Add missing fields with defaults
   - Build asset representation for upload

 Notifier (notifier.py)
   - Mailgun email integration
   - Outgoing webhook sender
   - Email templates (success, error, partial, critical)
   - Configurable recipients

Main Scripts:
 A1→A2 Download (a1_to_a2_download.py)
   - Poll DAM every 5 minutes for A1 campaigns
   - Download all master assets
   - Upload to Box with tracking IDs
   - Store in DB with full metadata
   - ALL-DONE CHECK before status update
   - Update A1→A2 only if all assets successful
   - Send webhook with campaign ID/number
   - Email notifications

 A2→A3 Upload (a2_to_a3_upload.py)
   - Flask webhook receiver for Box uploads
   - Signature validation
   - Async task queue processing
   - Parse V2 filenames
   - Load master metadata
   - Extract MVP fields
   - Upload to DAM
   - ALL-DONE CHECK for campaign
   - Update A2→A3 when all assets uploaded
   - Send webhook notifications

 Test Connection Script (test_connection.py)
   - Verify DAM, Box, Database connectivity
   - Quick health check

 README.md
   - Complete setup guide
   - Usage instructions
   - Configuration examples
   - Troubleshooting

Key Features:
- Python 3.6+ compatible (server requirement)
- Virtual environment isolated
- Configuration-driven (YAML files)
- Easy field updates (no code changes)
- Environment switching (staging/production)
- Comprehensive error handling
- Email + webhook notifications
- Retry logic
- All-done checks before status updates
- Campaign webhook notifications

Ready for testing locally with Python 3.10!

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 16:49:14 -04:00