| @@ -255,10 +255,14 @@ | ||
| 255 | 255 | } |
| 256 | 256 | |
| 257 | 257 | return [ |
| 258 | 258 | 'matching_count' => $count, |
| 259 | - 'by_type' => self::countBy((clone $query), 'transaction_type'), | |
| 260 | - 'by_status' => self::countBy((clone $query), 'status'), | |
| 259 | + // Cast to object: the output_schema types these as 'object', but a | |
| 260 | + // dynamically-built PHP map is an empty array [] when nothing matches, | |
| 261 | + // which json_encodes to [] and fails structured-output validation. | |
| 262 | + // (object) forces {} when empty and a JSON object otherwise. | |
| 263 | + 'by_type' => (object) self::countBy((clone $query), 'transaction_type'), | |
| 264 | + 'by_status' => (object) self::countBy((clone $query), 'status'), | |
| 261 | 265 | 'amount_by_currency' => $amountByCurrency, |
| 262 | 266 | 'note' => 'amount_by_currency sums transaction total within each currency; charges and refunds are both stored as positive amounts, so filter by type for a single-sided figure.', |
| 263 | 267 | ]; |
| 264 | 268 | } |