# Architecture Rules - Money Handling
# Rules for monetary value handling across the codebase
#
# Reference: docs/architecture/money-handling.md

money_handling_rules:

  - id: "MON-001"
    name: "Database columns for money must use Integer cents"
    severity: "error"
    description: |
      All monetary values in database models MUST be stored as integers representing
      cents (or smallest currency unit). This prevents floating-point precision errors.

      CORRECT:
        price_cents = Column(Integer)
        total_amount_cents = Column(Integer)
        sale_price_cents = Column(Integer, nullable=True)

      INCORRECT:
        price = Column(Float)
        total_amount = Column(Numeric(10, 2))

      Column naming convention: Use `_cents` suffix for all monetary columns.
    pattern:
      file_pattern:
        - "models/database/**/*.py"
        - "app/modules/*/models/**/*.py"
      required_patterns:
        - "_cents = Column(Integer"
      anti_patterns:
        - "price = Column(Float"
        - "amount = Column(Float"
        - "total = Column(Float"
        - "Column(Numeric"

  - id: "MON-002"
    name: "Use Money utility for conversions"
    severity: "error"
    description: |
      All euro/cents conversions MUST use the Money utility class or
      the euros_to_cents/cents_to_euros helper functions.

      Never use manual multiplication/division for money conversions.

      CORRECT:
        from app.utils.money import Money, euros_to_cents, cents_to_euros
        price_cents = euros_to_cents(19.99)
        display_price = cents_to_euros(price_cents)
        formatted = Money.format(price_cents, "EUR")

      INCORRECT:
        price_cents = int(price * 100)
        display_price = price_cents / 100
    pattern:
      file_pattern:
        - "app/**/*.py"
        - "models/**/*.py"
      required_imports:
        - "from app.utils.money import"
      anti_patterns:
        - "* 100"  # Manual cents conversion
        - "/ 100"  # Manual euros conversion
      exceptions:
        - "app/utils/money.py"  # The utility itself

  - id: "MON-003"
    name: "API responses use euros for display"
    severity: "error"
    description: |
      Pydantic response schemas MUST expose monetary values as floats (euros)
      for frontend consumption. Use computed properties to convert from _cents.

      CORRECT (in schema):
        price_cents: int  # Internal

        @computed_field
        @property
        def price(self) -> float:
            return cents_to_euros(self.price_cents)

      Or use model validators to convert before response serialization.
    pattern:
      file_pattern:
        - "models/schema/**/*.py"
        - "app/modules/*/schemas/**/*.py"
      check: "money_response_format"

  - id: "MON-004"
    name: "Frontend must use Money.format() for display"
    severity: "error"
    description: |
      All monetary value display in frontend MUST use the Money utility.
      This ensures consistent formatting across locales.

      CORRECT (JavaScript):
        Money.format(order.total_amount_cents, 'EUR')
        Money.formatEuros(order.total_amount)

      INCORRECT:
        `${order.total_amount} EUR`
        order.total_amount.toFixed(2)
    pattern:
      file_pattern:
        - "static/**/*.js"
        - "app/templates/**/*.html"
      required_patterns:
        - "Money.format"
        - "formatPrice"  # Helper function wrapping Money.format
      discouraged_patterns:
        - "toFixed(2)"
        - "${.*} EUR"

  - id: "MON-005"
    name: "All arithmetic on money uses integers"
    severity: "error"
    description: |
      All monetary calculations MUST be performed on integer cents values.
      Convert to euros ONLY for display purposes, never for calculations.

      CORRECT:
        subtotal_cents = sum(item.unit_price_cents * item.quantity for item in items)
        tax_cents = int(subtotal_cents * Decimal("0.17"))
        total_cents = subtotal_cents + tax_cents

      INCORRECT:
        subtotal = sum(item.price * item.quantity for item in items)
        tax = subtotal * 0.17  # Floating point!
        total = subtotal + tax
    pattern:
      file_pattern:
        - "app/services/**/*.py"
        - "app/modules/*/services/**/*.py"
      check: "money_arithmetic"

  - id: "MON-006"
    name: "CSV/External imports must convert to cents"
    severity: "error"
    description: |
      When importing monetary values from CSV files or external APIs,
      always convert to cents immediately upon parsing.

      CORRECT:
        price_cents = euros_to_cents(parsed_price)
        product.price_cents = price_cents

      INCORRECT:
        product.price = parsed_price  # Float assignment
    pattern:
      file_pattern:
        - "app/utils/csv_processor.py"
        - "app/services/**/import*.py"
      required_patterns:
        - "euros_to_cents"
        - "_cents"

  - id: "MON-007"
    name: "Test assertions use cents"
    severity: "warning"
    description: |
      Test assertions for monetary values should use integer cents
      to avoid floating-point comparison issues.

      CORRECT:
        assert order.total_amount_cents == 10591
        assert product.price_cents == 1999

      INCORRECT:
        assert order.total_amount == 105.91  # Float comparison
    pattern:
      file_pattern: "tests/**/*.py"
      encouraged_patterns:
        - "_cents =="
        - "_cents >"
        - "_cents <"
