Commit graph

186 commits

Author SHA1 Message Date
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
51e915e67c Add global_master_tracking_id to link A1→A2 local assets to B1→B2 global masters
A1→A2 now looks up the opentext_id in master_assets for an M-prefixed record
from B1→B2 and stores it as global_master_tracking_id on the local asset record.
This provides traceability from local campaign assets back to their global master
without changing any existing workflow logic or DAM metadata.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:12:55 +02:00
nickviljoen
78a4ca0976 Fix: CreativeX score supersede now matches base filename ignoring timestamp suffix
Previously, re-scored assets with a DAM timestamp suffix (e.g. _2026-03-13-05-53-36)
were treated as new files, leaving multiple 'active' records. Now strips the timestamp
and uses LIKE matching so all variants of the same base asset are properly superseded.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 21:12:50 +02:00
nickviljoen
4dded5de14 Fix: Send Mailgun API emails one recipient at a time
Mailgun silently drops emails with multiple recipients in the to field.
Send individual API calls per recipient and split comma-separated addresses.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 13:39:55 +02:00
nickviljoen
dc779724fc Add Mailgun API support for PROD email notifications
Mailgun API is used when MAILGUN_API_KEY and MAILGUN_DOMAIN are set,
with SMTP as fallback for PPR. Also fixes A2→A3 batch subject line
that was rendering Jinja2 syntax literally instead of substituting values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 14:39:16 +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
63e42d1196 Fix: Don't send generic CreativeX URL when no score exists
When no CreativeX score is found for a file, the system was sending a
generic placeholder URL (app.creativex.com/preflight/pretests) to the DAM.
Now sends no URL at all, so only files with actual CreativeX scores get a URL.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 17:42:57 +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
f6c84762ae Fix: Map CreativeX API channel/publisher to DAM platform names for PROD
The new CreativeX API format stores channel/publisher at the top level
of full_extraction_data instead of inside a data.ferrero_mapped_platforms
wrapper. Add fallback mapping so platforms are correctly populated for
DAM uploads.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 17:43:58 +02:00
nickviljoen
052558961a Revert "Fix: Add YouTube platform mapping and social media code fallback for CreativeX"
This reverts commit 799b6d50e8.
2026-02-13 17:17:06 +02:00
nickviljoen
799b6d50e8 Fix: Add YouTube platform mapping and social media code fallback for CreativeX
YouTube Ads was missing from the DAM-CX mappings CSV, causing empty
Platform > Rating fields for YouTube assets. Also adds a fallback that
derives the CreativeX platform from the filename social media code (e.g.
YTA -> YouTube) when the database has no mapped platforms.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 17:00:47 +02:00
nickviljoen
9dbb7ce8d9 Revert "Fix: Re-enable FERRERO.MASTERASSETIDS field for PROD single-master uploads"
This reverts commit ea85749e0a.
2026-02-13 16:41:57 +02:00
nickviljoen
ea85749e0a Fix: Re-enable FERRERO.MASTERASSETIDS field for PROD single-master uploads
Populates master_opentext_ids for single-master case so uploads use the
tabular FERRERO.MASTERASSETIDS field instead of the ARTESIA.FIELD.ASSET_ID
fallback. Reverts the workaround from 6517a4f now that the field is being
configured in PROD DAM.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 14:20:01 +02:00
nickviljoen
98826d51c4 Fix: CreativeX tracking ID fallback, filename stripping, and social media codes
CreativeX lookup now falls back to tracking ID search when filename match fails
(handles mismatched naming from CreativeX PDFs). strip_upload_components now
only removes job number and tracking ID, keeping social media codes (YTA, DV3,
etc.) in the clean filename. Updated SOCIAL_MEDIA_CODES from 4 to 39 codes
sourced from the Ferrero naming tool.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 13:24:23 +02:00
nickviljoen
6517a4f83f Fix: Skip FERRERO.MASTERASSETIDS field on PROD - field not yet configured
PROD DAM rejects FERRERO.MASTERASSETIDS as it only exists in PPR. Remove the
single-master-to-list conversion so PROD uses the existing single-ID field
(master_opentext_id) instead. Will be re-added when client configures the
tabular field in PROD.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 12:33:43 +02:00
nickviljoen
27916062ff Fix: Pass notifier to process_box_file and use case-sensitive Master ID check
The notifier variable was referenced inside process_box_file but never passed
as a parameter, causing NameError for any file hitting the Master Tracking ID
check. Also changed the check from case-insensitive (.upper().startswith('M'))
to case-sensitive (.startswith('M')) to avoid false positives on random tracking
IDs like mviSv5.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 11:49:21 +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
d72d37a83d Enhancement: Campaign re-opening support and PPR master asset ID registration
A1→A2 now handles re-processing when campaign is reset to A1 after adding new
master assets. Existing assets reuse tracking IDs and skip Box upload, new assets
are processed normally. Also includes PPR domain registration for multiple master
asset IDs in a2_to_a3 and dam_client.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-05 21:07:13 +02:00
nickviljoen
57b4df2799 Security: Remove database password from permanently failed email template
Replace exposed database credentials and SQL commands in A1 permanently failed notification email with support contact information (optical@oliver.agency).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-02 07:24:49 +02:00
nickviljoen
c90032b1d9 Fix: A1 retry logic now catches folder not found errors
Problem:
- Retry logic only triggered for empty folders (total_assets == 0)
- When "Master Assets" folder doesn't exist, error thrown BEFORE retry check
- Exception caught by outer try/except, sent old upload_failed template
- No database tracking, emails sent every 3 minutes indefinitely

