Manual-VIN-Entry Activated

Feature: Manual-VIN-Entry Activated Service Items
  Service items with CampaignActivationTrigger = ManualVinEntry are only
  eligible when an admin has recorded a CampaignVinEntry for the VIN whose
  CampaignID matches the item's CampaignID and whose RecordedDate falls
  inside the item's campaign window.
  ActivatedAt and ExpiresAt come from the matching entry's RecordedDate
  based on CampaignActivationType:
   - FirstTriggerOnly: the earliest matching entry
   - ExtendOnEachTrigger: the latest matching entry
   - EveryTrigger: one claim item is emitted per matching entry
  Claims tie back to the activating entry via CampaignVinEntryID, so the
  same item can be processed for one entry while still pending for another.

Scenario: ManualVinEntry-activated item is eligible when a matching entry exists
  Given vehicles in dealer stock:
    | VIN               | InvoiceDate | CompanyID | BranchID | BrandID |
    | 1FDKF37GXVEB34368 | 2026-01-15  | 1         | 10       | 1       |
  And service items:
    | ServiceItemID | Name   | BrandID | ActivationTrigger | ActivationType   | CampaignID | ActiveForMonths |
    | SI-MVE        | Reward | 1       | ManualVinEntry    | FirstTriggerOnly | 500        | 12              |
  And campaign VIN entries:
    | VIN               | CampaignID | RecordedDate |
    | 1FDKF37GXVEB34368 | 500        | 2026-02-01   |
  When evaluating service items for "1FDKF37GXVEB34368" with language "en"
  Then service item "SI-MVE" is in the result

Scenario: ManualVinEntry-activated item with no matching entry is excluded
  Given vehicles in dealer stock:
    | VIN               | InvoiceDate | CompanyID | BranchID | BrandID |
    | 1FDKF37GXVEB34368 | 2026-01-15  | 1         | 10       | 1       |
  And service items:
    | ServiceItemID | Name   | BrandID | ActivationTrigger | ActivationType   | CampaignID | ActiveForMonths |
    | SI-MVE        | Reward | 1       | ManualVinEntry    | FirstTriggerOnly | 500        | 12              |
  When evaluating service items for "1FDKF37GXVEB34368" with language "en"
  Then service item "SI-MVE" is not in the result

Scenario: Entry for a different campaign does not activate the item
  Given vehicles in dealer stock:
    | VIN               | InvoiceDate | CompanyID | BranchID | BrandID |
    | 1FDKF37GXVEB34368 | 2026-01-15  | 1         | 10       | 1       |
  And service items:
    | ServiceItemID | Name   | BrandID | ActivationTrigger | ActivationType   | CampaignID | ActiveForMonths |
    | SI-MVE        | Reward | 1       | ManualVinEntry    | FirstTriggerOnly | 500        | 12              |
  And campaign VIN entries:
    | VIN               | CampaignID | RecordedDate |
    | 1FDKF37GXVEB34368 | 999        | 2026-02-01   |
  When evaluating service items for "1FDKF37GXVEB34368" with language "en"
  Then service item "SI-MVE" is not in the result

Scenario: Entry recorded outside the campaign window is excluded
  Given vehicles in dealer stock:
    | VIN               | InvoiceDate | CompanyID | BranchID | BrandID |
    | 1FDKF37GXVEB34368 | 2026-01-15  | 1         | 10       | 1       |
  And service items:
    | ServiceItemID | Name   | BrandID | ActivationTrigger | ActivationType   | CampaignID | CampaignStartDate | CampaignEndDate | ActiveForMonths |
    | SI-MVE        | Reward | 1       | ManualVinEntry    | FirstTriggerOnly | 500        | 2026-01-01        | 2026-03-31      | 12              |
  And campaign VIN entries:
    | VIN               | CampaignID | RecordedDate |
    | 1FDKF37GXVEB34368 | 500        | 2026-05-01   |
  When evaluating service items for "1FDKF37GXVEB34368" with language "en"
  Then service item "SI-MVE" is not in the result

