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>
Major enhancements to all workflow scripts with recursive search and detailed rejection tracking.
NEW FEATURES:
1. Recursive Folder Search (ALL workflows: A1→A2, A5→A6, B1→B2)
- Searches subfolders within Master/Final Assets folders
- Preserves folder structure in Box
- Adds 'folder_path' attribute to each asset
2. NOT APPROVED Filtering (A5→A6 ONLY)
- Only downloads assets with ECOMMERCE STATUS = "NOT APPROVED"
- Skips approved/other status assets
- Logs rejected vs skipped counts
3. Rejection Details Extraction (A5→A6)
- Extracts comments from 3 reviewers: Approver, Legal, IA&CC
- Includes certifier names and dates
- Displays in detailed email notifications
CHANGES BY FILE:
dam_client.py:
- NEW: _get_assets_recursive() - Recursively searches folders
- UPDATED: get_master_assets() - Now uses recursive search, adds folder_path to assets
- NEW: is_asset_not_approved() - Checks FERRERO.FIELD.ECOMMERCE STATUS
- NEW: extract_rejection_details() - Extracts all rejection comments from 10 fields
box_client.py:
- UPDATED: upload_with_tracking_id() - Added subfolder_path parameter
- NEW: _get_or_create_subfolder_path() - Creates/navigates Box subfolders
- Preserves DAM folder structure in Box uploads
a1_to_a2_download.py:
- Added folder_path extraction from assets
- Pass subfolder_path to Box upload
- Logs subfolder info during processing
b1_to_b2_download.py:
- Added folder_path extraction from assets
- Pass subfolder_path to Box upload
- Logs subfolder info during processing
a5_to_a6_download.py:
- Filter assets for NOT APPROVED status ONLY
- Extract rejection details for each asset
- Pass subfolder_path to Box upload
- Updated email data with rejection_details
- Handle "no rejections" scenario with email
- Updated logging to show rejected vs skipped counts
notifier.py:
- REPLACED: a5_to_a6_complete → a5_to_a6_rejections
- Detailed HTML template with rejection sections
- Shows Approver, Legal, and IA&CC rejections
- Styled with red warnings and bordered sections
- NEW: a5_to_a6_no_rejections template
- Green success message when no rejected assets found
- UPDATED: a5_to_a6_partial - Now uses rejected_assets
FIELD IDs EXTRACTED (A5→A6):
- FERRERO.FIELD.ECOMMERCE STATUS (primary check)
- FERRERO.MARKETING.FIELD.CERTIFIER COMMENT
- FERRERO.FIELD.ECOMMERCE CERTIFIER
- FERRERO.MARKETING.FIELD.APPROVAL DATE
- FERRERO.MARKETING.FIELD.LEGAL COMMENT
- FERRERO.FIELD.LEGAL CERTIFER (typo in field ID)
- FERRERO.MARKETING.FIELD.LEGAL APPROVAL DATE
- FERRERO.MARKETING.FIELD.IA CC COMMENT
- FERRERO.MARKETING.FIELD.IA CERTIFIER
- FERRERO.MARKETING.FIELD.IA CC APPROVAL DATE
TESTING:
✓ All connections working (DAM, Box, Database)
✓ A5→A6 script executes correctly
✓ Recursive search working
✓ NOT APPROVED filtering working
✓ "No rejections" email sent successfully
✓ Folder structure preserved in logs
WORKFLOW IMPACTS:
- A1→A2: Now searches recursively, preserves folder structure
- A5→A6: Filters for NOT APPROVED only, shows rejection details
- B1→B2: Now searches recursively, preserves folder structure
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Box Metadata Extraction Fixed:
Template Name:
❌ Was: 'Ferrero-DAM-Metadata' (with dashes and caps)
✅ Now: 'ferrerodammetadata' (lowercase, no dashes)
Field Names:
❌ Was: 'CreativeX Score', 'CreativeX URL'
✅ Now: 'creativexScore', 'creativexUrl' (camelCase)
Test Results with File 2035459900168:
✅ Template found successfully
✅ creativexScore: 90
✅ creativexUrl: https://www.bbc.com✅ Metadata extraction working!
A2→A3 workflow will now:
1. Download file from Box
2. Read ferrerodammetadata template
3. Extract creativexScore and creativexUrl
4. Update CREATIVEX fields in asset representation
5. Upload to DAM with CreativeX data
Test: Upload a file to Box with ferrerodammetadata template applied
and the A2→A3 script will extract and use those values!
🤖 Generated with Claude Code
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>
Created a2_to_a3_upload_polling.py:
- Polls Box folder (348526703108) instead of webhook
- Works locally (no need for public URL)
- Single-run mode (process one file and exit)
- Can be run via cron every 5 minutes
Why Polling Instead of Webhook:
- Webhooks require public URL (doesn't work on localhost)
- Polling works everywhere (local and server)
- Same functionality, different trigger mechanism
Database Fix:
- Don't create new columns (dam_asset_id, upload_status)
- Use existing schema: tracking_id, derivative_filename, file_extension, status
- Simplified store_derivative_asset() to use existing columns only
- Database now compatible with existing schema
Test Results - A2→A3 Polling:
✅ Polls Box folder 348526703108
✅ Finds V2 files with tracking IDs
✅ Downloads from Box
✅ Loads master metadata from PostgreSQL
✅ Builds 27 MVP fields
✅ Updates Description, State, Language from filename
✅ Uploads to DAM successfully (Asset ID: 214924)
✅ Stores derivative record
✅ Processes one file and exits
Both Scripts Working:
✅ A1→A2: Downloads from DAM → Box (folder 348304357505)
✅ A2→A3: Uploads from Box → DAM (folder 348526703108)
Cron Setup:
*/5 * * * * python scripts/a1_to_a2_download.py
*/5 * * * * python scripts/a2_to_a3_upload_polling.py
Complete automation ready for production!
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Issue: Box folders were named with hex asset ID instead of campaign ID
Example Wrong: 7e2f7c97b003f91f8b2a162b9f62ccab51586fa9_Local_adaptation_test_2
Example Correct: C000000078-Local_adaptation_test_2
Fixes:
1. Use campaign_number (C000000078) instead of campaign_id (hex) for Box folder
2. Change separator from underscore to dash (C000000078-Campaign_Name)
The confusion:
- campaign_id variable = DAM asset_id (hex string for API calls)
- campaign_number variable = actual campaign ID (C000000078)
Now Box folders will be named correctly: C000000078-Local_adaptation_test_2
🤖 Generated with Claude Code