Class: CloverSandboxSimulator::Generators::OrderGenerator
- Inherits:
-
Object
- Object
- CloverSandboxSimulator::Generators::OrderGenerator
- Defined in:
- lib/clover_sandbox_simulator/generators/order_generator.rb
Overview
Generates realistic restaurant orders and payments with enhanced discount support
Constant Summary collapse
- MEAL_PERIODS =
Meal periods with realistic distributions
{ breakfast: { hours: 7..10, weight: 15, avg_items: 2..4, avg_party: 1..2 }, lunch: { hours: 11..14, weight: 30, avg_items: 2..5, avg_party: 1..4 }, happy_hour: { hours: 15..17, weight: 10, avg_items: 2..4, avg_party: 2..4 }, dinner: { hours: 17..21, weight: 35, avg_items: 3..6, avg_party: 2..6 }, late_night: { hours: 21..23, weight: 10, avg_items: 2..4, avg_party: 1..3 } }.freeze
- DINING_BY_PERIOD =
Dining option distributions by meal period
{ breakfast: { "HERE" => 40, "TO_GO" => 50, "DELIVERY" => 10 }, lunch: { "HERE" => 35, "TO_GO" => 45, "DELIVERY" => 20 }, happy_hour: { "HERE" => 80, "TO_GO" => 15, "DELIVERY" => 5 }, dinner: { "HERE" => 70, "TO_GO" => 15, "DELIVERY" => 15 }, late_night: { "HERE" => 50, "TO_GO" => 30, "DELIVERY" => 20 } }.freeze
- TIP_RATES =
Tip percentages by dining option
{ "HERE" => { min: 15, max: 25 }, # Dine-in tips higher "TO_GO" => { min: 0, max: 15 }, # Takeout tips lower "DELIVERY" => { min: 10, max: 20 } # Delivery tips moderate }.freeze
- ORDER_PATTERNS =
Order patterns by day of week
{ weekday: { min: 40, max: 60 }, friday: { min: 70, max: 100 }, saturday: { min: 80, max: 120 }, sunday: { min: 50, max: 80 } }.freeze
- CATEGORY_PREFERENCES =
Category preferences by meal period
{ breakfast: ["Drinks", "Sides"], lunch: ["Appetizers", "Entrees", "Sides", "Drinks"], happy_hour: ["Appetizers", "Alcoholic Beverages", "Drinks"], dinner: ["Appetizers", "Entrees", "Sides", "Desserts", "Alcoholic Beverages", "Drinks"], late_night: ["Appetizers", "Entrees", "Alcoholic Beverages", "Desserts"] }.freeze
- DISCOUNT_PROBABILITIES =
Discount application probabilities
{ promo_code: 0.08, # 8% use a promo code loyalty: 0.15, # 15% are loyalty members combo: 0.12, # 12% get combo discount time_based: 0.90, # 90% of eligible get time discounts line_item: 0.10, # 10% get line item discounts threshold: 0.20 # 20% get threshold discounts }.freeze
- GIFT_CARD_CONFIG =
Gift card configuration
{ payment_chance: 10, # 10% of orders may use gift cards for payment purchase_chance: 5, # 5% of orders may include gift card purchase full_payment_chance: 60 # 60% of gift card payments cover full amount }.freeze
- REFUND_REASONS =
Refund reasons
%w[customer_request quality_issue wrong_order duplicate_charge].freeze
Instance Attribute Summary collapse
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
-
#refund_percentage ⇒ Object
readonly
Returns the value of attribute refund_percentage.
-
#services ⇒ Object
readonly
Returns the value of attribute services.
-
#stats ⇒ Object
readonly
Returns the value of attribute stats.
Instance Method Summary collapse
-
#generate_for_date(date, count:) ⇒ Object
Generate specific count of orders.
-
#generate_realistic_day(date: Date.today, multiplier: 1.0, simulated_time: nil) ⇒ Object
Generate a realistic day of restaurant operations.
-
#generate_today(count: nil) ⇒ Object
Generate orders for today (simple mode).
-
#initialize(services: nil, refund_percentage: 5) ⇒ OrderGenerator
constructor
A new instance of OrderGenerator.
-
#process_order_refund(order) ⇒ Object
Process a refund for a single order.
-
#process_refunds(orders) ⇒ Object
Process refunds for a percentage of completed orders.
Constructor Details
#initialize(services: nil, refund_percentage: 5) ⇒ OrderGenerator
Returns a new instance of OrderGenerator.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/clover_sandbox_simulator/generators/order_generator.rb', line 71 def initialize(services: nil, refund_percentage: 5) @services = services || Services::Clover::ServicesManager.new @logger = CloverSandboxSimulator.logger @refund_percentage = refund_percentage @stats = { orders: 0, revenue: 0, tips: 0, tax: 0, discounts: 0, by_period: {}, by_dining: {}, by_discount_type: {}, by_order_type: {}, gift_cards: { payments: 0, full_payments: 0, partial_payments: 0, purchases: 0, amount_redeemed: 0 }, refunds: { total: 0, full: 0, partial: 0, amount: 0 }, cash_events: { payments: 0, amount: 0 } } end |
Instance Attribute Details
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
69 70 71 |
# File 'lib/clover_sandbox_simulator/generators/order_generator.rb', line 69 def logger @logger end |
#refund_percentage ⇒ Object (readonly)
Returns the value of attribute refund_percentage.
69 70 71 |
# File 'lib/clover_sandbox_simulator/generators/order_generator.rb', line 69 def refund_percentage @refund_percentage end |
#services ⇒ Object (readonly)
Returns the value of attribute services.
69 70 71 |
# File 'lib/clover_sandbox_simulator/generators/order_generator.rb', line 69 def services @services end |
#stats ⇒ Object (readonly)
Returns the value of attribute stats.
69 70 71 |
# File 'lib/clover_sandbox_simulator/generators/order_generator.rb', line 69 def stats @stats end |
Instance Method Details
#generate_for_date(date, count:) ⇒ Object
Generate specific count of orders
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/clover_sandbox_simulator/generators/order_generator.rb', line 220 def generate_for_date(date, count:) logger.info "=" * 60 logger.info "Generating #{count} orders for #{date}" logger.info "=" * 60 data = fetch_required_data return [] unless data orders = [] count.times do |i| period = weighted_random_period order_time = generate_order_time(date, period) logger.info "-" * 40 logger.info "Creating order #{i + 1}/#{count} (#{period})" order = create_realistic_order( period: period, data: data, order_num: i + 1, total_in_period: count, order_time: order_time ) if order orders << order update_stats(order, period) end end # Process refunds for some orders process_refunds(orders) if refund_percentage > 0 print_summary orders end |
#generate_realistic_day(date: Date.today, multiplier: 1.0, simulated_time: nil) ⇒ Object
Generate a realistic day of restaurant operations
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/clover_sandbox_simulator/generators/order_generator.rb', line 92 def generate_realistic_day(date: Date.today, multiplier: 1.0, simulated_time: nil) count = (order_count_for_date(date) * multiplier).to_i logger.info "=" * 60 logger.info "Generating realistic restaurant day: #{date}" logger.info " Target orders: #{count}" logger.info " Day: #{date.strftime('%A')}" logger.info "=" * 60 # Fetch required data data = fetch_required_data return [] unless data # Distribute orders across meal periods period_orders = distribute_orders_by_period(count) orders = [] period_orders.each do |period, period_count| logger.info "-" * 40 logger.info "#{period.to_s.upcase} SERVICE: #{period_count} orders" period_count.times do |i| # Generate simulated time for the order order_time = simulated_time || generate_order_time(date, period) order = create_realistic_order( period: period, data: data, order_num: i + 1, total_in_period: period_count, order_time: order_time ) if order orders << order update_stats(order, period) end end end # Process refunds for some orders process_refunds(orders) if refund_percentage > 0 print_summary orders end |
#generate_today(count: nil) ⇒ Object
Generate orders for today (simple mode)
211 212 213 214 215 216 217 |
# File 'lib/clover_sandbox_simulator/generators/order_generator.rb', line 211 def generate_today(count: nil) if count generate_for_date(Date.today, count: count) else generate_realistic_day end end |
#process_order_refund(order) ⇒ Object
Process a refund for a single order
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/clover_sandbox_simulator/generators/order_generator.rb', line 158 def process_order_refund(order) order_id = order["id"] payments = order.dig("payments", "elements") || [] return if payments.empty? payment = payments.first payment_id = payment["id"] payment_amount = payment["amount"] || 0 return if payment_amount <= 0 # 60% full refunds, 40% partial refunds is_full_refund = rand < 0.6 reason = REFUND_REASONS.sample if is_full_refund # Full refund begin result = services.refund.create_full_refund(payment_id: payment_id, reason: reason) if result @stats[:refunds][:total] += 1 @stats[:refunds][:full] += 1 @stats[:refunds][:amount] += payment_amount logger.info " 💸 Full refund: Order #{order_id} - $#{'%.2f' % (payment_amount / 100.0)} (#{reason})" end rescue StandardError => e logger.warn " Failed to refund order #{order_id}: #{e.}" end else # Partial refund (25-75% of payment) refund_percent = rand(25..75) refund_amount = (payment_amount * refund_percent / 100.0).round begin result = services.refund.create_partial_refund( payment_id: payment_id, amount: refund_amount, reason: reason ) if result @stats[:refunds][:total] += 1 @stats[:refunds][:partial] += 1 @stats[:refunds][:amount] += refund_amount logger.info " 💸 Partial refund: Order #{order_id} - $#{'%.2f' % (refund_amount / 100.0)} of $#{'%.2f' % (payment_amount / 100.0)} (#{reason})" end rescue StandardError => e logger.warn " Failed to partially refund order #{order_id}: #{e.}" end end end |
#process_refunds(orders) ⇒ Object
Process refunds for a percentage of completed orders
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/clover_sandbox_simulator/generators/order_generator.rb', line 140 def process_refunds(orders) return if orders.empty? || refund_percentage <= 0 refund_count = (orders.size * refund_percentage / 100.0).ceil refund_count = [refund_count, orders.size].min logger.info "-" * 40 logger.info "PROCESSING REFUNDS: #{refund_count} orders (#{refund_percentage}%)" # Select random orders to refund orders_to_refund = orders.sample(refund_count) orders_to_refund.each do |order| process_order_refund(order) end end |