Solution:
- Added retry logic to outer exception handler
- Detects folder/assets errors and applies same 3-attempt tracking
- Now handles both: (1) folder doesn't exist, (2) folder is empty
- Database tracking works for both scenarios

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-31 19:34:29 +02:00
nickviljoen
e1f15ea632 Add A1 retry logic and orchestrator off-hours cadence
Feature 1: A1→A2 Empty Folder Retry Logic
- Track retry attempts (max 3) for campaigns with no master assets
- Mark campaigns as permanently failed after 3 attempts
- Stop processing and sending emails for permanently failed campaigns
- Two new email templates: retry notification and permanent failure
- Database migration adds 4 new columns to campaign_status table
- Comprehensive documentation in A1_RETRY_LOGIC.md

Feature 2: Orchestrator Off-Hours Cadence
- Add 30 minutes to all task intervals during off-hours
- Off-hours: 10 PM - 5 AM weekdays + all day Saturday/Sunday
- Tasks only run at minutes 0 and 30 during off-hours
- Configurable and easy to enable/disable
- Daily Report (7 PM) remains unchanged

Files changed:
- NEW: database/migrations/003_add_a1_retry_tracking.sql
- NEW: MARKDOWN_DOCS/A1_RETRY_LOGIC.md
- MODIFIED: scripts/shared/database.py (added 3 methods)
- MODIFIED: scripts/a1_to_a2_box_uploader.py (added retry logic)
- MODIFIED: scripts/shared/notifier.py (added 2 templates)
- MODIFIED: scripts/orchestrator-prod.py (added off-hours config)
- MODIFIED: RUN_ORCHESTRATOR.md (added off-hours docs)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-31 17:38:57 +02:00
nickviljoen
b7e0430636 Fix: Prevent DAM folder creation attempts causing timeouts
Remove folder creation logic in get_or_create_subfolder_path() since DAM does not allow folder creation via API. When a subfolder doesn't exist, upload to the parent folder instead of attempting to create it (which was causing 120 second timeouts).

This resolves upload failures in PROD environment during A2→A3 workflow.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-30 10:34:53 +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
27c23bd98f Enhancement: Add timestamps to batch entries in daily report for better identification 2026-01-19 15:16:13 -05:00
DJP
a5b4c78b01 Fix: Increment campaigns_processed for file-based workflow batches to show in breakdown 2026-01-19 15:13:58 -05:00
DJP
72a02b3667 Fix: Add batch entries to workflow breakdown for file-based workflows in daily report 2026-01-19 15:12:48 -05:00
DJP
331f47d9ef Fix: Correct summary block parsing in daily report to capture all workflow activity 2026-01-19 15:09:40 -05:00
DJP
7eb99536b7 Fix: Add parsing for all workflow summary patterns in daily report 2026-01-19 15:05:27 -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
2ef92674d3 Feat: Add subfolder path to A2->A3 email notifications 2026-01-19 10:20:51 -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
631dba4390 Fix campaign ID storage - always set local_campaign_id
Critical Fix:
- extract_global_campaign_reference() now accepts campaign_id parameter
- Always sets local_campaign_id to current campaign as fallback
- Prevents NULL local_campaign_id when no Global Campaign Reference exists

Root Cause:
- Assets without Global Campaign Reference had NULL local_campaign_id
- Caused derivatives to be linked to wrong campaigns
- Same asset in multiple campaigns would share tracking IDs incorrectly

Impact:
- Every asset now has proper local_campaign_id
- Derivatives correctly linked to their source campaign
- Fixes issue where C000001177 assets were showing as C000002098

Changes:
- database.py: Added campaign_id parameter with fallback logic
- a1_to_a2_box_uploader.py: Pass campaign_number to function
- a5_to_a6_download.py: Pass campaign_number to function
2025-12-22 11:37:58 -05:00
DJP
5586dcc5de Simplify derivative storage - only store dam_asset_id
Reverted master_asset_id changes per user feedback:
- tracking_id already links derivatives to masters
- No need for additional master_asset_id foreign key
- Only storing dam_asset_id for DAM asset tracking

Changes:
- Reverted get_master_asset() to not return database 'id'
- Updated store_derivative_asset() to only INSERT dam_asset_id
- Updated a2_to_a3_upload_polling.py to pass None for master_asset_id
- Removed master_asset_id from INSERT statement

Note: Migration script still needed for dam_asset_id column only
2025-12-22 10:16:14 -05:00
DJP
c901a79e24 Fix A2→A3 email template and database logging issues
Email Template Fix:
- Fixed subject line syntax error in a2_to_a3_batch_complete template
- Removed Jinja2 control flow ({% if %}) from subject line
- Changed to simple expression-only format
- Fixes 'Failed to send email' error

Database Logging Fix:
- Updated get_master_asset() to return database primary key 'id'
- Updated store_derivative_asset() to actually store master_asset_id and dam_asset_id
- Updated a2_to_a3_upload_polling.py to pass master_asset['id'] instead of None
- Added migration script to add dam_asset_id column to derivative_assets table
- Fixes issue where derivatives weren't being linked to masters in database
- Enables proper lookups and tracking of uploaded derivatives

Impact:
- Email notifications will now send successfully
- Derivatives will be properly logged and linked to master assets
- Other tools can now find uploaded derivatives in database
2025-12-22 10:12:36 -05:00