Class: CloverSandboxSimulator::Generators::EntityGenerator

Inherits:
Object
  • Object
show all
Defined in:
lib/clover_sandbox_simulator/generators/entity_generator.rb

Overview

Creates restaurant entities in Clover (categories, items, discounts, etc.)

Constant Summary collapse

DEFAULT_EMPLOYEE_COUNT =

Configuration constants

5
DEFAULT_CUSTOMER_COUNT =
20
LOG_SEPARATOR =
"=" * 60

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(services: nil, business_type: :restaurant) ⇒ EntityGenerator

Returns a new instance of EntityGenerator.



14
15
16
17
18
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 14

def initialize(services: nil, business_type: :restaurant)
  @services = services || Services::Clover::ServicesManager.new
  @data = DataLoader.new(business_type: business_type)
  @logger = CloverSandboxSimulator.logger
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



12
13
14
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 12

def data
  @data
end

#loggerObject (readonly)

Returns the value of attribute logger.



12
13
14
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 12

def logger
  @logger
end

#servicesObject (readonly)

Returns the value of attribute services.



12
13
14
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 12

def services
  @services
end

Instance Method Details

#assign_item_tax_rates(items, tax_rates) ⇒ Object

Assign tax rates to items based on category mapping Assign tax rates to items based on category mapping (idempotent)



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 266

def assign_item_tax_rates(items, tax_rates)
  logger.info "Assigning tax rates to items by category..."
  category_mapping = data.category_tax_mapping

  return if category_mapping.empty? || tax_rates.empty?

  # Build lookup for tax rates by name
  tax_rate_lookup = tax_rates.each_with_object({}) do |rate, hash|
    hash[rate["name"]&.downcase] = rate["id"]
  end

  # Build lookup of existing item-tax associations
  existing_associations = build_item_tax_association_lookup(items, tax_rates)

  assigned_count = 0
  skipped_count = 0
  items.each do |item|
    category = item.dig("categories", "elements", 0, "name") || item["category"]
    next unless category

    applicable_taxes = category_mapping[category] || category_mapping["default"] || []

    applicable_taxes.each do |tax_name|
      tax_rate_id = tax_rate_lookup[tax_name.downcase]
      next unless tax_rate_id

      # Check if association already exists
      item_associations = existing_associations[item["id"]] || []
      if item_associations.include?(tax_rate_id)
        skipped_count += 1
        next
      end

      begin
        services.tax.associate_item_with_tax_rate(item["id"], tax_rate_id)
        assigned_count += 1
      rescue StandardError => e
        logger.debug "Could not assign tax to item #{item["id"]}: #{e.message}"
      end
    end
  end

  logger.info "Assigned #{assigned_count} new tax rate associations (#{skipped_count} already existed)"
end

#build_item_tax_association_lookup(items, tax_rates) ⇒ Hash

Build lookup of existing item-tax associations

Returns:

  • (Hash)

    { item_id => [tax_rate_ids] }



313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 313

def build_item_tax_association_lookup(items, tax_rates)
  associations = {}

  # Try to fetch existing associations from each tax rate
  tax_rates.each do |rate|
    begin
      items_for_rate = services.tax.get_items_for_tax_rate(rate["id"])
      items_for_rate.each do |item|
        associations[item["id"]] ||= []
        associations[item["id"]] << rate["id"]
      end
    rescue StandardError => e
      logger.debug "Could not fetch items for tax rate #{rate["id"]}: #{e.message}"
    end
  end

  associations
end

#delete_allObject

Delete all entities (for clean slate)



333
334
335
336
337
338
339
340
341
342
343
344
345
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 333

def delete_all
  logger.warn "=" * 60
  logger.warn "DELETING ALL ENTITIES..."
  logger.warn "=" * 60

  services.inventory.delete_all

  services.discount.get_discounts.each do |d|
    services.discount.delete_discount(d["id"])
  end

  logger.info "All entities deleted"
end

#ensure_modifiers_for_group(group, expected_modifiers) ⇒ Object

