{
  "feature": "loyalty-coupons",
  "version": "1.0.0",
  "description": "Loyalty and promotion engine supporting points, coupons, gift cards, discount codes, buy-X-get-Y offers, e-wallets, and next-order rewards.\n",
  "category": "payment",
  "tags": [
    "loyalty",
    "coupons",
    "gift-cards",
    "promotions",
    "rewards",
    "discounts"
  ],
  "actors": [
    {
      "id": "customer",
      "name": "Customer",
      "type": "human",
      "description": "Earns points, redeems rewards, applies coupon codes"
    },
    {
      "id": "marketing_manager",
      "name": "Marketing Manager",
      "type": "human",
      "description": "Creates and manages loyalty programs and promotion campaigns"
    },
    {
      "id": "system",
      "name": "Loyalty Engine",
      "type": "system",
      "description": "Evaluates earning rules, validates redemption, tracks balances"
    }
  ],
  "fields": [
    {
      "name": "program_type",
      "type": "select",
      "label": "Program Type",
      "required": true,
      "options": [
        {
          "value": "coupons",
          "label": "Coupons"
        },
        {
          "value": "gift_card",
          "label": "Gift Card"
        },
        {
          "value": "loyalty",
          "label": "Loyalty"
        },
        {
          "value": "promotion",
          "label": "Promotion"
        },
        {
          "value": "ewallet",
          "label": "E-Wallet"
        },
        {
          "value": "promo_code",
          "label": "Promo Code"
        },
        {
          "value": "buy_x_get_y",
          "label": "Buy X Get Y"
        },
        {
          "value": "next_order_coupons",
          "label": "Next Order Coupons"
        }
      ]
    },
    {
      "name": "program_name",
      "type": "text",
      "label": "Program Name",
      "required": true
    },
    {
      "name": "program_active",
      "type": "boolean",
      "label": "Active",
      "required": true
    },
    {
      "name": "earning_mode",
      "type": "select",
      "label": "Earning Mode",
      "required": true,
      "options": [
        {
          "value": "order",
          "label": "Order"
        },
        {
          "value": "money",
          "label": "Money"
        },
        {
          "value": "unit",
          "label": "Unit"
        }
      ]
    },
    {
      "name": "points_per_trigger",
      "type": "number",
      "label": "Points Earned",
      "required": true,
      "validation": [
        {
          "type": "min",
          "value": 0.01,
          "message": "Points earned must be a positive number"
        }
      ]
    },
    {
      "name": "trigger_mode",
      "type": "select",
      "label": "Trigger Mode",
      "required": true,
      "options": [
        {
          "value": "auto",
          "label": "Auto"
        },
        {
          "value": "with_code",
          "label": "With Code"
        }
      ]
    },
    {
      "name": "promo_code",
      "type": "text",
      "label": "Promotion Code",
      "required": false
    },
    {
      "name": "minimum_quantity",
      "type": "number",
      "label": "Minimum Quantity",
      "required": false
    },
    {
      "name": "minimum_amount",
      "type": "number",
      "label": "Minimum Purchase Amount",
      "required": false
    },
    {
      "name": "eligible_products",
      "type": "json",
      "label": "Eligible Products",
      "required": false
    },
    {
      "name": "reward_type",
      "type": "select",
      "label": "Reward Type",
      "required": true,
      "options": [
        {
          "value": "discount",
          "label": "Discount"
        },
        {
          "value": "product",
          "label": "Product"
        }
      ]
    },
    {
      "name": "discount_mode",
      "type": "select",
      "label": "Discount Mode",
      "required": false,
      "options": [
        {
          "value": "percent",
          "label": "Percent"
        },
        {
          "value": "fixed_amount",
          "label": "Fixed Amount"
        }
      ]
    },
    {
      "name": "discount_value",
      "type": "number",
      "label": "Discount Value",
      "required": false,
      "validation": [
        {
          "type": "min",
          "value": 0.01,
          "message": "Discount value must be a positive number"
        }
      ]
    },
    {
      "name": "discount_applicability",
      "type": "select",
      "label": "Applies To",
      "required": false,
      "options": [
        {
          "value": "order",
          "label": "Order"
        },
        {
          "value": "cheapest",
          "label": "Cheapest"
        },
        {
          "value": "specific",
          "label": "Specific"
        }
      ]
    },
    {
      "name": "reward_product_id",
      "type": "text",
      "label": "Free Product",
      "required": false
    },
    {
      "name": "reward_product_qty",
      "type": "number",
      "label": "Free Product Quantity",
      "required": false,
      "validation": [
        {
          "type": "min",
          "value": 1,
          "message": "Free product quantity must be at least 1"
        }
      ]
    },
    {
      "name": "required_points",
      "type": "number",
      "label": "Points Required",
      "required": true,
      "validation": [
        {
          "type": "min",
          "value": 1,
          "message": "Required points must be at least 1"
        }
      ]
    },
    {
      "name": "card_code",
      "type": "text",
      "label": "Card/Coupon Code",
      "required": true
    },
    {
      "name": "card_points_balance",
      "type": "number",
      "label": "Points Balance",
      "required": true
    },
    {
      "name": "card_partner_id",
      "type": "text",
      "label": "Card Holder",
      "required": false
    }
  ],
  "rules": {
    "code_uniqueness": {
      "description": "Promotion codes must be unique across all active rules and loyalty cards"
    },
    "reward_points_positive": {
      "description": "Required points for redemption must be greater than zero"
    },
    "discount_value_positive": {
      "description": "Discount amount or percentage must be a positive number"
    },
    "reward_qty_positive": {
      "description": "Free product reward quantity must be at least 1"
    },
    "points_earned_positive": {
      "description": "Points earned per trigger must be a positive number"
    },
    "nominative_no_split": {
      "description": "Nominative programs (loyalty, e-wallet) cannot split earned points across multiple cards — all points go to the customer's single card\n"
    },
    "minimum_threshold_check": {
      "description": "Earning rules only trigger when the order meets the minimum quantity and/or minimum purchase amount thresholds\n"
    },
    "auto_vs_code_trigger": {
      "description": "Auto-triggered promotions apply at checkout without customer action. Code-triggered promotions require the customer to enter a valid code.\n"
    },
    "gift_card_balance_sufficient": {
      "description": "Gift card redemption cannot exceed the card's remaining balance"
    },
    "ewallet_balance_sufficient": {
      "description": "E-wallet payment cannot exceed the wallet's available balance"
    }
  },
  "outcomes": {
    "points_earned": {
      "priority": 1,
      "given": [
        "customer completes a qualifying purchase",
        "a loyalty program with matching earning rules exists",
        {
          "any": [
            "program trigger mode is auto",
            "customer entered the correct promo code"
          ]
        }
      ],
      "then": [
        {
          "action": "set_field",
          "target": "card_points_balance",
          "description": "Points added to customer's loyalty card based on earning rules"
        },
        {
          "action": "create_record",
          "type": "loyalty_history",
          "target": "loyalty_history",
          "description": "History entry records points issued for this transaction"
        },
        {
          "action": "emit_event",
          "event": "loyalty.points.earned",
          "payload": [
            "card_code",
            "program_type",
            "points_earned",
            "order_id"
          ]
        }
      ],
      "result": "Customer's loyalty balance increases by the earned amount"
    },
    "reward_redeemed_discount": {
      "priority": 2,
      "given": [
        "customer has sufficient points on their loyalty card",
        "customer applies reward at checkout",
        {
          "field": "reward_type",
          "source": "input",
          "operator": "eq",
          "value": "discount"
        }
      ],
      "then": [
        {
          "action": "set_field",
          "target": "card_points_balance",
          "description": "Required points deducted from card balance"
        },
        {
          "action": "create_record",
          "type": "discount_line",
          "target": "discount_line",
          "description": "Discount line added to the order based on reward configuration"
        },
        {
          "action": "create_record",
          "type": "loyalty_history",
          "target": "loyalty_history",
          "description": "History entry records points used for this redemption"
        },
        {
          "action": "emit_event",
          "event": "loyalty.reward.redeemed",
          "payload": [
            "card_code",
            "reward_type",
            "discount_value",
            "order_id"
          ]
        }
      ],
      "result": "Discount applied to order, points deducted from card"
    },
    "reward_redeemed_product": {
      "priority": 3,
      "given": [
        "customer has sufficient points on their loyalty card",
        {
          "field": "reward_type",
          "source": "input",
          "operator": "eq",
          "value": "product"
        }
      ],
      "then": [
        {
          "action": "set_field",
          "target": "card_points_balance",
          "description": "Required points deducted from card balance"
        },
        {
          "action": "create_record",
          "type": "order_line",
          "target": "free_product_line",
          "description": "Free product added to the order at zero cost"
        },
        {
          "action": "emit_event",
          "event": "loyalty.reward.redeemed",
          "payload": [
            "card_code",
            "reward_type",
            "reward_product_id",
            "order_id"
          ]
        }
      ],
      "result": "Free product added to order, points deducted"
    },
    "coupon_applied": {
      "priority": 4,
      "given": [
        "customer enters a coupon code at checkout",
        "coupon code matches an active coupon or promo code",
        "order meets the minimum quantity and amount requirements"
      ],
      "then": [
        {
          "action": "create_record",
          "type": "discount_line",
          "target": "discount_line",
          "description": "Coupon discount applied to the order"
        },
        {
          "action": "emit_event",
          "event": "loyalty.coupon.applied",
          "payload": [
            "card_code",
            "program_type",
            "discount_value",
            "order_id"
          ]
        }
      ],
      "result": "Coupon discount reflected on the order total"
    },
    "gift_card_redeemed": {
      "priority": 5,
      "given": [
        "customer enters a gift card code",
        "gift card has sufficient remaining balance"
      ],
      "then": [
        {
          "action": "set_field",
          "target": "card_points_balance",
          "description": "Gift card balance reduced by the applied amount"
        },
        {
          "action": "create_record",
          "type": "payment_line",
          "target": "payment_line",
          "description": "Gift card payment applied to the order"
        },
        {
          "action": "emit_event",
          "event": "loyalty.gift_card.redeemed",
          "payload": [
            "card_code",
            "amount_used",
            "remaining_balance"
          ]
        }
      ],
      "result": "Gift card balance applied as payment toward the order",
      "error": "LOYALTY_GIFT_CARD_EMPTY"
    },
    "insufficient_points": {
      "priority": 1,
      "error": "LOYALTY_INSUFFICIENT_POINTS",
      "given": [
        "customer attempts to redeem a reward",
        {
          "field": "card_points_balance",
          "source": "db",
          "operator": "lt",
          "value": "required_points"
        }
      ],
      "then": [
        {
          "action": "notify",
          "channel": "ui",
          "description": "Show current balance and required points"
        }
      ],
      "result": "Reward not applied, customer informed of points needed"
    },
    "invalid_promo_code": {
      "priority": 2,
      "error": "LOYALTY_INVALID_CODE",
      "given": [
        "customer enters a promo code that does not match any active program"
      ],
      "then": [
        {
          "action": "notify",
          "channel": "ui",
          "description": "Code not recognized message"
        }
      ],
      "result": "No discount applied"
    },
    "minimum_not_met": {
      "priority": 3,
      "error": "LOYALTY_MINIMUM_NOT_MET",
      "given": [
        "order does not meet the minimum quantity or amount for the promotion"
      ],
      "then": [
        {
          "action": "notify",
          "channel": "ui",
          "description": "Show minimum requirements"
        }
      ],
      "result": "Promotion not applied until order meets thresholds"
    }
  },
  "errors": [
    {
      "code": "LOYALTY_INSUFFICIENT_POINTS",
      "message": "You don't have enough points for this reward.",
      "status": 400
    },
    {
      "code": "LOYALTY_INVALID_CODE",
      "message": "The code you entered is not valid or has expired.",
      "status": 400
    },
    {
      "code": "LOYALTY_MINIMUM_NOT_MET",
      "message": "Your order does not meet the minimum requirements for this promotion.",
      "status": 400
    },
    {
      "code": "LOYALTY_GIFT_CARD_EMPTY",
      "message": "This gift card has no remaining balance.",
      "status": 400
    },
    {
      "code": "LOYALTY_CODE_ALREADY_USED",
      "message": "This coupon has already been used.",
      "status": 400
    },
    {
      "code": "LOYALTY_DUPLICATE_CODE",
      "message": "A program with this code already exists.",
      "status": 409
    }
  ],
  "events": [
    {
      "name": "loyalty.points.earned",
      "description": "Customer earned loyalty points from a purchase",
      "payload": [
        "card_code",
        "program_type",
        "points_earned",
        "order_id"
      ]
    },
    {
      "name": "loyalty.reward.redeemed",
      "description": "Customer redeemed a reward (discount or free product)",
      "payload": [
        "card_code",
        "reward_type",
        "value",
        "order_id"
      ]
    },
    {
      "name": "loyalty.coupon.applied",
      "description": "Coupon or promo code successfully applied to an order",
      "payload": [
        "card_code",
        "program_type",
        "discount_value",
        "order_id"
      ]
    },
    {
      "name": "loyalty.gift_card.redeemed",
      "description": "Gift card balance used for payment",
      "payload": [
        "card_code",
        "amount_used",
        "remaining_balance"
      ]
    },
    {
      "name": "loyalty.card.created",
      "description": "New loyalty card or coupon generated",
      "payload": [
        "card_code",
        "program_type",
        "partner_id"
      ]
    }
  ],
  "related": [
    {
      "feature": "pos-core",
      "type": "optional",
      "reason": "Loyalty rewards applied at point-of-sale checkout"
    },
    {
      "feature": "quotation-order-management",
      "type": "optional",
      "reason": "Loyalty rewards applied to online/portal sales orders"
    },
    {
      "feature": "ecommerce-store",
      "type": "optional",
      "reason": "Promo codes and loyalty applied during online checkout"
    }
  ],
  "agi": {
    "goals": [
      {
        "id": "reliable_loyalty_coupons",
        "description": "Loyalty and promotion engine supporting points, coupons, gift cards, discount codes, buy-X-get-Y offers, e-wallets, and next-order rewards.\n",
        "success_metrics": [
          {
            "metric": "policy_violation_rate",
            "target": "0%",
            "measurement": "Operations that violate defined policies"
          },
          {
            "metric": "audit_completeness",
            "target": "100%",
            "measurement": "All decisions have complete audit trails"
          }
        ],
        "constraints": [
          {
            "type": "regulatory",
            "description": "All operations must be auditable and traceable",
            "negotiable": false
          }
        ]
      }
    ],
    "autonomy": {
      "level": "supervised",
      "human_checkpoints": [
        "before making irreversible changes"
      ],
      "escalation_triggers": [
        "error_rate > 5",
        "consecutive_failures > 3"
      ]
    },
    "safety": {
      "action_permissions": [
        {
          "action": "points_earned",
          "permission": "autonomous"
        },
        {
          "action": "reward_redeemed_discount",
          "permission": "autonomous"
        },
        {
          "action": "reward_redeemed_product",
          "permission": "autonomous"
        },
        {
          "action": "coupon_applied",
          "permission": "autonomous"
        },
        {
          "action": "gift_card_redeemed",
          "permission": "autonomous"
        },
        {
          "action": "insufficient_points",
          "permission": "autonomous"
        },
        {
          "action": "invalid_promo_code",
          "permission": "autonomous"
        },
        {
          "action": "minimum_not_met",
          "permission": "autonomous"
        }
      ]
    },
    "tradeoffs": [
      {
        "prefer": "accuracy",
        "over": "speed",
        "reason": "financial transactions must be precise and auditable"
      }
    ],
    "verification": {
      "invariants": [
        "error messages never expose internal system details"
      ]
    }
  },
  "extensions": {
    "source": {
      "repo": "https://github.com/odoo/odoo.git",
      "project": "Odoo",
      "tech_stack": "Python + JavaScript/OWL",
      "files_traced": 25,
      "entry_points": [
        "addons/loyalty/models/loyalty_program.py",
        "addons/loyalty/models/loyalty_rule.py",
        "addons/loyalty/models/loyalty_reward.py",
        "addons/sale_loyalty/models/sale_order.py"
      ]
    }
  }
}