v1.0.0-beta3: Add Planner task creation with notes, fix folder name trimming, fix Excel folder link fallback
This commit is contained in:
@@ -273,7 +273,7 @@ function calculateJobFullName(record: any): string {
|
||||
const companyClient = record.Company_Client || record.company_client || '';
|
||||
|
||||
const parts = [jobName, jobAddress, companyClient].filter(p => p && String(p).trim());
|
||||
return parts.join(' - ');
|
||||
return parts.map(p => String(p).trim()).join(' - ').trim();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -376,6 +376,84 @@ function calculateActive(record: any): boolean {
|
||||
return activeStatuses.includes(jobStatus);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// PLANNER TASK CREATION
|
||||
// ============================================================================
|
||||
|
||||
async function createPlannerTask({
|
||||
jobNumber,
|
||||
jobFullName,
|
||||
dueDate,
|
||||
}: {
|
||||
jobNumber: string;
|
||||
jobFullName: string;
|
||||
dueDate?: string;
|
||||
}) {
|
||||
try {
|
||||
const client = await getGraphClient();
|
||||
|
||||
// Hardcoded assignee for testing: aewing@cardoza.construction
|
||||
const assigneeId = '1a6e9d10-138a-43e4-a09e-1f50463148c9';
|
||||
const assigneeName = 'Alex Ewing'; // Display name
|
||||
|
||||
// Parse due date if provided (ISO format to Date object)
|
||||
let dueDateObj: any = undefined;
|
||||
if (dueDate) {
|
||||
const d = new Date(dueDate);
|
||||
if (!isNaN(d.getTime())) {
|
||||
dueDateObj = d.toISOString();
|
||||
}
|
||||
}
|
||||
|
||||
// Task title: "Disposition New Job Folder for [Job_Number] [Job_Full_Name]"
|
||||
const title = `Disposition New Job Folder for ${jobNumber} ${jobFullName}`;
|
||||
|
||||
// Create the Planner task
|
||||
const groupId = process.env.PLANNER_GROUP_ID;
|
||||
const planId = process.env.PLANNER_PLAN_ID;
|
||||
const bucketId = process.env.PLANNER_BUCKET_ID;
|
||||
|
||||
if (!groupId || !planId || !bucketId) {
|
||||
throw new Error('Missing Planner configuration: PLANNER_GROUP_ID, PLANNER_PLAN_ID, or PLANNER_BUCKET_ID');
|
||||
}
|
||||
|
||||
const newTask = await client.api('/planner/tasks').post({
|
||||
planId,
|
||||
bucketId,
|
||||
title,
|
||||
assignments: {
|
||||
[assigneeId]: {
|
||||
'@odata.type': 'microsoft.graph.plannerAssignment',
|
||||
orderHint: ' !',
|
||||
},
|
||||
},
|
||||
...(dueDateObj ? { dueDateTime: dueDateObj } : {}),
|
||||
});
|
||||
|
||||
// Set the Notes/Description via task details (match the working test script)
|
||||
const taskDetails = await client.api(`/planner/tasks/${newTask.id}/details`).get();
|
||||
const detailsEtag = taskDetails['@odata.etag'];
|
||||
console.log(`[Planner] Task created ${newTask.id}, fetched details ETag: ${detailsEtag}`);
|
||||
await client
|
||||
.api(`/planner/tasks/${newTask.id}/details`)
|
||||
.header('If-Match', detailsEtag)
|
||||
.patch({
|
||||
description: 'Move the new folder to the correct Job Pages folder.',
|
||||
});
|
||||
console.log(`[Planner] Successfully patched description`);
|
||||
|
||||
console.log(`✓ Planner task created: "${title}" assigned to ${assigneeName}`);
|
||||
return { success: true, taskId: newTask.id, title };
|
||||
} catch (error: any) {
|
||||
console.error('✗ Planner task creation failed:', error.message);
|
||||
await logError('Planner Task Creation', error, {
|
||||
jobNumber,
|
||||
jobFullName,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize table cache on startup
|
||||
async function initializeTableCache() {
|
||||
const client = await getGraphClient();
|
||||
@@ -542,8 +620,19 @@ async function updateExcelFolderLink(pbId: string, link: string) {
|
||||
return vals && vals[pbIdColIndex] === pbId;
|
||||
});
|
||||
if (!target) {
|
||||
console.warn('⚠️ Excel row not found for pb_id:', pbId);
|
||||
return;
|
||||
// Row was just inserted at index 0, try updating that directly
|
||||
console.warn('⚠️ Excel row not found by pb_id, trying index 0 (just inserted)');
|
||||
try {
|
||||
await client.api(`${excelTablePath}/rows/itemAt(index=0)/range/cell(row=0,column=${linkColIndex})`)
|
||||
.patch({
|
||||
values: [[link || '']]
|
||||
});
|
||||
console.log('✓ Updated Excel Job_Folder_Link cell at index 0 for pb_id:', pbId);
|
||||
return;
|
||||
} catch (fallbackErr: any) {
|
||||
console.error('⚠️ Fallback update at index 0 also failed:', fallbackErr.message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Update only the Job_Folder_Link cell to preserve formulas in other columns (e.g., Active)
|
||||
@@ -720,6 +809,25 @@ app.post('/api/submit', async (c) => {
|
||||
await logError('PocketBase Final Update', pbFinalizeErr, { recordId: record.id, jobFolderLink });
|
||||
}
|
||||
|
||||
// Create Planner task for the new job (assigned to aewing@cardoza.construction)
|
||||
try {
|
||||
const jobFullName = (record as any).Job_Full_Name || '';
|
||||
|
||||
await createPlannerTask({
|
||||
jobNumber: newJobNumber,
|
||||
jobFullName,
|
||||
dueDate: data.Due_Date || undefined,
|
||||
});
|
||||
console.log('✓ Planner task created successfully');
|
||||
} catch (plannerError: any) {
|
||||
console.error('⚠️ Planner task creation failed, continuing:', plannerError.message);
|
||||
await logError('Planner Task Creation', plannerError, {
|
||||
jobNumber: newJobNumber,
|
||||
recordId: record.id,
|
||||
});
|
||||
// Don't fail the response; Planner is optional
|
||||
}
|
||||
|
||||
// Send Teams notification (fire and forget, don't block response)
|
||||
notifyTeamsChannel(record).catch(err => {
|
||||
console.error('⚠️ Teams notification error:', err.message);
|
||||
|
||||
Reference in New Issue
Block a user