Ensure all modifiers exist within a group (idempotent)



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 192

def ensure_modifiers_for_group(group, expected_modifiers)
  return if expected_modifiers.empty?

  # Get existing modifiers for this group
  existing_modifiers = group.dig("modifiers", "elements") || []
  existing_names = existing_modifiers.map { |m| m["name"]&.downcase }

  missing_count = 0
  expected_modifiers.each do |mod_data|
    next if existing_names.include?(mod_data["name"]&.downcase)

    logger.debug "  Creating missing modifier: #{mod_data["name"]}"
    services.inventory.create_modifier(
      modifier_group_id: group["id"],
      name: mod_data["name"],
      price: mod_data["price"] || 0
    )
    missing_count += 1
  end

  logger.info "  Created #{missing_count} missing modifiers for '#{group["name"]}'" if missing_count > 0
end

#setup_allObject

Set up all entities (categories, items, discounts, etc.)



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 21

def setup_all
  logger.info LOG_SEPARATOR
  logger.info "Setting up restaurant entities in Clover..."
  logger.info LOG_SEPARATOR

  results = {
    categories: setup_categories,
    items: setup_items,
    modifier_groups: setup_modifier_groups,
    discounts: setup_discounts,
    employees: setup_employees,
    customers: setup_customers,
    order_types: setup_order_types,
    tax_rates: setup_tax_rates
  }

  # Assign tax rates to items based on category
  assign_item_tax_rates(results[:items], results[:tax_rates]) if results[:items].any? && results[:tax_rates].any?

  logger.info LOG_SEPARATOR
  logger.info "Entity setup complete!"
  logger.info "  Categories: #{results[:categories].size}"
  logger.info "  Items: #{results[:items].size}"
  logger.info "  Modifier Groups: #{results[:modifier_groups].size}"
  logger.info "  Discounts: #{results[:discounts].size}"
  logger.info "  Employees: #{results[:employees].size}"
  logger.info "  Customers: #{results[:customers].size}"
  logger.info "  Order Types: #{results[:order_types].size}"
  logger.info "  Tax Rates: #{results[:tax_rates].size}"
  logger.info LOG_SEPARATOR

  results
end

#setup_categoriesObject

Create categories from data file



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 56

def setup_categories
  logger.info "Setting up categories..."

  existing = services.inventory.get_categories
  existing_names = existing.map { |c| c["name"]&.downcase }

  created = []
  data.categories.each do |cat_data|
    if existing_names.include?(cat_data["name"]&.downcase)
      logger.debug "Category '#{cat_data["name"]}' already exists, skipping"
      created << existing.find { |c| c["name"] == cat_data["name"] }
    else
      cat = services.inventory.create_category(
        name: cat_data["name"],
        sort_order: cat_data["sort_order"]
      )
      created << cat if cat
    end
  end

  logger.info "Categories ready: #{created.size}"
  created
end

#setup_customersObject

Ensure customers exist



224
225
226
227
228
229
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 224

def setup_customers
  logger.info "Setting up customers..."
  customers = services.customer.ensure_customers(count: DEFAULT_CUSTOMER_COUNT)
  logger.info "Customers ready: #{customers.size}"
  customers
end

#setup_discountsObject

Create discounts from data file



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 115

def setup_discounts
  logger.info "Setting up discounts..."

  existing = services.discount.get_discounts
  existing_names = existing.map { |d| d["name"]&.downcase }

  created = []
  data.discounts.each do |disc_data|
    if existing_names.include?(disc_data["name"]&.downcase)
      logger.debug "Discount '#{disc_data["name"]}' already exists, skipping"
      created << existing.find { |d| d["name"] == disc_data["name"] }
    else
      disc = if disc_data["percentage"]
               services.discount.create_percentage_discount(
                 name: disc_data["name"],
                 percentage: disc_data["percentage"]
               )
             else
               services.discount.create_fixed_discount(
                 name: disc_data["name"],
                 amount: disc_data["amount"]
               )
             end
      created << disc if disc
    end
  end

  logger.info "Discounts ready: #{created.size}"
  created