Scenario: FirstTriggerOnly uses the earliest matching entry
  Given vehicles in dealer stock:
    | VIN               | InvoiceDate | CompanyID | BranchID | BrandID |
    | 1FDKF37GXVEB34368 | 2026-01-15  | 1         | 10       | 1       |
  And service items:
    | ServiceItemID | Name   | BrandID | ActivationTrigger | ActivationType   | CampaignID | ActiveForMonths |
    | SI-FIRST      | Reward | 1       | ManualVinEntry    | FirstTriggerOnly | 500        | 12              |
  And campaign VIN entries:
    | VIN               | CampaignID | RecordedDate |
    | 1FDKF37GXVEB34368 | 500        | 2026-05-01   |
    | 1FDKF37GXVEB34368 | 500        | 2026-02-01   |
  When evaluating service items for "1FDKF37GXVEB34368" with language "en"
  Then service item "SI-FIRST" has activation "2026-02-01"
  And service item "SI-FIRST" has expiration "2027-02-01"

Scenario: ExtendOnEachTrigger uses the latest matching entry
  Given vehicles in dealer stock:
    | VIN               | InvoiceDate | CompanyID | BranchID | BrandID |
    | 1FDKF37GXVEB34368 | 2026-01-15  | 1         | 10       | 1       |
  And service items:
    | ServiceItemID | Name   | BrandID | ActivationTrigger | ActivationType      | CampaignID | ActiveForMonths |
    | SI-EXTEND     | Reward | 1       | ManualVinEntry    | ExtendOnEachTrigger | 500        | 12              |
  And campaign VIN entries:
    | VIN               | CampaignID | RecordedDate |
    | 1FDKF37GXVEB34368 | 500        | 2026-02-01   |
    | 1FDKF37GXVEB34368 | 500        | 2026-05-01   |
  When evaluating service items for "1FDKF37GXVEB34368" with language "en"
  Then service item "SI-EXTEND" has activation "2026-05-01"
  And service item "SI-EXTEND" has expiration "2027-05-01"

Scenario: EveryTrigger emits one claim item per matching entry
  Given vehicles in dealer stock:
    | VIN               | InvoiceDate | CompanyID | BranchID | BrandID |
    | 1FDKF37GXVEB34368 | 2026-01-15  | 1         | 10       | 1       |
  And service items:
    | ServiceItemID | Name   | BrandID | ActivationTrigger | ActivationType | CampaignID | ActiveForMonths |
    | SI-EVERY      | Reward | 1       | ManualVinEntry    | EveryTrigger   | 500        | 12              |
  And campaign VIN entries:
    | VIN               | CampaignID | RecordedDate |
    | 1FDKF37GXVEB34368 | 500        | 2026-02-01   |
    | 1FDKF37GXVEB34368 | 500        | 2026-05-01   |
  When evaluating service items for "1FDKF37GXVEB34368" with language "en"
  Then there are 2 service items with ID "SI-EVERY"

Scenario: Claim tied to a specific entry processes only that entry's item
  Given vehicles in dealer stock:
    | VIN               | InvoiceDate | CompanyID | BranchID | BrandID |
    | 1FDKF37GXVEB34368 | 2026-01-15  | 1         | 10       | 1       |
  And service items:
    | ServiceItemID | Name   | BrandID | ActivationTrigger | ActivationType | CampaignID | ActiveForMonths |
    | SI-EVERY      | Reward | 1       | ManualVinEntry    | EveryTrigger   | 500        | 12              |
  And campaign VIN entries:
    | id      | VIN               | CampaignID | RecordedDate |
    | ENTRY-A | 1FDKF37GXVEB34368 | 500        | 2026-02-01   |
    | ENTRY-B | 1FDKF37GXVEB34368 | 500        | 2026-05-01   |
  And item claims:
    | ServiceItemID | CampaignVinEntryID | ClaimDate  | JobNumber | InvoiceNumber |
    | SI-EVERY      | ENTRY-A            | 2026-02-15 | JOB-1     | INV-1         |
  When evaluating service items for "1FDKF37GXVEB34368" with language "en"
  Then service item "SI-EVERY" for campaign VIN entry "ENTRY-A" has status "processed"
  And service item "SI-EVERY" for campaign VIN entry "ENTRY-B" has status "pending"