(args: ToolArgs, ctx: TrainingContext)
| 3373 | } |
| 3374 | |
| 3375 | export async function handleReportUsage(args: ToolArgs, ctx: TrainingContext) { |
| 3376 | const req = args as unknown as ReportUsageArgs; |
| 3377 | const session = await getSession(sessionKeyFromArgs(req, ctx.mode, ctx.userId, ctx.moduleId)); |
| 3378 | |
| 3379 | if (!req.reporting_period || !req.usage?.length) { |
| 3380 | return { errors: [{ code: 'INVALID_USAGE_DATA', message: 'reporting_period and at least one usage record are required.' }] }; |
| 3381 | } |
| 3382 | |
| 3383 | if (session.usageRecords.length + req.usage.length > MAX_USAGE_RECORDS_PER_SESSION) { |
| 3384 | return { errors: [{ code: 'LIMIT_EXCEEDED', message: `Usage record limit (${MAX_USAGE_RECORDS_PER_SESSION}) would be exceeded.` }] }; |
| 3385 | } |
| 3386 | |
| 3387 | let accepted = 0; |
| 3388 | const errors: Array<{ code: string; message: string; field?: string }> = []; |
| 3389 | |
| 3390 | for (let i = 0; i < req.usage.length; i++) { |
| 3391 | const record = req.usage[i]; |
| 3392 | |
| 3393 | // Validate required fields |
| 3394 | if (record.vendor_cost === undefined || record.vendor_cost === null) { |
| 3395 | errors.push({ code: 'INVALID_USAGE_DATA', message: 'vendor_cost is required.', field: `usage[${i}].vendor_cost` }); |
| 3396 | continue; |
| 3397 | } |
| 3398 | if (record.vendor_cost < 0) { |
| 3399 | errors.push({ code: 'INVALID_USAGE_DATA', message: 'vendor_cost must be non-negative.', field: `usage[${i}].vendor_cost` }); |
| 3400 | continue; |
| 3401 | } |
| 3402 | if (!record.currency) { |
| 3403 | errors.push({ code: 'INVALID_USAGE_DATA', message: 'currency is required.', field: `usage[${i}].currency` }); |
| 3404 | continue; |
| 3405 | } |
| 3406 | if (!record.account) { |
| 3407 | errors.push({ code: 'INVALID_USAGE_DATA', message: 'account is required.', field: `usage[${i}].account` }); |
| 3408 | continue; |
| 3409 | } |
| 3410 | if (record.impressions !== undefined && record.impressions < 0) { |
| 3411 | errors.push({ code: 'INVALID_USAGE_DATA', message: 'impressions must be non-negative.', field: `usage[${i}].impressions` }); |
| 3412 | continue; |
| 3413 | } |
| 3414 | |
| 3415 | // Validate creative_id exists if provided |
| 3416 | if (record.creative_id) { |
| 3417 | const creative = session.creatives.get(record.creative_id) ?? getComplianceCreative(record.creative_id); |
| 3418 | if (!creative) { |
| 3419 | errors.push({ code: 'NOT_FOUND', message: `Creative "${record.creative_id}" not found in session.`, field: `usage[${i}].creative_id` }); |
| 3420 | continue; |
| 3421 | } |
| 3422 | |
| 3423 | // Validate pricing_option_id matches if provided |
| 3424 | if (record.pricing_option_id && creative.pricingOptionId && record.pricing_option_id !== creative.pricingOptionId) { |
| 3425 | errors.push({ |
| 3426 | code: 'INVALID_PRICING_OPTION', |
| 3427 | message: `pricing_option_id mismatch: expected ${creative.pricingOptionId}, received ${record.pricing_option_id}`, |
| 3428 | field: `usage[${i}].pricing_option_id`, |
| 3429 | }); |
| 3430 | continue; |
| 3431 | } |
| 3432 | } |
nothing calls this directly
no test coverage detected