clover_sandbox_simulator 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +10 -0
- data/README.md +316 -0
- data/bin/simulate +209 -0
- data/lib/clover_sandbox_simulator/configuration.rb +51 -0
- data/lib/clover_sandbox_simulator/data/restaurant/categories.json +39 -0
- data/lib/clover_sandbox_simulator/data/restaurant/discounts.json +39 -0
- data/lib/clover_sandbox_simulator/data/restaurant/items.json +238 -0
- data/lib/clover_sandbox_simulator/data/restaurant/modifiers.json +62 -0
- data/lib/clover_sandbox_simulator/data/restaurant/tenders.json +41 -0
- data/lib/clover_sandbox_simulator/generators/data_loader.rb +54 -0
- data/lib/clover_sandbox_simulator/generators/entity_generator.rb +164 -0
- data/lib/clover_sandbox_simulator/generators/order_generator.rb +540 -0
- data/lib/clover_sandbox_simulator/services/base_service.rb +111 -0
- data/lib/clover_sandbox_simulator/services/clover/customer_service.rb +82 -0
- data/lib/clover_sandbox_simulator/services/clover/discount_service.rb +58 -0
- data/lib/clover_sandbox_simulator/services/clover/employee_service.rb +82 -0
- data/lib/clover_sandbox_simulator/services/clover/inventory_service.rb +120 -0
- data/lib/clover_sandbox_simulator/services/clover/order_service.rb +170 -0
- data/lib/clover_sandbox_simulator/services/clover/payment_service.rb +123 -0
- data/lib/clover_sandbox_simulator/services/clover/services_manager.rb +49 -0
- data/lib/clover_sandbox_simulator/services/clover/tax_service.rb +53 -0
- data/lib/clover_sandbox_simulator/services/clover/tender_service.rb +117 -0
- data/lib/clover_sandbox_simulator.rb +43 -0
- metadata +195 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
{
|
|
2
|
+
"items": [
|
|
3
|
+
{
|
|
4
|
+
"name": "Buffalo Wings",
|
|
5
|
+
"price": 1299,
|
|
6
|
+
"category": "Appetizers",
|
|
7
|
+
"description": "Crispy wings tossed in buffalo sauce"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"name": "Loaded Nachos",
|
|
11
|
+
"price": 1099,
|
|
12
|
+
"category": "Appetizers",
|
|
13
|
+
"description": "Tortilla chips with cheese, jalapeños, and salsa"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "Mozzarella Sticks",
|
|
17
|
+
"price": 899,
|
|
18
|
+
"category": "Appetizers",
|
|
19
|
+
"description": "Golden fried with marinara sauce"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"name": "Spinach Artichoke Dip",
|
|
23
|
+
"price": 1199,
|
|
24
|
+
"category": "Appetizers",
|
|
25
|
+
"description": "Creamy dip with tortilla chips"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "Calamari",
|
|
29
|
+
"price": 1399,
|
|
30
|
+
"category": "Appetizers",
|
|
31
|
+
"description": "Lightly fried with aioli"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "Classic Burger",
|
|
35
|
+
"price": 1499,
|
|
36
|
+
"category": "Entrees",
|
|
37
|
+
"description": "8oz beef patty with lettuce, tomato, onion"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "Bacon Cheeseburger",
|
|
41
|
+
"price": 1699,
|
|
42
|
+
"category": "Entrees",
|
|
43
|
+
"description": "Burger with bacon and cheddar"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "Grilled Salmon",
|
|
47
|
+
"price": 2199,
|
|
48
|
+
"category": "Entrees",
|
|
49
|
+
"description": "Atlantic salmon with lemon herb butter"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "NY Strip Steak",
|
|
53
|
+
"price": 2899,
|
|
54
|
+
"category": "Entrees",
|
|
55
|
+
"description": "12oz steak cooked to order"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"name": "Chicken Parmesan",
|
|
59
|
+
"price": 1899,
|
|
60
|
+
"category": "Entrees",
|
|
61
|
+
"description": "Breaded chicken with marinara and mozzarella"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "Fettuccine Alfredo",
|
|
65
|
+
"price": 1599,
|
|
66
|
+
"category": "Entrees",
|
|
67
|
+
"description": "Creamy parmesan sauce over pasta"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "Fish and Chips",
|
|
71
|
+
"price": 1699,
|
|
72
|
+
"category": "Entrees",
|
|
73
|
+
"description": "Beer-battered cod with fries"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"name": "BBQ Ribs",
|
|
77
|
+
"price": 2399,
|
|
78
|
+
"category": "Entrees",
|
|
79
|
+
"description": "Full rack with house BBQ sauce"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"name": "Caesar Salad",
|
|
83
|
+
"price": 1199,
|
|
84
|
+
"category": "Entrees",
|
|
85
|
+
"description": "Romaine, parmesan, croutons"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"name": "Grilled Chicken Salad",
|
|
89
|
+
"price": 1399,
|
|
90
|
+
"category": "Entrees",
|
|
91
|
+
"description": "Mixed greens with grilled chicken"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"name": "French Fries",
|
|
95
|
+
"price": 499,
|
|
96
|
+
"category": "Sides",
|
|
97
|
+
"description": "Crispy golden fries"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"name": "Sweet Potato Fries",
|
|
101
|
+
"price": 599,
|
|
102
|
+
"category": "Sides",
|
|
103
|
+
"description": "With honey drizzle"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"name": "Onion Rings",
|
|
107
|
+
"price": 549,
|
|
108
|
+
"category": "Sides",
|
|
109
|
+
"description": "Beer-battered and fried"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"name": "Coleslaw",
|
|
113
|
+
"price": 399,
|
|
114
|
+
"category": "Sides",
|
|
115
|
+
"description": "Creamy house-made coleslaw"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "Mashed Potatoes",
|
|
119
|
+
"price": 499,
|
|
120
|
+
"category": "Sides",
|
|
121
|
+
"description": "Creamy with gravy"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"name": "Steamed Vegetables",
|
|
125
|
+
"price": 449,
|
|
126
|
+
"category": "Sides",
|
|
127
|
+
"description": "Seasonal vegetables"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"name": "Chocolate Brownie",
|
|
131
|
+
"price": 699,
|
|
132
|
+
"category": "Desserts",
|
|
133
|
+
"description": "Warm brownie with ice cream"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"name": "New York Cheesecake",
|
|
137
|
+
"price": 799,
|
|
138
|
+
"category": "Desserts",
|
|
139
|
+
"description": "Classic creamy cheesecake"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"name": "Apple Pie",
|
|
143
|
+
"price": 749,
|
|
144
|
+
"category": "Desserts",
|
|
145
|
+
"description": "A la mode with vanilla ice cream"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"name": "Tiramisu",
|
|
149
|
+
"price": 899,
|
|
150
|
+
"category": "Desserts",
|
|
151
|
+
"description": "Italian coffee-flavored dessert"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"name": "Soft Drink",
|
|
155
|
+
"price": 299,
|
|
156
|
+
"category": "Drinks",
|
|
157
|
+
"description": "Coke, Sprite, Dr Pepper"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"name": "Iced Tea",
|
|
161
|
+
"price": 299,
|
|
162
|
+
"category": "Drinks",
|
|
163
|
+
"description": "Fresh brewed, sweetened or unsweetened"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"name": "Lemonade",
|
|
167
|
+
"price": 349,
|
|
168
|
+
"category": "Drinks",
|
|
169
|
+
"description": "Fresh squeezed lemonade"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"name": "Coffee",
|
|
173
|
+
"price": 349,
|
|
174
|
+
"category": "Drinks",
|
|
175
|
+
"description": "Regular or decaf"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"name": "Hot Tea",
|
|
179
|
+
"price": 299,
|
|
180
|
+
"category": "Drinks",
|
|
181
|
+
"description": "Assorted flavors"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"name": "Draft Beer",
|
|
185
|
+
"price": 599,
|
|
186
|
+
"category": "Alcoholic Beverages",
|
|
187
|
+
"description": "Rotating selection of craft beers"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"name": "Domestic Beer",
|
|
191
|
+
"price": 499,
|
|
192
|
+
"category": "Alcoholic Beverages",
|
|
193
|
+
"description": "Bud Light, Coors, Miller"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"name": "Import Beer",
|
|
197
|
+
"price": 649,
|
|
198
|
+
"category": "Alcoholic Beverages",
|
|
199
|
+
"description": "Corona, Heineken, Guinness"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"name": "House Wine",
|
|
203
|
+
"price": 799,
|
|
204
|
+
"category": "Alcoholic Beverages",
|
|
205
|
+
"description": "Red or white by the glass"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"name": "Premium Wine",
|
|
209
|
+
"price": 1199,
|
|
210
|
+
"category": "Alcoholic Beverages",
|
|
211
|
+
"description": "Cabernet, Chardonnay, Pinot Noir"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"name": "Margarita",
|
|
215
|
+
"price": 999,
|
|
216
|
+
"category": "Alcoholic Beverages",
|
|
217
|
+
"description": "House or frozen"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"name": "Long Island Iced Tea",
|
|
221
|
+
"price": 1099,
|
|
222
|
+
"category": "Alcoholic Beverages",
|
|
223
|
+
"description": "Classic cocktail"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"name": "Chef's Special",
|
|
227
|
+
"price": 2499,
|
|
228
|
+
"category": "Specials",
|
|
229
|
+
"description": "Ask your server for today's special"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"name": "Soup of the Day",
|
|
233
|
+
"price": 599,
|
|
234
|
+
"category": "Specials",
|
|
235
|
+
"description": "Fresh made daily"
|
|
236
|
+
}
|
|
237
|
+
]
|
|
238
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"modifier_groups": [
|
|
3
|
+
{
|
|
4
|
+
"name": "Temperature",
|
|
5
|
+
"min_required": 0,
|
|
6
|
+
"max_allowed": 1,
|
|
7
|
+
"modifiers": [
|
|
8
|
+
{ "name": "Rare", "price": 0 },
|
|
9
|
+
{ "name": "Medium Rare", "price": 0 },
|
|
10
|
+
{ "name": "Medium", "price": 0 },
|
|
11
|
+
{ "name": "Medium Well", "price": 0 },
|
|
12
|
+
{ "name": "Well Done", "price": 0 }
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "Add-Ons",
|
|
17
|
+
"min_required": 0,
|
|
18
|
+
"max_allowed": 5,
|
|
19
|
+
"modifiers": [
|
|
20
|
+
{ "name": "Extra Cheese", "price": 150 },
|
|
21
|
+
{ "name": "Bacon", "price": 200 },
|
|
22
|
+
{ "name": "Avocado", "price": 175 },
|
|
23
|
+
{ "name": "Fried Egg", "price": 125 },
|
|
24
|
+
{ "name": "Jalapeños", "price": 75 }
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "Side Choice",
|
|
29
|
+
"min_required": 1,
|
|
30
|
+
"max_allowed": 1,
|
|
31
|
+
"modifiers": [
|
|
32
|
+
{ "name": "French Fries", "price": 0 },
|
|
33
|
+
{ "name": "Sweet Potato Fries", "price": 100 },
|
|
34
|
+
{ "name": "Onion Rings", "price": 100 },
|
|
35
|
+
{ "name": "Side Salad", "price": 0 },
|
|
36
|
+
{ "name": "Coleslaw", "price": 0 }
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "Dressing",
|
|
41
|
+
"min_required": 0,
|
|
42
|
+
"max_allowed": 1,
|
|
43
|
+
"modifiers": [
|
|
44
|
+
{ "name": "Ranch", "price": 0 },
|
|
45
|
+
{ "name": "Blue Cheese", "price": 0 },
|
|
46
|
+
{ "name": "Caesar", "price": 0 },
|
|
47
|
+
{ "name": "Balsamic Vinaigrette", "price": 0 },
|
|
48
|
+
{ "name": "Honey Mustard", "price": 0 }
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "Drink Size",
|
|
53
|
+
"min_required": 1,
|
|
54
|
+
"max_allowed": 1,
|
|
55
|
+
"modifiers": [
|
|
56
|
+
{ "name": "Small", "price": 0 },
|
|
57
|
+
{ "name": "Medium", "price": 50 },
|
|
58
|
+
{ "name": "Large", "price": 100 }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tenders": [
|
|
3
|
+
{
|
|
4
|
+
"label": "Cash",
|
|
5
|
+
"label_key": "com.clover.tender.cash",
|
|
6
|
+
"opens_cash_drawer": true,
|
|
7
|
+
"weight": 30
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"label": "Check",
|
|
11
|
+
"label_key": "com.clover.tender.check",
|
|
12
|
+
"opens_cash_drawer": true,
|
|
13
|
+
"weight": 5
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"label": "Gift Card",
|
|
17
|
+
"label_key": "com.clover.tender.external_gift_card",
|
|
18
|
+
"opens_cash_drawer": false,
|
|
19
|
+
"weight": 15
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"label": "External Payment",
|
|
23
|
+
"label_key": "com.clover.tender.external_payment",
|
|
24
|
+
"opens_cash_drawer": false,
|
|
25
|
+
"weight": 10
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"label": "Mobile Payment",
|
|
29
|
+
"label_key": "com.clover.tender.mobile_payment",
|
|
30
|
+
"opens_cash_drawer": false,
|
|
31
|
+
"weight": 20
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"label": "Store Credit",
|
|
35
|
+
"label_key": "com.clover.tender.store_credit",
|
|
36
|
+
"opens_cash_drawer": false,
|
|
37
|
+
"weight": 10
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"note": "Credit Card and Debit Card are intentionally excluded - they are broken in Clover sandbox"
|
|
41
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CloverSandboxSimulator
|
|
4
|
+
module Generators
|
|
5
|
+
# Loads data from JSON files for different business types
|
|
6
|
+
class DataLoader
|
|
7
|
+
attr_reader :business_type
|
|
8
|
+
|
|
9
|
+
def initialize(business_type: :restaurant)
|
|
10
|
+
@business_type = business_type
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def categories
|
|
14
|
+
@categories ||= load_json("categories")["categories"]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def items
|
|
18
|
+
@items ||= load_json("items")["items"]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def discounts
|
|
22
|
+
@discounts ||= load_json("discounts")["discounts"]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def tenders
|
|
26
|
+
@tenders ||= load_json("tenders")["tenders"]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def modifiers
|
|
30
|
+
@modifiers ||= load_json("modifiers")["modifier_groups"]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def items_for_category(category_name)
|
|
34
|
+
items.select { |item| item["category"] == category_name }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def load_json(filename)
|
|
40
|
+
path = File.join(data_path, "#{filename}.json")
|
|
41
|
+
|
|
42
|
+
unless File.exist?(path)
|
|
43
|
+
raise Error, "Data file not found: #{path}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
JSON.parse(File.read(path))
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def data_path
|
|
50
|
+
File.join(CloverSandboxSimulator.root, "lib", "clover_sandbox_simulator", "data", business_type.to_s)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CloverSandboxSimulator
|
|
4
|
+
module Generators
|
|
5
|
+
# Creates restaurant entities in Clover (categories, items, discounts, etc.)
|
|
6
|
+
class EntityGenerator
|
|
7
|
+
attr_reader :services, :data, :logger
|
|
8
|
+
|
|
9
|
+
def initialize(services: nil, business_type: :restaurant)
|
|
10
|
+
@services = services || Services::Clover::ServicesManager.new
|
|
11
|
+
@data = DataLoader.new(business_type: business_type)
|
|
12
|
+
@logger = CloverSandboxSimulator.logger
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Set up all entities (categories, items, discounts, etc.)
|
|
16
|
+
def setup_all
|
|
17
|
+
logger.info "=" * 60
|
|
18
|
+
logger.info "Setting up restaurant entities in Clover..."
|
|
19
|
+
logger.info "=" * 60
|
|
20
|
+
|
|
21
|
+
results = {
|
|
22
|
+
categories: setup_categories,
|
|
23
|
+
items: setup_items,
|
|
24
|
+
discounts: setup_discounts,
|
|
25
|
+
employees: setup_employees,
|
|
26
|
+
customers: setup_customers
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
logger.info "=" * 60
|
|
30
|
+
logger.info "Entity setup complete!"
|
|
31
|
+
logger.info " Categories: #{results[:categories].size}"
|
|
32
|
+
logger.info " Items: #{results[:items].size}"
|
|
33
|
+
logger.info " Discounts: #{results[:discounts].size}"
|
|
34
|
+
logger.info " Employees: #{results[:employees].size}"
|
|
35
|
+
logger.info " Customers: #{results[:customers].size}"
|
|
36
|
+
logger.info "=" * 60
|
|
37
|
+
|
|
38
|
+
results
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Create categories from data file
|
|
42
|
+
def setup_categories
|
|
43
|
+
logger.info "Setting up categories..."
|
|
44
|
+
|
|
45
|
+
existing = services.inventory.get_categories
|
|
46
|
+
existing_names = existing.map { |c| c["name"] }
|
|
47
|
+
|
|
48
|
+
created = []
|
|
49
|
+
data.categories.each do |cat_data|
|
|
50
|
+
if existing_names.include?(cat_data["name"])
|
|
51
|
+
logger.debug "Category '#{cat_data["name"]}' already exists, skipping"
|
|
52
|
+
created << existing.find { |c| c["name"] == cat_data["name"] }
|
|
53
|
+
else
|
|
54
|
+
cat = services.inventory.create_category(
|
|
55
|
+
name: cat_data["name"],
|
|
56
|
+
sort_order: cat_data["sort_order"]
|
|
57
|
+
)
|
|
58
|
+
created << cat if cat
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
logger.info "Categories ready: #{created.size}"
|
|
63
|
+
created
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Create items from data file
|
|
67
|
+
def setup_items
|
|
68
|
+
logger.info "Setting up menu items..."
|
|
69
|
+
|
|
70
|
+
# Build category lookup
|
|
71
|
+
categories = services.inventory.get_categories
|
|
72
|
+
category_lookup = categories.each_with_object({}) do |cat, hash|
|
|
73
|
+
hash[cat["name"]] = cat["id"]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
existing = services.inventory.get_items
|
|
77
|
+
existing_names = existing.map { |i| i["name"] }
|
|
78
|
+
|
|
79
|
+
created = []
|
|
80
|
+
data.items.each do |item_data|
|
|
81
|
+
if existing_names.include?(item_data["name"])
|
|
82
|
+
logger.debug "Item '#{item_data["name"]}' already exists, skipping"
|
|
83
|
+
created << existing.find { |i| i["name"] == item_data["name"] }
|
|
84
|
+
else
|
|
85
|
+
category_id = category_lookup[item_data["category"]]
|
|
86
|
+
|
|
87
|
+
item = services.inventory.create_item(
|
|
88
|
+
name: item_data["name"],
|
|
89
|
+
price: item_data["price"],
|
|
90
|
+
category_id: category_id
|
|
91
|
+
)
|
|
92
|
+
created << item if item
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
logger.info "Items ready: #{created.size}"
|
|
97
|
+
created
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Create discounts from data file
|
|
101
|
+
def setup_discounts
|
|
102
|
+
logger.info "Setting up discounts..."
|
|
103
|
+
|
|
104
|
+
existing = services.discount.get_discounts
|
|
105
|
+
existing_names = existing.map { |d| d["name"] }
|
|
106
|
+
|
|
107
|
+
created = []
|
|
108
|
+
data.discounts.each do |disc_data|
|
|
109
|
+
if existing_names.include?(disc_data["name"])
|
|
110
|
+
logger.debug "Discount '#{disc_data["name"]}' already exists, skipping"
|
|
111
|
+
created << existing.find { |d| d["name"] == disc_data["name"] }
|
|
112
|
+
else
|
|
113
|
+
disc = if disc_data["percentage"]
|
|
114
|
+
services.discount.create_percentage_discount(
|
|
115
|
+
name: disc_data["name"],
|
|
116
|
+
percentage: disc_data["percentage"]
|
|
117
|
+
)
|
|
118
|
+
else
|
|
119
|
+
services.discount.create_fixed_discount(
|
|
120
|
+
name: disc_data["name"],
|
|
121
|
+
amount: disc_data["amount"]
|
|
122
|
+
)
|
|
123
|
+
end
|
|
124
|
+
created << disc if disc
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
logger.info "Discounts ready: #{created.size}"
|
|
129
|
+
created
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Ensure employees exist
|
|
133
|
+
def setup_employees
|
|
134
|
+
logger.info "Setting up employees..."
|
|
135
|
+
employees = services.employee.ensure_employees(count: 5)
|
|
136
|
+
logger.info "Employees ready: #{employees.size}"
|
|
137
|
+
employees
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Ensure customers exist
|
|
141
|
+
def setup_customers
|
|
142
|
+
logger.info "Setting up customers..."
|
|
143
|
+
customers = services.customer.ensure_customers(count: 20)
|
|
144
|
+
logger.info "Customers ready: #{customers.size}"
|
|
145
|
+
customers
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Delete all entities (for clean slate)
|
|
149
|
+
def delete_all
|
|
150
|
+
logger.warn "=" * 60
|
|
151
|
+
logger.warn "DELETING ALL ENTITIES..."
|
|
152
|
+
logger.warn "=" * 60
|
|
153
|
+
|
|
154
|
+
services.inventory.delete_all
|
|
155
|
+
|
|
156
|
+
services.discount.get_discounts.each do |d|
|
|
157
|
+
services.discount.delete_discount(d["id"])
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
logger.info "All entities deleted"
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|