skytab_sandbox_simulator 0.1.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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +10 -0
  3. data/bin/simulate +433 -0
  4. data/lib/skytab_sandbox_simulator/configuration.rb +205 -0
  5. data/lib/skytab_sandbox_simulator/data/bar_nightclub/categories.json +9 -0
  6. data/lib/skytab_sandbox_simulator/data/bar_nightclub/items.json +28 -0
  7. data/lib/skytab_sandbox_simulator/data/bar_nightclub/tenders.json +19 -0
  8. data/lib/skytab_sandbox_simulator/data/cafe_bakery/categories.json +9 -0
  9. data/lib/skytab_sandbox_simulator/data/cafe_bakery/items.json +30 -0
  10. data/lib/skytab_sandbox_simulator/data/cafe_bakery/tenders.json +17 -0
  11. data/lib/skytab_sandbox_simulator/data/fine_dining/categories.json +9 -0
  12. data/lib/skytab_sandbox_simulator/data/fine_dining/items.json +30 -0
  13. data/lib/skytab_sandbox_simulator/data/fine_dining/tenders.json +18 -0
  14. data/lib/skytab_sandbox_simulator/data/pizzeria/categories.json +9 -0
  15. data/lib/skytab_sandbox_simulator/data/pizzeria/items.json +28 -0
  16. data/lib/skytab_sandbox_simulator/data/pizzeria/tenders.json +18 -0
  17. data/lib/skytab_sandbox_simulator/data/restaurant/categories.json +44 -0
  18. data/lib/skytab_sandbox_simulator/data/restaurant/items.json +59 -0
  19. data/lib/skytab_sandbox_simulator/data/restaurant/tenders.json +22 -0
  20. data/lib/skytab_sandbox_simulator/database.rb +192 -0
  21. data/lib/skytab_sandbox_simulator/db/factories/business_types.rb +102 -0
  22. data/lib/skytab_sandbox_simulator/db/factories/categories.rb +243 -0
  23. data/lib/skytab_sandbox_simulator/db/factories/items.rb +976 -0
  24. data/lib/skytab_sandbox_simulator/db/factories/simulated_orders.rb +120 -0
  25. data/lib/skytab_sandbox_simulator/db/factories/simulated_payments.rb +75 -0
  26. data/lib/skytab_sandbox_simulator/db/migrate/20260316000000_enable_pgcrypto.rb +7 -0
  27. data/lib/skytab_sandbox_simulator/db/migrate/20260316000001_create_business_types.rb +18 -0
  28. data/lib/skytab_sandbox_simulator/db/migrate/20260316000002_create_categories.rb +18 -0
  29. data/lib/skytab_sandbox_simulator/db/migrate/20260316000003_create_items.rb +23 -0
  30. data/lib/skytab_sandbox_simulator/db/migrate/20260316000004_create_simulated_orders.rb +35 -0
  31. data/lib/skytab_sandbox_simulator/db/migrate/20260316000005_create_simulated_payments.rb +26 -0
  32. data/lib/skytab_sandbox_simulator/db/migrate/20260316000006_create_api_requests.rb +27 -0
  33. data/lib/skytab_sandbox_simulator/db/migrate/20260316000007_create_daily_summaries.rb +24 -0
  34. data/lib/skytab_sandbox_simulator/generators/data_loader.rb +125 -0
  35. data/lib/skytab_sandbox_simulator/generators/entity_generator.rb +107 -0
  36. data/lib/skytab_sandbox_simulator/generators/order_generator.rb +390 -0
  37. data/lib/skytab_sandbox_simulator/models/api_request.rb +43 -0
  38. data/lib/skytab_sandbox_simulator/models/business_type.rb +25 -0
  39. data/lib/skytab_sandbox_simulator/models/category.rb +17 -0
  40. data/lib/skytab_sandbox_simulator/models/daily_summary.rb +67 -0
  41. data/lib/skytab_sandbox_simulator/models/item.rb +32 -0
  42. data/lib/skytab_sandbox_simulator/models/record.rb +14 -0
  43. data/lib/skytab_sandbox_simulator/models/simulated_order.rb +40 -0
  44. data/lib/skytab_sandbox_simulator/models/simulated_payment.rb +28 -0
  45. data/lib/skytab_sandbox_simulator/seeder.rb +167 -0
  46. data/lib/skytab_sandbox_simulator/services/base_service.rb +227 -0
  47. data/lib/skytab_sandbox_simulator/services/skytab/catalog_service.rb +130 -0
  48. data/lib/skytab_sandbox_simulator/services/skytab/location_service.rb +54 -0
  49. data/lib/skytab_sandbox_simulator/services/skytab/order_service.rb +139 -0
  50. data/lib/skytab_sandbox_simulator/services/skytab/payment_service.rb +94 -0
  51. data/lib/skytab_sandbox_simulator/services/skytab/service_manager.rb +62 -0
  52. data/lib/skytab_sandbox_simulator/version.rb +5 -0
  53. data/lib/skytab_sandbox_simulator.rb +45 -0
  54. metadata +305 -0
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SkytabSandboxSimulator
4
+ module Services
5
+ module Skytab
6
+ # Manages SkyTab tickets (orders/checks) via POS API.
7
+ # GET /pos/v2/{locationId}/tickets
8
+ class OrderService < BaseService
9
+ REVENUE_CLASSES = %w[DINE_IN TAKEOUT DELIVERY BAR CATERING].freeze
10
+
11
+ # Fetch all tickets for the current location
12
+ #
13
+ # @param limit [Integer] Maximum number of tickets to return
14
+ # @param status [String, nil] Filter by status (open, closed)
15
+ # @return [Array<Hash>] Array of ticket objects
16
+ def get_tickets(limit: 50, status: nil)
17
+ logger.info "Fetching tickets..."
18
+ params = { limit: limit }
19
+ params[:status] = status if status
20
+
21
+ response = request(:get, pos_endpoint("tickets"), params: params,
22
+ resource_type: "Ticket")
23
+ tickets = extract_elements(response)
24
+ logger.info "Found #{tickets.size} tickets"
25
+ tickets
26
+ end
27
+
28
+ # Get a single ticket by ID
29
+ #
30
+ # @param ticket_id [String] Ticket ID
31
+ # @return [Hash, nil] Ticket data
32
+ def get_ticket(ticket_id)
33
+ logger.info "Fetching ticket: #{ticket_id}"
34
+ request(:get, pos_endpoint("tickets/#{ticket_id}"),
35
+ resource_type: "Ticket", resource_id: ticket_id)
36
+ end
37
+
38
+ # Create a new ticket (check/order)
39
+ #
40
+ # @param pos_ref [String, nil] POS reference number
41
+ # @param employee_pos_ref [String, nil] Employee POS reference
42
+ # @param revenue_class [String] Revenue class (DINE_IN, TAKEOUT, etc.)
43
+ # @return [Hash, nil] Created ticket
44
+ def create_ticket(pos_ref: nil, employee_pos_ref: nil, revenue_class: "DINE_IN")
45
+ logger.info "Creating ticket..."
46
+
47
+ payload = {
48
+ "status" => "open",
49
+ "revenueClassPosRef" => revenue_class
50
+ }
51
+ payload["posRef"] = pos_ref if pos_ref
52
+ payload["employeePosRef"] = employee_pos_ref if employee_pos_ref
53
+
54
+ request(:post, pos_endpoint("tickets"), payload: payload,
55
+ resource_type: "Ticket")
56
+ end
57
+
58
+ # Add an item to a ticket
59
+ #
60
+ # @param ticket_id [String] Ticket ID
61
+ # @param pos_ref [String] Item POS reference
62
+ # @param name [String] Item name
63
+ # @param quantity [Integer] Quantity
64
+ # @param price [Integer] Unit price in cents
65
+ # @return [Hash, nil] Updated ticket
66
+ def add_item_to_ticket(ticket_id, pos_ref:, name:, quantity: 1, price:)
67
+ logger.debug "Adding item #{name} to ticket #{ticket_id}"
68
+
69
+ payload = {
70
+ "items" => [
71
+ {
72
+ "posRef" => pos_ref,
73
+ "name" => name,
74
+ "quantity" => quantity,
75
+ "price" => price,
76
+ "total" => price * quantity
77
+ }
78
+ ]
79
+ }
80
+
81
+ request(:put, pos_endpoint("tickets/#{ticket_id}/items"), payload: payload,
82
+ resource_type: "Ticket", resource_id: ticket_id)
83
+ end
84
+
85
+ # Close a ticket (mark as completed)
86
+ #
87
+ # @param ticket_id [String] Ticket ID
88
+ # @param subtotal [Integer] Subtotal in cents
89
+ # @param tax [Integer] Tax amount in cents
90
+ # @param total [Integer] Total in cents
91
+ # @param tip [Integer] Tip amount in cents
92
+ # @return [Hash, nil] Updated ticket
93
+ def close_ticket(ticket_id, subtotal:, tax:, total:, tip: 0)
94
+ logger.info "Closing ticket: #{ticket_id}"
95
+
96
+ payload = {
97
+ "status" => "closed",
98
+ "subtotal" => subtotal,
99
+ "tax" => tax,
100
+ "total" => total,
101
+ "tip" => tip,
102
+ "closedAt" => Time.now.utc.iso8601
103
+ }
104
+
105
+ request(:put, pos_endpoint("tickets/#{ticket_id}"), payload: payload,
106
+ resource_type: "Ticket", resource_id: ticket_id)
107
+ end
108
+
109
+ # Delete all tickets (use with caution)
110
+ #
111
+ # @return [Integer] Number of deleted tickets
112
+ def delete_all_tickets
113
+ tickets = get_tickets(limit: 100)
114
+ tickets.each do |ticket|
115
+ request(:delete, pos_endpoint("tickets/#{ticket['id']}"),
116
+ resource_type: "Ticket", resource_id: ticket["id"])
117
+ rescue StandardError => e
118
+ logger.warn "Failed to delete ticket #{ticket['id']}: #{e.message}"
119
+ end
120
+ tickets.size
121
+ end
122
+
123
+ private
124
+
125
+ def extract_elements(response)
126
+ return [] if response.nil?
127
+
128
+ if response.is_a?(Array)
129
+ response
130
+ elsif response.is_a?(Hash)
131
+ response["tickets"] || response["elements"] || []
132
+ else
133
+ []
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SkytabSandboxSimulator
4
+ module Services
5
+ module Skytab
6
+ # Manages SkyTab payments on tickets via POS API.
7
+ class PaymentService < BaseService
8
+ # Add a payment to a ticket
9
+ #
10
+ # @param ticket_id [String] Ticket ID
11
+ # @param tender_pos_ref [String] Tender POS reference (CASH, VISA, etc.)
12
+ # @param amount [Integer] Payment amount in cents
13
+ # @param tip [Integer] Tip amount in cents
14
+ # @return [Hash, nil] Payment result
15
+ def add_payment(ticket_id, tender_pos_ref:, amount:, tip: 0)
16
+ logger.info "Adding payment of $#{amount / 100.0} to ticket #{ticket_id}"
17
+
18
+ payload = {
19
+ "payments" => [
20
+ {
21
+ "tenderPosRef" => tender_pos_ref,
22
+ "amount" => amount,
23
+ "tip" => tip,
24
+ "status" => "completed"
25
+ }
26
+ ]
27
+ }
28
+
29
+ request(:put, pos_endpoint("tickets/#{ticket_id}/payments"), payload: payload,
30
+ resource_type: "Payment")
31
+ end
32
+
33
+ # Add a split payment to a ticket (multiple tenders)
34
+ #
35
+ # @param ticket_id [String] Ticket ID
36
+ # @param payments [Array<Hash>] Array of payment hashes with :tender_pos_ref, :amount, :tip
37
+ # @return [Hash, nil] Payment result
38
+ def add_split_payment(ticket_id, payments:)
39
+ logger.info "Adding #{payments.size} split payments to ticket #{ticket_id}"
40
+
41
+ payment_data = payments.map do |p|
42
+ {
43
+ "tenderPosRef" => p[:tender_pos_ref],
44
+ "amount" => p[:amount],
45
+ "tip" => p[:tip] || 0,
46
+ "status" => "completed"
47
+ }
48
+ end
49
+
50
+ payload = { "payments" => payment_data }
51
+
52
+ request(:put, pos_endpoint("tickets/#{ticket_id}/payments"), payload: payload,
53
+ resource_type: "Payment")
54
+ end
55
+
56
+ # Fetch payments for a ticket
57
+ #
58
+ # @param ticket_id [String] Ticket ID
59
+ # @return [Array<Hash>] Array of payment objects
60
+ def get_payments(ticket_id)
61
+ logger.info "Fetching payments for ticket: #{ticket_id}"
62
+ response = request(:get, pos_endpoint("tickets/#{ticket_id}/payments"),
63
+ resource_type: "Payment")
64
+
65
+ return [] if response.nil?
66
+
67
+ if response.is_a?(Array)
68
+ response
69
+ elsif response.is_a?(Hash)
70
+ response["payments"] || response["elements"] || []
71
+ else
72
+ []
73
+ end
74
+ end
75
+
76
+ # Refund a payment
77
+ #
78
+ # @param ticket_id [String] Ticket ID
79
+ # @param payment_id [String] Payment ID to refund
80
+ # @param amount [Integer, nil] Refund amount in cents (nil for full refund)
81
+ # @return [Hash, nil] Refund result
82
+ def refund_payment(ticket_id, payment_id:, amount: nil)
83
+ logger.info "Refunding payment #{payment_id} on ticket #{ticket_id}"
84
+
85
+ payload = { "paymentId" => payment_id }
86
+ payload["amount"] = amount if amount
87
+
88
+ request(:post, pos_endpoint("tickets/#{ticket_id}/refunds"), payload: payload,
89
+ resource_type: "Refund")
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SkytabSandboxSimulator
4
+ module Services
5
+ module Skytab
6
+ # Central manager for all SkyTab services.
7
+ # Provides thread-safe, lazy-loaded access to all service classes.
8
+ class ServiceManager
9
+ attr_reader :config
10
+
11
+ def initialize(config: nil)
12
+ @config = config || SkytabSandboxSimulator.configuration
13
+ @mutex = Mutex.new
14
+ end
15
+
16
+ def location
17
+ thread_safe_memoize(:@location) { LocationService.new(config: config) }
18
+ end
19
+
20
+ def catalog
21
+ thread_safe_memoize(:@catalog) { CatalogService.new(config: config) }
22
+ end
23
+
24
+ def order
25
+ thread_safe_memoize(:@order) { OrderService.new(config: config) }
26
+ end
27
+
28
+ def payment
29
+ thread_safe_memoize(:@payment) { PaymentService.new(config: config) }
30
+ end
31
+
32
+ # Clear all cached service instances
33
+ def clear_services
34
+ @mutex.synchronize do
35
+ instance_variables.each do |var|
36
+ next if var == :@config || var == :@mutex
37
+
38
+ instance_variable_set(var, nil)
39
+ end
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ # Thread-safe memoization pattern
46
+ def thread_safe_memoize(ivar_name)
47
+ value = instance_variable_get(ivar_name)
48
+ return value if value
49
+
50
+ @mutex.synchronize do
51
+ value = instance_variable_get(ivar_name)
52
+ return value if value
53
+
54
+ value = yield
55
+ instance_variable_set(ivar_name, value)
56
+ value
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SkytabSandboxSimulator
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zeitwerk"
4
+ require "logger"
5
+ require "json"
6
+ require "rest-client"
7
+ require "dotenv"
8
+
9
+ # Load environment variables
10
+ Dotenv.load
11
+
12
+ module SkytabSandboxSimulator
13
+ class Error < StandardError; end
14
+ class ConfigurationError < Error; end
15
+ class ApiError < Error; end
16
+
17
+ class << self
18
+ attr_writer :configuration
19
+
20
+ def configuration
21
+ @configuration ||= Configuration.new
22
+ end
23
+
24
+ def configure
25
+ yield(configuration)
26
+ end
27
+
28
+ def logger
29
+ configuration.logger
30
+ end
31
+
32
+ def root
33
+ File.expand_path("..", __dir__)
34
+ end
35
+ end
36
+ end
37
+
38
+ # Set up Zeitwerk autoloader
39
+ loader = Zeitwerk::Loader.for_gem
40
+ # Migrations and factories follow ActiveRecord conventions, not Zeitwerk naming
41
+ loader.ignore(File.expand_path("skytab_sandbox_simulator/db", __dir__))
42
+ loader.setup
43
+
44
+ # Eager load in production
45
+ loader.eager_load if ENV["RACK_ENV"] == "production"
metadata ADDED
@@ -0,0 +1,305 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: skytab_sandbox_simulator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - TheOwnerStack
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activerecord
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '8.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '8.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: concurrent-ruby
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.2'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.2'
40
+ - !ruby/object:Gem::Dependency
41
+ name: dotenv
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: factory_bot
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '6.4'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '6.4'
68
+ - !ruby/object:Gem::Dependency
69
+ name: faker
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.2'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.2'
82
+ - !ruby/object:Gem::Dependency
83
+ name: pg
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.5'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '1.5'
96
+ - !ruby/object:Gem::Dependency
97
+ name: rest-client
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '2.1'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '2.1'
110
+ - !ruby/object:Gem::Dependency
111
+ name: thor
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '1.3'
117
+ type: :runtime
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '1.3'
124
+ - !ruby/object:Gem::Dependency
125
+ name: tzinfo
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '2.0'
131
+ type: :runtime
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '2.0'
138
+ - !ruby/object:Gem::Dependency
139
+ name: zeitwerk
140
+ requirement: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '2.6'
145
+ type: :runtime
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '2.6'
152
+ - !ruby/object:Gem::Dependency
153
+ name: database_cleaner-active_record
154
+ requirement: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: '2.1'
159
+ type: :development
160
+ prerelease: false
161
+ version_requirements: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - "~>"
164
+ - !ruby/object:Gem::Version
165
+ version: '2.1'
166
+ - !ruby/object:Gem::Dependency
167
+ name: rspec
168
+ requirement: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "~>"
171
+ - !ruby/object:Gem::Version
172
+ version: '3.12'
173
+ type: :development
174
+ prerelease: false
175
+ version_requirements: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '3.12'
180
+ - !ruby/object:Gem::Dependency
181
+ name: rubocop
182
+ requirement: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - "~>"
185
+ - !ruby/object:Gem::Version
186
+ version: '1.50'
187
+ type: :development
188
+ prerelease: false
189
+ version_requirements: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - "~>"
192
+ - !ruby/object:Gem::Version
193
+ version: '1.50'
194
+ - !ruby/object:Gem::Dependency
195
+ name: vcr
196
+ requirement: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - "~>"
199
+ - !ruby/object:Gem::Version
200
+ version: '6.1'
201
+ type: :development
202
+ prerelease: false
203
+ version_requirements: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - "~>"
206
+ - !ruby/object:Gem::Version
207
+ version: '6.1'
208
+ - !ruby/object:Gem::Dependency
209
+ name: webmock
210
+ requirement: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - "~>"
213
+ - !ruby/object:Gem::Version
214
+ version: '3.18'
215
+ type: :development
216
+ prerelease: false
217
+ version_requirements: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - "~>"
220
+ - !ruby/object:Gem::Version
221
+ version: '3.18'
222
+ description: A Ruby gem for simulating Point of Sale operations in SkyTab (Shift4)
223
+ sandbox environments. Generates realistic restaurant orders, payments, and transaction
224
+ data for testing integrations with the Shift4 Marketplace API.
225
+ email:
226
+ - support@salestobooks.com
227
+ executables:
228
+ - simulate
229
+ extensions: []
230
+ extra_rdoc_files: []
231
+ files:
232
+ - Gemfile
233
+ - bin/simulate
234
+ - lib/skytab_sandbox_simulator.rb
235
+ - lib/skytab_sandbox_simulator/configuration.rb
236
+ - lib/skytab_sandbox_simulator/data/bar_nightclub/categories.json
237
+ - lib/skytab_sandbox_simulator/data/bar_nightclub/items.json
238
+ - lib/skytab_sandbox_simulator/data/bar_nightclub/tenders.json
239
+ - lib/skytab_sandbox_simulator/data/cafe_bakery/categories.json
240
+ - lib/skytab_sandbox_simulator/data/cafe_bakery/items.json
241
+ - lib/skytab_sandbox_simulator/data/cafe_bakery/tenders.json
242
+ - lib/skytab_sandbox_simulator/data/fine_dining/categories.json
243
+ - lib/skytab_sandbox_simulator/data/fine_dining/items.json
244
+ - lib/skytab_sandbox_simulator/data/fine_dining/tenders.json
245
+ - lib/skytab_sandbox_simulator/data/pizzeria/categories.json
246
+ - lib/skytab_sandbox_simulator/data/pizzeria/items.json
247
+ - lib/skytab_sandbox_simulator/data/pizzeria/tenders.json
248
+ - lib/skytab_sandbox_simulator/data/restaurant/categories.json
249
+ - lib/skytab_sandbox_simulator/data/restaurant/items.json
250
+ - lib/skytab_sandbox_simulator/data/restaurant/tenders.json
251
+ - lib/skytab_sandbox_simulator/database.rb
252
+ - lib/skytab_sandbox_simulator/db/factories/business_types.rb
253
+ - lib/skytab_sandbox_simulator/db/factories/categories.rb
254
+ - lib/skytab_sandbox_simulator/db/factories/items.rb
255
+ - lib/skytab_sandbox_simulator/db/factories/simulated_orders.rb
256
+ - lib/skytab_sandbox_simulator/db/factories/simulated_payments.rb
257
+ - lib/skytab_sandbox_simulator/db/migrate/20260316000000_enable_pgcrypto.rb
258
+ - lib/skytab_sandbox_simulator/db/migrate/20260316000001_create_business_types.rb
259
+ - lib/skytab_sandbox_simulator/db/migrate/20260316000002_create_categories.rb
260
+ - lib/skytab_sandbox_simulator/db/migrate/20260316000003_create_items.rb
261
+ - lib/skytab_sandbox_simulator/db/migrate/20260316000004_create_simulated_orders.rb
262
+ - lib/skytab_sandbox_simulator/db/migrate/20260316000005_create_simulated_payments.rb
263
+ - lib/skytab_sandbox_simulator/db/migrate/20260316000006_create_api_requests.rb
264
+ - lib/skytab_sandbox_simulator/db/migrate/20260316000007_create_daily_summaries.rb
265
+ - lib/skytab_sandbox_simulator/generators/data_loader.rb
266
+ - lib/skytab_sandbox_simulator/generators/entity_generator.rb
267
+ - lib/skytab_sandbox_simulator/generators/order_generator.rb
268
+ - lib/skytab_sandbox_simulator/models/api_request.rb
269
+ - lib/skytab_sandbox_simulator/models/business_type.rb
270
+ - lib/skytab_sandbox_simulator/models/category.rb
271
+ - lib/skytab_sandbox_simulator/models/daily_summary.rb
272
+ - lib/skytab_sandbox_simulator/models/item.rb
273
+ - lib/skytab_sandbox_simulator/models/record.rb
274
+ - lib/skytab_sandbox_simulator/models/simulated_order.rb
275
+ - lib/skytab_sandbox_simulator/models/simulated_payment.rb
276
+ - lib/skytab_sandbox_simulator/seeder.rb
277
+ - lib/skytab_sandbox_simulator/services/base_service.rb
278
+ - lib/skytab_sandbox_simulator/services/skytab/catalog_service.rb
279
+ - lib/skytab_sandbox_simulator/services/skytab/location_service.rb
280
+ - lib/skytab_sandbox_simulator/services/skytab/order_service.rb
281
+ - lib/skytab_sandbox_simulator/services/skytab/payment_service.rb
282
+ - lib/skytab_sandbox_simulator/services/skytab/service_manager.rb
283
+ - lib/skytab_sandbox_simulator/version.rb
284
+ homepage: https://github.com/dan1d/skytab_sandbox_simulator
285
+ licenses:
286
+ - MIT
287
+ metadata: {}
288
+ rdoc_options: []
289
+ require_paths:
290
+ - lib
291
+ required_ruby_version: !ruby/object:Gem::Requirement
292
+ requirements:
293
+ - - ">="
294
+ - !ruby/object:Gem::Version
295
+ version: 3.0.0
296
+ required_rubygems_version: !ruby/object:Gem::Requirement
297
+ requirements:
298
+ - - ">="
299
+ - !ruby/object:Gem::Version
300
+ version: '0'
301
+ requirements: []
302
+ rubygems_version: 3.6.9
303
+ specification_version: 4
304
+ summary: SkyTab (Shift4) POS sandbox simulator for SalesToBooks integration testing
305
+ test_files: []