end

#setup_employeesObject

Ensure employees exist



216
217
218
219
220
221
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 216

def setup_employees
  logger.info "Setting up employees..."
  employees = services.employee.ensure_employees(count: DEFAULT_EMPLOYEE_COUNT)
  logger.info "Employees ready: #{employees.size}"
  employees
end

#setup_itemsObject

Create items from data file



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 81

def setup_items
  logger.info "Setting up menu items..."

  # Build category lookup
  categories = services.inventory.get_categories
  category_lookup = categories.each_with_object({}) do |cat, hash|
    hash[cat["name"]] = cat["id"]
  end

  existing = services.inventory.get_items
  existing_names = existing.map { |i| i["name"]&.downcase }

  created = []
  data.items.each do |item_data|
    if existing_names.include?(item_data["name"]&.downcase)
      logger.debug "Item '#{item_data["name"]}' already exists, skipping"
      created << existing.find { |i| i["name"] == item_data["name"] }
    else
      category_id = category_lookup[item_data["category"]]

      item = services.inventory.create_item(
        name: item_data["name"],
        price: item_data["price"],
        category_id: category_id
      )
      created << item if item
    end
  end

  logger.info "Items ready: #{created.size}"
  created
end

#setup_modifier_groupsObject

Create modifier groups from data file Ensures both groups AND their child modifiers exist (idempotent)



148
149
150
151
152
153
154
155
156
157
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
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 148

def setup_modifier_groups
  logger.info "Setting up modifier groups..."

  existing = services.inventory.get_modifier_groups
  existing_by_name = existing.each_with_object({}) { |mg, h| h[mg["name"]&.downcase] = mg }

  created = []
  data.modifiers.each do |group_data|
    group_name_lower = group_data["name"]&.downcase

    if existing_by_name.key?(group_name_lower)
      # Group exists - but ensure modifiers are also present
      group = existing_by_name[group_name_lower]
      logger.debug "Modifier group '#{group_data["name"]}' already exists, checking modifiers..."
      ensure_modifiers_for_group(group, group_data["modifiers"] || [])
      created << group
    else
      # Create new group and its modifiers
      group = services.inventory.create_modifier_group(
        name: group_data["name"],
        min_required: group_data["min_required"] || 0,
        max_allowed: group_data["max_allowed"]
      )

      if group && group["id"]
        # Create modifiers within the group
        (group_data["modifiers"] || []).each do |mod_data|
          services.inventory.create_modifier(
            modifier_group_id: group["id"],
            name: mod_data["name"],
            price: mod_data["price"] || 0
          )
        end
      end

      created << group if group
    end
  end

  logger.info "Modifier groups ready: #{created.size}"
  created
end

#setup_order_typesObject

Set up order types (Dine In, Takeout, Delivery, etc.)



232
233
234
235
236
237
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 232

def setup_order_types
  logger.info "Setting up order types..."
  order_types = services.order_type.setup_default_order_types
  logger.info "Order types ready: #{order_types.size}"
  order_types
end

#setup_tax_ratesObject

Set up tax rates from data file



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/clover_sandbox_simulator/generators/entity_generator.rb', line 240

def setup_tax_rates
  logger.info "Setting up tax rates..."
  existing = services.tax.get_tax_rates
  existing_names = existing.map { |r| r["name"]&.downcase }

  created = []
  data.tax_rates.each do |rate_data|
    if existing_names.include?(rate_data["name"].downcase)
      logger.debug "Tax rate '#{rate_data["name"]}' already exists, skipping"
      created << existing.find { |r| r["name"]&.downcase == rate_data["name"].downcase }
    else
      rate = services.tax.create_tax_rate(
        name: rate_data["name"],
        rate: rate_data["rate"],
        is_default: rate_data["is_default"] || false
      )
      created << rate if rate
    end
  end

  logger.info "Tax rates ready: #{created.size}"
  created
end