Adds `reason_code`, `reason_label_snapshot`, `reason_comment` columns to `order_items` and integrates the `order_item_reason_policy` class into the POST and PUT /order/items routes. Validation order on audited products (consistent across POST and PUT): 1. If `reason_code` is present, validate reason first — emits the most specific error (invalid code, deprecated code, missing reason_comment). 2. If notes are provided but empty/whitespace, return "Notes is required for this product" (the legacy message). 3. Otherwise run reason validation — covers the missing-reason_code case. PHP api suite went from 284/290 to 290/290 (was 6 OrderItemsApiTest failures, now 0). Wired `addItemToOrder`, `updateOrderItem`, and `getItemAsArray` to persist and return the new columns.
74 lines
2.5 KiB
PHP
74 lines
2.5 KiB
PHP
<?php
|
|
|
|
namespace classes;
|
|
|
|
use InvalidArgumentException;
|
|
|
|
class order_item_reason_policy
|
|
{
|
|
public const EXTRAORDINARY_CHEMISTRY_PRODUCT_ID = 27;
|
|
public const AFFECTED_PRODUCT_IDS = [21, 22, 24, 25, 26, 27];
|
|
|
|
public static function reasons(): array
|
|
{
|
|
return [
|
|
'customer_approved_extra_work' => [
|
|
'label' => 'Kunde godkendte ekstra arbejde',
|
|
'requires_comment' => true,
|
|
'active' => true,
|
|
],
|
|
'vehicle_condition_extra_work' => [
|
|
'label' => 'Køretøjets tilstand krævede ekstra tid',
|
|
'requires_comment' => true,
|
|
'active' => true,
|
|
],
|
|
'quality_rework' => [
|
|
'label' => 'Kvalitetsopfølgning eller omvask',
|
|
'requires_comment' => true,
|
|
'active' => true,
|
|
],
|
|
'legacy_note_only' => [
|
|
'label' => 'Legacy note only',
|
|
'requires_comment' => true,
|
|
'active' => false,
|
|
],
|
|
];
|
|
}
|
|
|
|
public static function productRequiresReason(int $productId): bool
|
|
{
|
|
return in_array($productId, self::AFFECTED_PRODUCT_IDS, true);
|
|
}
|
|
|
|
public static function validateForProduct(int $productId, array $data): array
|
|
{
|
|
if (!self::productRequiresReason($productId)) {
|
|
return ['reason_code' => null, 'reason_label_snapshot' => null, 'reason_comment' => null];
|
|
}
|
|
|
|
$code = trim((string)($data['reason_code'] ?? $data['order_item_reason_code'] ?? ''));
|
|
if ($code === '') {
|
|
throw new InvalidArgumentException('Reason code is required for this product');
|
|
}
|
|
|
|
$reasons = self::reasons();
|
|
if (!array_key_exists($code, $reasons)) {
|
|
throw new InvalidArgumentException('Reason code is invalid for this product');
|
|
}
|
|
|
|
$reason = $reasons[$code];
|
|
if (!$reason['active']) {
|
|
throw new InvalidArgumentException('Reason code is deprecated for this product');
|
|
}
|
|
|
|
$comment = trim((string)($data['reason_comment'] ?? $data['comment'] ?? $data['notes'] ?? ''));
|
|
if ($reason['requires_comment'] && $comment === '') {
|
|
throw new InvalidArgumentException('Reason comment is required for this product');
|
|
}
|
|
|
|
$snapshot = $reason['label'];
|
|
|
|
return ['reason_code' => $code, 'reason_label_snapshot' => $snapshot, 'reason_comment' => $comment];
|
|
}
|
|
}
|