Update deliverable creation: Projects with URLs and correct dates

Changes:
- Deliverables now created as Projects (not Tasks)
- Project dates: Using StartDate/EndDate from ProjectDetails
- Deliverable dates: BriefDate as start, LiveDate (or DueDate) as end
- OMG# field for deliverables: Contains URL (OMG# - 999999)
  - Example: 6361863 → https://bissell.omg.oliver.solutions/jobs/5361864
- Projects keep OMG# as plain number
- Added find_deliverable_by_omg_number() for duplicate detection
- Added generate_omg_url() for URL construction

Structure: Folder > Project > Deliverable (as Project)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Dave Porter 2025-10-14 16:08:18 -04:00
parent 255c03b65d
commit d449668cb9

View file

@ -415,40 +415,106 @@ class WrikeMonitor:
return task["id"]
return None
def create_deliverable_task(self, project_id, job_details):
"""Create deliverable task (skip if exists)"""
task_title = job_details.get("Title", "Untitled Task")
def find_deliverable_by_omg_number(self, parent_project_id, omg_number):
"""Find deliverable (project) with matching OMG number"""
if not omg_number:
return None
# Get folder tree
result = self.make_wrike_request("GET", f"/folders/{parent_project_id}/folders?fields=[\"customFields\",\"project\"]")
if result and "data" in result:
# Find parent folder with childIds
parent_folder = None
for item in result["data"]:
if item["id"] == parent_project_id:
parent_folder = item
break
if parent_folder:
child_ids = parent_folder.get("childIds", [])
# Search only in direct children that are projects
for item in result["data"]:
if item["id"] in child_ids and "project" in item:
custom_fields = item.get("customFields", [])
for field in custom_fields:
if field.get("id") == Config.CUSTOM_FIELDS["omg_number"]:
if field.get("value") == omg_number:
return item["id"]
return None
def generate_omg_url(self, omg_number):
"""Generate OMG URL from OMG number (subtract 999999)"""
try:
omg_int = int(omg_number)
job_id = omg_int - 999999
return f"https://bissell.omg.oliver.solutions/jobs/{job_id}"
except (ValueError, TypeError):
return None
def create_deliverable_project(self, parent_project_id, job_details):
"""Create deliverable as a project (not a task) - skip if exists"""
deliverable_title = job_details.get("Title", "Untitled Deliverable")
job_number = job_details.get("Number", "")
# Check if exists
# Check if exists by searching for existing deliverable with same OMG#
if job_number:
existing_task_id = self.find_task_by_omg_number(project_id, job_number)
if existing_task_id:
self.logger.info(f"⊙ Task already exists: {task_title} (#{job_number}) - skipping")
return existing_task_id, True # Return (task_id, skipped=True)
existing_deliverable_id = self.find_deliverable_by_omg_number(parent_project_id, job_number)
if existing_deliverable_id:
self.logger.info(f"Deliverable already exists: {deliverable_title} (#{job_number}) - skipping")
return existing_deliverable_id, True # Return (deliverable_id, skipped=True)
# Parse dates
due_date = self.parse_date(job_details.get("DueDate"))
# Parse dates - use BriefDate as start, LiveDate (or DueDate) as end
brief_date = self.parse_date(job_details.get("BriefDate"))
live_date = self.parse_date(job_details.get("LiveDate")) or self.parse_date(job_details.get("DueDate"))
# Create task
task_data = {
"title": task_title,
"description": job_details.get("Notes", ""),
# Build description
description_parts = []
if job_details.get("Notes"):
description_parts.append(job_details["Notes"])
if job_details.get("Type"):
description_parts.append(f"Type: {job_details['Type']}")
if job_details.get("MediaType"):
description_parts.append(f"Media: {job_details['MediaType']}")
deliverable_description = " | ".join(description_parts) if description_parts else ""
# Create deliverable as a project (subfolder)
deliverable_data = {
"title": deliverable_title,
"description": deliverable_description
}
if due_date:
task_data["dates"] = {"due": due_date}
if brief_date:
task_data["dates"]["start"] = brief_date
result = self.make_wrike_request("POST", f"/folders/{parent_project_id}/folders", deliverable_data)
result = self.make_wrike_request("POST", f"/folders/{project_id}/tasks", task_data)
if result and "data" in result and len(result["data"]) > 0:
task_id = result["data"][0]["id"]
deliverable_id = result["data"][0]["id"]
# Convert to project with dates
project_data = {"project": {}}
if brief_date:
project_data["project"]["startDate"] = brief_date
if live_date:
project_data["project"]["endDate"] = live_date
# Add custom fields
custom_fields = []
# For deliverables: OMG# field gets the URL, not just the number
if job_number:
omg_url = self.generate_omg_url(job_number)
if omg_url:
custom_fields.append({
"id": Config.CUSTOM_FIELDS["omg_number"],
"value": omg_url
})
else:
# Fallback to just the number if URL generation fails
custom_fields.append({
"id": Config.CUSTOM_FIELDS["omg_number"],
"value": job_number
})
job_category = job_details.get("JobCategory", job_details.get("MediaType", ""))
if job_category:
custom_fields.append({
@ -456,12 +522,6 @@ class WrikeMonitor:
"value": job_category
})
if job_number:
custom_fields.append({
"id": Config.CUSTOM_FIELDS["omg_number"],
"value": job_number
})
notes_parts = []
if job_details.get("Type"):
notes_parts.append(f"Type: {job_details['Type']}")
@ -474,10 +534,13 @@ class WrikeMonitor:
})
if custom_fields:
self.make_wrike_request("PUT", f"/tasks/{task_id}", {"customFields": custom_fields})
project_data["customFields"] = custom_fields
self.logger.info(f"Created task: {task_title} (#{job_number})")
return task_id, False # Return (task_id, skipped=False)
# Update with project dates and custom fields
self.make_wrike_request("PUT", f"/folders/{deliverable_id}", project_data)
self.logger.info(f"✓ Created deliverable (as project): {deliverable_title} (#{job_number})")
return deliverable_id, False # Return (deliverable_id, skipped=False)
return None, False
@ -514,10 +577,10 @@ class WrikeMonitor:
if not project_id:
raise ValueError(f"Failed to create project: {project_title}")
# Create task
task_id, skipped = self.create_deliverable_task(project_id, job_details)
if not task_id:
raise ValueError("Failed to create task")
# Create deliverable (as project)
deliverable_id, skipped = self.create_deliverable_project(project_id, job_details)
if not deliverable_id:
raise ValueError("Failed to create deliverable")
processing_time = time.time() - start_time