Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Date Time Conditions

Complete guide to date/time-based pricing conditions.

Overview

Date time conditions define when a pricing rule applies. Each condition specifies a date_type that determines which fields are required and how the condition evaluates.

Location: app/models/date_time_condition.rb

Date Types

Defined in: DATE_TYPES constant

date_typeDescriptionRequired FieldsUses condition_items
everydayApplies every day within rule periodaction_type, value_type, value❌ No
specific_dateApplies on specific datescondition_items with date fields✅ Yes
specific_timeApplies at specific times dailycondition_items with time fields✅ Yes
specific_date_timeApplies on specific dates AND timescondition_items with date & time✅ Yes
day_of_weekApplies on specific weekdaysdays_of_week array❌ No
day_time_of_weekApplies on specific weekdays AND timesdays_of_week + condition_items with time✅ Yes

Model Attributes

FieldTypeDescriptionRequired
pricing_rule_idIntegerParent rule (FK)✅ Yes
date_typeStringType of condition (see Date Types)✅ Yes
action_typeStringincrease or decreaseConditional
value_typeStringpercentage or fixedConditional
valueIntegerAmount in basis points or centsConditional
period_modeStringsingle or range❌ No
days_of_weekInteger[]Day numbers (0=Sun, 6=Sat)For day types

Value Storage Format

IMPORTANT: Values are stored as integers:

  • Percentage: Basis points (1% = 100 basis points)
  • Fixed Amount: Cents (IDR)

Examples:

  • 10% = 1000 basis points
  • 25% = 2500 basis points
  • IDR 5,000 = 500000 cents
  • IDR 10,000 = 1000000 cents

Action Types

Defined in: ACTION_TYPES constant

ValueDescription
increaseIncrease price by value
decreaseDecrease price by value

Value Types

Defined in: VALUE_TYPES constant

ValueDescriptionStorage Unit
percentagePercentage adjustmentBasis points (1% = 100)
fixedFixed amount adjustmentCents

Days of Week

Defined in: VALID_DAYS constant

Storage Format: Integer array (0-6)

IntegerDay
0Sunday
1Monday
2Tuesday
3Wednesday
4Thursday
5Friday
6Saturday

String constants (validation only):

["mon", "tue", "wed", "thu", "fri", "sat", "sun"]

API Usage: Send as integer array

{
  "days_of_week": [0, 6]  // Sunday and Saturday
}

Condition Items

Some date_types require condition_items (time slots):

Required for:

  • specific_date
  • specific_time
  • specific_date_time
  • day_time_of_week

Not required for:

  • everyday
  • day_of_week

See: app/models/condition_item.rb

Condition Item Fields

FieldTypeUsed by
start_dateDatespecific_date, specific_date_time
end_dateDatespecific_date, specific_date_time
start_timeTimespecific_time, specific_date_time, day_time_of_week
end_timeTimespecific_time, specific_date_time, day_time_of_week

Validations

Required Validations

  • date_type: Must be one of DATE_TYPES
  • action_type: Must be increase or decrease (if present)
  • value_type: Must be percentage or fixed (if present)
  • value: Must be integer >= 0 (if present)

Custom Validations

  • days_of_week_valid: If present, must be valid day numbers (0-6)
  • days_of_week_required_for_day_types: Required for day_of_week and day_time_of_week
  • condition_items_required_for_slot_types: Required for types with slots
  • action_configuration_complete: action_type, value_type, and value must all be present together

Scopes

By Date Type

DateTimeCondition.by_date_type('everyday')
DateTimeCondition.everyday
DateTimeCondition.specific_date
DateTimeCondition.specific_time
DateTimeCondition.specific_date_time
DateTimeCondition.day_of_week
DateTimeCondition.day_time_of_week

By Day

DateTimeCondition.for_day(0)           # Sunday
DateTimeCondition.for_day(Date.today)  # Today's weekday

Active

DateTimeCondition.active  # Conditions from active rules

Helper Methods

condition.everyday?              # Is everyday type?
condition.specific_date?         # Is specific_date type?
condition.specific_time?         # Is specific_time type?
condition.specific_date_time?    # Is specific_date_time type?
condition.day_of_week?           # Is day_of_week type?
condition.day_time_of_week?      # Is day_time_of_week type?

condition.requires_slots?        # Needs condition_items?
condition.uses_days_of_week?     # Uses days_of_week field?

Example Payloads

1. Everyday (All Day, Every Day)

{
  "date_type": "everyday",
  "action_type": "increase",
  "value_type": "percentage",
  "value": 1000
}

2. Specific Date (Certain Dates Only)

{
  "date_type": "specific_date",
  "action_type": "increase",
  "value_type": "percentage",
  "value": 1500,
  "condition_items_attributes": [
    {
      "start_date": "2025-01-15",
      "end_date": "2025-01-15"
    },
    {
      "start_date": "2025-02-14",
      "end_date": "2025-02-14"
    }
  ]
}

3. Specific Time (Daily Time Slots)

{
  "date_type": "specific_time",
  "action_type": "increase",
  "value_type": "percentage",
  "value": 2000,
  "condition_items_attributes": [
    {
      "start_time": "11:00",
      "end_time": "14:00"
    },
    {
      "start_time": "18:00",
      "end_time": "21:00"
    }
  ]
}

4. Specific Date Time (Exact Date + Time)

{
  "date_type": "specific_date_time",
  "action_type": "decrease",
  "value_type": "fixed",
  "value": 500000,
  "condition_items_attributes": [
    {
      "start_date": "2025-01-01",
      "end_date": "2025-01-01",
      "start_time": "10:00",
      "end_time": "12:00"
    }
  ]
}

5. Day of Week (Specific Weekdays, All Day)

{
  "date_type": "day_of_week",
  "days_of_week": [0, 6],
  "action_type": "increase",
  "value_type": "percentage",
  "value": 1000
}

6. Day Time of Week (Specific Weekdays + Times)

{
  "date_type": "day_time_of_week",
  "days_of_week": [5, 6],
  "action_type": "increase",
  "value_type": "percentage",
  "value": 1500,
  "condition_items_attributes": [
    {
      "start_time": "18:00",
      "end_time": "23:00"
    }
  ]
}

Nested Attributes

Conditions accept nested attributes for condition_items:

accepts_nested_attributes_for :condition_items,
                              allow_destroy: true,
                              reject_if: :all_blank

Cache Invalidation

Callback: after_commit :invalidate_pricing_rule_cache

Automatically invalidates parent rule’s cache after:

  • Create
  • Update
  • Destroy

Global Pricing Limits

All conditions are validated against restaurant’s global pricing limits:

Enforced at: PricingRule model level Validation: validate_global_pricing_limits

Limits check:

  • Increase/decrease values don’t exceed global limits
  • Value type matches global limit type

See: 007-GLOBAL-PRICING-SETTINGS.md