Files
pleno-vue/docs/customer-attributes-refactor-plan.md

7.7 KiB

Customer attributes refactor and migration plan

Problem statement

Customer attributes are currently represented as loosely typed string flags and evaluated in several UI, POS, and invoicing paths. This makes product restrictions vulnerable to broad category heuristics. The immediate defect is that restrictAdditionalServices ("Begræns tillægsydelser") treats related booking add-ons as additional services, so interior wash add-ons plus trailer/dolly additions are blocked even though that attribute is intended to cover standalone additional services only.

Target behavior matrix

Attribute Canonical intent Product availability behavior Invoice/workflow behavior
restrictAdditionalServices Block standalone additional services/tillægsydelser. Block standalone additional-service catalog items; do not block related booking add-ons such as interior wash, trailer, or dolly. Flag only order lines that are standalone additional services.
restrictTankCleaning Block tank-cleaning services. Block products whose category or legacy name identifies tank cleaning. Flag tank-cleaning order lines.
restrictSpotFree Block Spot Free/RO rinse products. Block canonical Spot Free product IDs and legacy Spot Free/RO naming. Flag Spot Free order lines.
restrictInteriorCleaning Block interior wash services. Block products whose names/categories explicitly identify interior wash. Flag interior-wash order lines.
onlyTankCleaning Allow only tank-cleaning services. Block every non-tank-cleaning product while keeping tank-cleaning products available. Flag non-tank-cleaning order lines.
requiresReferenceNumber Require an order reference. No product filtering. Flag orders missing a required reference.
requiresRegistrationNumbersInvoice Require registration numbers on invoice/order context. No product filtering. Flag orders missing required registration numbers.
invoiceAllOrdersIndividually Prevent grouped invoicing. No product filtering. Split/flag invoice collections containing multiple orders for the customer.
invoiceWithStripe Invoice through Stripe workflow. No product filtering. Route the customer through Stripe invoicing/payment handling.
showPricesOnBookingPage Show customer prices during booking. No product filtering. Presentation-only booking behavior.
usePONumbers Use/prompt for PO numbers. No product filtering. Require or expose PO-number workflow where configured.
exemptFromAdministrationFee Do not charge administration fees. No product filtering. Suppress/flag administration-fee order lines for this customer.

Refactor plan

  1. Create a canonical customer-rule domain module

    • Keep CUSTOMER_RULE_DEFINITIONS as the registry of public attributes, but extend each entry with a typed evaluator contract: product predicate, category predicate, invoice predicate, and UI impact metadata.
    • Replace scattered string comparisons with registry lookups so every surface uses the same semantics.
    • Add explicit names for ambiguous categories: standaloneAdditionalService, relatedAddon, primaryProduct, tankCleaning, spotFree, and interiorCleaning.
  2. Normalize product classification once

    • Build a classifyCustomerRuleProduct(product, context) helper returning booleans for each product class.
    • Treat related add-ons (isRelatedAddon, relatedItemId) as context, not as proof that the item is a standalone additional service.
    • Reserve restrictAdditionalServices for category 8/standalone service context or explicit additional-service labels, not numeric booking add-on category 4.
  3. Migrate rule evaluation paths

    • POS product cards and mobile flows should call getCustomerProductRestriction only with the normalized product context.
    • Customer-rule tooltips should derive blocked/available products from the same evaluator used by POS.
    • Invoicing-period flag generation should use the same classification vocabulary as product availability so historical and current orders are flagged consistently.
  4. Backfill and data migration

    • Keep existing attribute keys unchanged to avoid a destructive migration.
    • Add a one-time data audit/report listing customers with restrictAdditionalServices and recent orders containing interior wash, trailer, or dolly add-ons. These rows should be verified as no longer violating the rule after deployment.
    • If any historical invoice flags were created solely because related add-ons were treated as additional services, provide an idempotent cleanup command to recalculate customer-rule violations for affected invoice periods.
  5. Regression test coverage

    • Unit-test every attribute in the target behavior matrix.
    • Add focused cases for the defect: interior wash related add-on, trailer related add-on, and dolly related add-on must remain available under restrictAdditionalServices.
    • Add invoice-flag fixtures mirroring the same products so invoicing behavior cannot drift from POS behavior.
    • Keep tooltip tests aligned with the evaluator, showing standalone additional services under restrictAdditionalServices and not showing related add-ons.
  6. Rollout and verification

    • Ship the evaluator patch behind the existing attribute keys.
    • Run unit tests and targeted POS/customer-rule e2e tests.
    • Verify with production-like catalog data that restrictAdditionalServices blocks only standalone additional services while restrictInteriorCleaning, restrictTankCleaning, restrictSpotFree, and onlyTankCleaning continue to behave exactly as listed above.