clover_sandbox_simulator 1.5.0 → 1.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 71bf747b5954c1ed19674690e6bd87b50565e6134d271578d0ca555107c5768b
4
- data.tar.gz: a6e887ab824caa87d013d98fefc58040d0668849b05f60694375d14202792ad5
3
+ metadata.gz: 9f684b2338da3333984bdf63a1abb0ff18112be9cd5e210e4f2dc3ded17b554f
4
+ data.tar.gz: 193f13605291b79ead034124638c03fc863089e364f73bb1cb4f829281ce00ae
5
5
  SHA512:
6
- metadata.gz: 01fbdfe1c3deb2506c2c49b8f800e4636b9c34150047276f034b85a4f51a60681feb0d6374abe2682481de2d44410e337a44b4f5b9a84ef93ebc0003e396d801
7
- data.tar.gz: 845682838c47593dbfff5face1418d6a1359224bfbd1c167c314527d7ca7a1c4a3a9c39a6ac2d10a8b81bcb3a9180a17014f4881c2be139b55ba3947b22e31ef
6
+ metadata.gz: dadd0674dd7b51f92e3df36ad084282fb068831149208fa37cb2238b904a3a2bbb4336433ad88efae1bd0fea9bd2703c0925f5972711decc0aa415798c27f816
7
+ data.tar.gz: 388a79a26a9425fce232d21e08de3b9b9f1dcf86bea42175e27e605fd2c48215dfb78b274ebd28ec40195a1ac8584259766f7801889866f9f1898d6540cd0902
data/README.md CHANGED
@@ -1,12 +1,13 @@
1
1
  # Clover Sandbox Simulator
2
2
 
3
- A Ruby gem for simulating Point of Sale operations in Clover sandbox environments. Generates realistic restaurant orders, payments, and transaction data for testing integrations with Clover's API.
3
+ A Ruby gem for simulating Point of Sale operations in Clover sandbox environments. Generates realistic orders, payments, and transaction data across **9 business types** for testing integrations with Clover's API.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Realistic Restaurant Data**: Complete menu with 39 items across 7 categories (appetizers, entrees, sides, desserts, drinks, alcoholic beverages, specials)
7
+ - **9 Business Types**: Restaurant, Cafe/Bakery, Bar/Nightclub, Food Truck, Fine Dining, Pizzeria, Retail Clothing, Retail General, Salon/Spa each with tailored categories and items
8
+ - **168 Menu/Product Items**: Spread across 38 categories with realistic pricing
8
9
  - **Modifier Groups**: Temperature, add-ons, sides, dressings, drink sizes applied to menu items
9
- - **Multiple Payment Methods**: Supports Credit/Debit cards via Ecommerce API, plus Cash, Check, Gift Card, and other tenders
10
+ - **Multiple Payment Methods**: Credit/Debit cards via Ecommerce API, plus Cash, Check, Gift Card, and other tenders
10
11
  - **Split Payments**: Supports 1-4 tender splits per order, more common for larger parties
11
12
  - **Meal Period Simulation**: Orders distributed across breakfast, lunch, happy hour, dinner, and late night with realistic weights
12
13
  - **Order Types**: Dine-in, Takeout, and Delivery with configurable settings
@@ -14,12 +15,15 @@ A Ruby gem for simulating Point of Sale operations in Clover sandbox environment
14
15
  - **Dynamic Order Volume**: Different order counts for weekdays, Friday, Saturday, Sunday (40-120 orders/day)
15
16
  - **Tips & Taxes**: Variable tip rates by dining option (15-25% dine-in, 0-15% takeout, 10-20% delivery)
16
17
  - **Per-Item Tax Rates**: Different tax rates for food vs alcohol items
17
- - **Discounts**: 7 discount types including Happy Hour, Senior, Military, Employee, Birthday, and fixed amounts
18
+ - **Discounts**: 7 discount types including Happy Hour, promo codes, loyalty, combo, line-item, threshold, and legacy
18
19
  - **Employees & Customers**: Auto-generated with realistic names and contact info
19
20
  - **Shift Tracking**: Clock in/out for employees with duration tracking
20
21
  - **Cash Drawer Management**: Open/close drawer events with cash tracking
21
22
  - **Party Size Variation**: 1-6 guests affecting item counts and split payment probability
22
23
  - **Order Notes**: Random special instructions (allergies, modifications, VIP customers)
24
+ - **PostgreSQL Audit Trail**: Track all simulated orders, payments, and API requests in a local database
25
+ - **Daily Summaries**: Automated aggregation of revenue, tax, tips, and discounts by meal period and dining option
26
+ - **Database Seeding**: Idempotent FactoryBot-based seeder for all 9 business types
23
27
 
24
28
  ## Installation
25
29
 
@@ -45,18 +49,32 @@ gem install clover_sandbox_simulator
45
49
 
46
50
  ### Multi-Merchant Setup (Recommended)
47
51
 
48
- Create a `.env.json` file with multiple merchant configurations:
52
+ Create a `.env.json` file with the object format:
53
+
54
+ ```json
55
+ {
56
+ "DATABASE_URL": "postgres://localhost:5432/clover_simulator_development",
57
+ "merchants": [
58
+ {
59
+ "CLOVER_MERCHANT_ID": "YOUR_MERCHANT_ID",
60
+ "CLOVER_MERCHANT_NAME": "My Test Merchant",
61
+ "CLOVER_API_TOKEN": "static-api-token",
62
+ "CLOVER_ACCESS_TOKEN": "oauth-jwt-token",
63
+ "CLOVER_REFRESH_TOKEN": "clvroar-refresh-token",
64
+ "PUBLIC_TOKEN": "ecommerce-public-token",
65
+ "PRIVATE_TOKEN": "ecommerce-private-token"
66
+ }
67
+ ]
68
+ }
69
+ ```
70
+
71
+ The legacy array format is also supported for backwards compatibility:
49
72
 
50
73
  ```json
51
74
  [
52
75
  {
53
76
  "CLOVER_MERCHANT_ID": "YOUR_MERCHANT_ID",
54
- "CLOVER_MERCHANT_NAME": "My Test Merchant",
55
- "CLOVER_API_TOKEN": "static-api-token",
56
- "CLOVER_ACCESS_TOKEN": "oauth-jwt-token",
57
- "CLOVER_REFRESH_TOKEN": "clvroar-refresh-token",
58
- "PUBLIC_TOKEN": "ecommerce-public-token",
59
- "PRIVATE_TOKEN": "ecommerce-private-token"
77
+ "CLOVER_API_TOKEN": "your-token"
60
78
  }
61
79
  ]
62
80
  ```
@@ -65,6 +83,7 @@ Create a `.env.json` file with multiple merchant configurations:
65
83
  - `CLOVER_API_TOKEN` - Static API token (never expires, preferred)
66
84
  - `CLOVER_ACCESS_TOKEN` - OAuth JWT token (expires, can be refreshed)
67
85
  - `PUBLIC_TOKEN` / `PRIVATE_TOKEN` - Required for credit card payments via Ecommerce API
86
+ - `DATABASE_URL` - PostgreSQL connection string for audit trail persistence
68
87
 
69
88
  ### Single Merchant Setup
70
89
 
@@ -80,6 +99,20 @@ LOG_LEVEL=INFO
80
99
  TAX_RATE=8.25
81
100
  ```
82
101
 
102
+ ### Database Setup
103
+
104
+ The simulator uses PostgreSQL to persist audit data (simulated orders, payments, API requests, daily summaries). Set up the database with:
105
+
106
+ ```bash
107
+ # Create, migrate, and seed the database
108
+ ./bin/simulate db reset
109
+
110
+ # Or step by step:
111
+ ./bin/simulate db create
112
+ ./bin/simulate db migrate
113
+ ./bin/simulate db seed
114
+ ```
115
+
83
116
  ## Usage
84
117
 
85
118
  ### Quick Start
@@ -93,6 +126,9 @@ Run a full simulation (setup + generate orders):
93
126
  ### Commands
94
127
 
95
128
  ```bash
129
+ # Show version
130
+ ./bin/simulate version
131
+
96
132
  # List available merchants from .env.json
97
133
  ./bin/simulate merchants
98
134
 
@@ -175,9 +211,42 @@ Run a full simulation (setup + generate orders):
175
211
  ./bin/simulate generate -v
176
212
  ```
177
213
 
214
+ ### Database Management
215
+
216
+ ```bash
217
+ # Database subcommands
218
+ ./bin/simulate db create # Create PostgreSQL database
219
+ ./bin/simulate db migrate # Run pending migrations
220
+ ./bin/simulate db seed # Seed with 9 business types, 38 categories, 168 items
221
+ ./bin/simulate db reset # Drop, create, migrate, and seed
222
+
223
+ # Reporting
224
+ ./bin/simulate summary # Show daily summary (revenue, orders, tips, tax)
225
+ ./bin/simulate audit # Show recent API requests
226
+ ./bin/simulate business_types # List business types with category/item counts
227
+ ```
228
+
229
+ ## Business Types
230
+
231
+ The simulator supports 9 business types across 3 industries:
232
+
233
+ | Business Type | Industry | Categories | Items | Description |
234
+ |---------------|----------|------------|-------|-------------|
235
+ | Restaurant | Food | 5 | 25 | Full-service casual dining |
236
+ | Cafe/Bakery | Food | 5 | 25 | Coffee shop with pastries and light fare |
237
+ | Bar/Nightclub | Food | 5 | 25 | Craft cocktails, draft beer, late-night bites |
238
+ | Food Truck | Food | 3 | 15 | Mobile street food — tacos and Mexican fare |
239
+ | Fine Dining | Food | 3 | 15 | Upscale prix-fixe and a la carte dining |
240
+ | Pizzeria | Food | 3 | 15 | Classic and specialty pies, calzones, sides |
241
+ | Retail Clothing | Retail | 5 | 25 | Casual wear with size/color variants |
242
+ | Retail General | Retail | 5 | 13 | Electronics, home goods, personal care |
243
+ | Salon/Spa | Service | 4 | 10 | Hair salon, spa treatments, nail services |
244
+
245
+ All business types have tailored order profiles, category structures, and item pricing.
246
+
178
247
  ## Menu Structure
179
248
 
180
- ### Categories
249
+ ### Categories (Restaurant Example)
181
250
  - Appetizers
182
251
  - Entrees
183
252
  - Sides
@@ -216,6 +285,8 @@ Run a full simulation (setup + generate orders):
216
285
 
217
286
  Credit and debit card payments are fully supported via the **Clover Ecommerce API**. This requires configuring `PUBLIC_TOKEN` and `PRIVATE_TOKEN` in your `.env.json`.
218
287
 
288
+ ~55% of orders use card payments when the Ecommerce API is configured. The simulator tokenizes test cards and creates charges linked to orders. If a charge fails, payment gracefully falls back to cash.
289
+
219
290
  **Test Card Numbers:**
220
291
 
221
292
  | Card Type | Number |
@@ -240,10 +311,41 @@ For non-card payments, the simulator uses Platform API tenders:
240
311
  - Check
241
312
  - Gift Card
242
313
  - External Payment
243
- - Mobile Payment
244
- - Store Credit
245
314
 
246
- The simulator uses whatever tenders are available in the Clover merchant account.
315
+ The simulator uses whatever tenders are available in the Clover merchant account. Card tenders are automatically excluded from split payments (which use the Platform API).
316
+
317
+ ## Audit Trail & Persistence
318
+
319
+ The simulator persists all activity to a PostgreSQL database for analysis and debugging:
320
+
321
+ ### Models
322
+
323
+ | Model | Purpose |
324
+ |-------|---------|
325
+ | `BusinessType` | 9 business types with industry classification and order profiles |
326
+ | `Category` | 38 categories linked to business types with tax groups |
327
+ | `Item` | 168 items with SKUs, pricing, and optional size/color variants |
328
+ | `SimulatedOrder` | Every generated order with merchant ID, period, dining option, amounts |
329
+ | `SimulatedPayment` | Payment records with tender type classification (credit_card, debit_card, cash, check, gift_card) |
330
+ | `ApiRequest` | Full audit log of every HTTP call to Clover (method, URL, status, duration, payloads) |
331
+ | `DailySummary` | Automated daily aggregation of revenue, tax, tips, and discounts |
332
+
333
+ ### Daily Summary
334
+
335
+ The `DailySummary` model automatically aggregates:
336
+ - Order count, revenue, tax, tips, discounts
337
+ - Breakdown by meal period and dining option
338
+ - Revenue by meal period and dining option
339
+ - Payment breakdown by tender type
340
+
341
+ ```ruby
342
+ # Generate a summary for today
343
+ DailySummary.generate_for!("MERCHANT_ID", Date.today)
344
+
345
+ # Query summaries
346
+ DailySummary.for_merchant("M1").recent(7)
347
+ DailySummary.between_dates(1.week.ago, Date.today)
348
+ ```
247
349
 
248
350
  ## Tax Rates
249
351
 
@@ -281,47 +383,6 @@ The simulator supports multiple order types that affect order flow and reporting
281
383
 
282
384
  Order types are automatically created during setup if they don't exist.
283
385
 
284
- ## Shift Management
285
-
286
- The simulator tracks employee shifts for realistic operations:
287
-
288
- ```ruby
289
- # Clock in an employee
290
- services.shift.clock_in(employee_id: "EMP_123")
291
-
292
- # Clock out an employee
293
- services.shift.clock_out(employee_id: "EMP_123")
294
-
295
- # Get active shifts
296
- services.shift.get_active_shifts
297
-
298
- # Calculate shift duration
299
- services.shift.calculate_shift_duration(shift_id: "SHIFT_123")
300
- ```
301
-
302
- ## Cash Drawer Operations
303
-
304
- Track cash drawer operations for end-of-day reconciliation:
305
-
306
- ```ruby
307
- # Open cash drawer
308
- services.cash_event.open_drawer(employee_id: "EMP_123", amount: 10000)
309
-
310
- # Close cash drawer
311
- services.cash_event.close_drawer(employee_id: "EMP_123", amount: 15000)
312
-
313
- # Add cash (e.g., from cash payment)
314
- services.cash_event.add_cash(employee_id: "EMP_123", amount: 2500, note: "Cash sale")
315
-
316
- # Remove cash (e.g., cash out)
317
- services.cash_event.remove_cash(employee_id: "EMP_123", amount: 5000, note: "Bank deposit")
318
-
319
- # Get drawer total
320
- services.cash_event.calculate_drawer_total
321
- ```
322
-
323
- **Note:** Cash event creation may not be fully supported in the Clover sandbox. The simulator handles this gracefully with simulated responses.
324
-
325
386
  ## Tips
326
387
 
327
388
  Tips vary by dining option to simulate realistic customer behavior:
@@ -374,24 +435,38 @@ Each meal period has different dining option distributions:
374
435
 
375
436
  ```
376
437
  clover_sandbox_simulator/
377
- ├── bin/simulate # CLI entry point
438
+ ├── bin/simulate # CLI entry point (Thor)
378
439
  ├── lib/
379
- │ ├── clover_sandbox_simulator.rb # Gem entry point
440
+ │ ├── clover_sandbox_simulator.rb # Gem entry point, VERSION constant
380
441
  │ └── clover_sandbox_simulator/
381
442
  │ ├── configuration.rb # Multi-merchant config from .env.json
443
+ │ ├── database.rb # PostgreSQL connection management
444
+ │ ├── seeder.rb # Idempotent FactoryBot seeder
382
445
  │ ├── parallel_executor.rb # Concurrent execution support
446
+ │ ├── models/ # ActiveRecord models (standalone, no Rails)
447
+ │ │ ├── record.rb # Base class for all models
448
+ │ │ ├── business_type.rb # 9 business types with industries
449
+ │ │ ├── category.rb # 38 categories per business type
450
+ │ │ ├── item.rb # 168 items with pricing & variants
451
+ │ │ ├── simulated_order.rb # Generated order audit records
452
+ │ │ ├── simulated_payment.rb # Payment audit records by tender type
453
+ │ │ ├── api_request.rb # Full HTTP request/response audit log
454
+ │ │ └── daily_summary.rb # Automated daily aggregation
455
+ │ ├── db/
456
+ │ │ ├── migrate/ # 8 PostgreSQL migrations (UUID PKs)
457
+ │ │ └── factories/ # FactoryBot factories (shared with seeder)
383
458
  │ ├── services/
384
- │ │ ├── base_service.rb # HTTP client, error handling helpers
385
- │ │ └── clover/ # Clover API services
459
+ │ │ ├── base_service.rb # HTTP client, error handling, audit logging
460
+ │ │ └── clover/ # Clover API services
386
461
  │ │ ├── inventory_service.rb # Categories, items, modifier groups
387
462
  │ │ ├── order_service.rb # Orders, line items, modifiers
388
- │ │ ├── payment_service.rb # Payments, splits
389
- │ │ ├── tender_service.rb # Payment tenders
463
+ │ │ ├── payment_service.rb # Payments, splits, card payments
464
+ │ │ ├── tender_service.rb # Payment tenders, card detection
465
+ │ │ ├── ecommerce_service.rb # Card tokenization & charges
390
466
  │ │ ├── tax_service.rb # Tax rates, per-item taxes
391
- │ │ ├── discount_service.rb # Discounts, promos, combos
467
+ │ │ ├── discount_service.rb # Discounts, promos, combos, loyalty
392
468
  │ │ ├── employee_service.rb # Employee management
393
469
  │ │ ├── customer_service.rb # Customer management
394
- │ │ ├── ecommerce_service.rb # Card payments via Ecommerce API
395
470
  │ │ ├── refund_service.rb # Full/partial refunds
396
471
  │ │ ├── gift_card_service.rb # Gift card management
397
472
  │ │ ├── service_charge_service.rb # Service charges, auto-gratuity
@@ -401,18 +476,18 @@ clover_sandbox_simulator/
401
476
  │ │ ├── oauth_service.rb # Token refresh
402
477
  │ │ └── services_manager.rb # Thread-safe service access
403
478
  │ ├── generators/
404
- │ │ ├── data_loader.rb # Load JSON data files
479
+ │ │ ├── data_loader.rb # DB-first data loading with JSON fallback
405
480
  │ │ ├── entity_generator.rb # Setup entities (idempotent)
406
- │ │ └── order_generator.rb # Generate realistic orders
481
+ │ │ └── order_generator.rb # Generate realistic orders & payments
407
482
  │ └── data/
408
- │ └── restaurant/ # JSON data files
483
+ │ └── restaurant/ # JSON data files (fallback for DB)
409
484
  │ ├── categories.json
410
485
  │ ├── items.json
411
486
  │ ├── discounts.json
412
487
  │ ├── tenders.json
413
488
  │ ├── modifiers.json
414
489
  │ └── tax_rates.json
415
- └── spec/ # RSpec tests with VCR integration
490
+ └── spec/ # 1124 examples, 0 failures
416
491
  ```
417
492
 
418
493
  ## Development
@@ -427,6 +502,9 @@ bundle exec rspec --format documentation
427
502
  # Run specific test file
428
503
  bundle exec rspec spec/services/clover/tender_service_spec.rb
429
504
 
505
+ # Run model specs
506
+ bundle exec rspec spec/models/
507
+
430
508
  # Run integration tests (requires .env.json with valid credentials)
431
509
  bundle exec rspec spec/integration/
432
510
 
@@ -435,24 +513,30 @@ bundle exec rubocop
435
513
 
436
514
  # Open console
437
515
  bundle exec irb -r ./lib/clover_sandbox_simulator
516
+
517
+ # Build the gem
518
+ gem build clover_sandbox_simulator.gemspec
438
519
  ```
439
520
 
440
521
  ## Testing
441
522
 
442
- The gem includes comprehensive RSpec tests with WebMock for HTTP stubbing and VCR for integration tests.
523
+ The gem includes comprehensive RSpec tests with WebMock for HTTP stubbing, VCR for integration tests, and DatabaseCleaner for test isolation.
443
524
 
444
525
  ### Test Coverage
445
526
 
446
- - **475 examples, 0 failures, 3 pending**
447
- - Configuration validation
448
- - Data loading from JSON files
527
+ - **1124 examples, 0 failures, 3 pending**
528
+ - Database connection management and migration
529
+ - Seeder idempotency (9 business types, 38 categories, 168 items)
530
+ - FactoryBot factory validation (219 factories/traits)
531
+ - All ActiveRecord models (validations, scopes, associations)
449
532
  - All Clover API services:
450
533
  - InventoryService (categories, items, modifier groups)
451
534
  - OrderService (create, line items, dining options, modifiers)
452
535
  - PaymentService (single, split, and card payments)
453
- - TenderService (tender selection)
536
+ - TenderService (tender selection, card detection, ecommerce filtering)
537
+ - EcommerceService (tokenization, charges, refunds)
454
538
  - TaxService (rates, per-item calculation, item associations)
455
- - DiscountService (percentage, fixed, time-based, loyalty)
539
+ - DiscountService (percentage, fixed, time-based, loyalty, combo, promo codes)
456
540
  - EmployeeService (CRUD, deterministic setup)
457
541
  - CustomerService (CRUD, anonymous orders)
458
542
  - RefundService (full/partial refunds, multiple strategies)
@@ -462,42 +546,64 @@ The gem includes comprehensive RSpec tests with WebMock for HTTP stubbing and VC
462
546
  - OrderTypeService (CRUD, default setup)
463
547
  - CashEventService (drawer operations, simulated responses)
464
548
  - ServicesManager (thread-safe memoization, lazy loading)
465
- - Entity generator idempotency
466
- - Order generator (meal periods, dining options, tips, refunds, modifiers, service charges)
467
- - Edge cases (nil handling, empty arrays, API errors)
549
+ - Audit trail (API request logging, order/payment tracking, daily summaries)
550
+ - Order generator (meal periods, dining options, tips, card payments, fallbacks, refunds, modifiers, service charges)
551
+ - Data loader (DB-first with JSON fallback, format parity)
552
+ - Multi-business type integration (industry classification, order profiles)
553
+ - Financial data quality validation
554
+ - Edge cases (nil handling, empty arrays, API errors, network failures)
468
555
  - VCR integration tests for real API validation
469
556
 
470
557
  ### Test Files
471
558
 
472
559
  ```
473
560
  spec/
474
- ├── configuration_spec.rb
561
+ ├── audit_logging_spec.rb # BaseService audit + OrderGenerator tracking
562
+ ├── configuration_spec.rb # Multi-merchant config validation
563
+ ├── configuration_database_url_spec.rb # DATABASE_URL parsing
564
+ ├── database_spec.rb # Connection management, migrations
565
+ ├── seeder_spec.rb # Idempotent seeding, business types
566
+ ├── factories/
567
+ │ └── factories_spec.rb # 219 factory/trait validation
475
568
  ├── generators/
476
- │ ├── data_loader_spec.rb
477
- │ ├── entity_generator_spec.rb
478
- │ └── order_generator_spec.rb
479
- ├── services/clover/
480
- │ ├── customer_service_spec.rb
481
- │ ├── discount_service_spec.rb
482
- │ ├── employee_service_spec.rb
483
- │ ├── gift_card_service_spec.rb
484
- │ ├── inventory_service_spec.rb
485
- │ ├── order_service_spec.rb
486
- │ ├── payment_service_spec.rb
487
- ├── refund_service_spec.rb
488
- ├── service_charge_service_spec.rb
489
- │ ├── shift_service_spec.rb
490
- │ ├── order_type_service_spec.rb
491
- │ ├── cash_event_service_spec.rb
492
- │ ├── tax_service_spec.rb
493
- │ ├── services_manager_spec.rb
494
- └── tender_service_spec.rb
495
- └── integration/
496
- ├── modifier_groups_spec.rb
497
- ├── service_charges_spec.rb
498
- ├── order_types_spec.rb
499
- ├── cash_events_spec.rb
500
- └── tax_rates_spec.rb
569
+ │ ├── data_loader_spec.rb # DB/JSON loading, format parity
570
+ │ ├── entity_generator_spec.rb # Idempotent setup
571
+ │ └── order_generator_spec.rb # Payments, tips, dining, card flow
572
+ ├── integration/
573
+ │ ├── audit_trail_spec.rb # End-to-end order/payment/summary
574
+ │ ├── data_loader_compat_spec.rb # DB vs JSON compatibility
575
+ │ ├── multi_business_spec.rb # 9 business types, industries
576
+ │ ├── modifier_groups_spec.rb # VCR: real API
577
+ │ ├── service_charges_spec.rb # VCR: real API
578
+ │ ├── order_types_spec.rb # VCR: real API
579
+ │ ├── cash_events_spec.rb # VCR: real API
580
+ └── tax_rates_spec.rb # VCR: real API
581
+ ├── models/
582
+ │ ├── api_request_spec.rb # Scopes, validations
583
+ │ ├── business_type_spec.rb # Industries, associations
584
+ │ ├── category_spec.rb # Scoped uniqueness
585
+ │ ├── daily_summary_spec.rb # Aggregation, idempotency
586
+ │ ├── item_spec.rb # Pricing, variants, scopes
587
+ ├── record_spec.rb # Base class
588
+ │ ├── simulated_order_spec.rb # Status transitions, scopes
589
+ │ └── simulated_payment_spec.rb # Tender classification, scopes
590
+ └── services/clover/
591
+ ├── cash_event_service_spec.rb
592
+ ├── customer_service_spec.rb
593
+ ├── discount_service_spec.rb
594
+ ├── employee_service_spec.rb
595
+ ├── financial_data_quality_spec.rb
596
+ ├── gift_card_service_spec.rb
597
+ ├── inventory_service_spec.rb
598
+ ├── order_service_spec.rb
599
+ ├── order_type_service_spec.rb
600
+ ├── payment_service_spec.rb
601
+ ├── refund_service_spec.rb
602
+ ├── service_charge_service_spec.rb
603
+ ├── services_manager_spec.rb
604
+ ├── shift_service_spec.rb
605
+ ├── tax_service_spec.rb
606
+ └── tender_service_spec.rb
501
607
  ```
502
608
 
503
609
  ### Idempotency Verification
@@ -519,6 +625,7 @@ The tests verify:
519
625
  - Tax rates are not duplicated
520
626
  - Order types are not duplicated
521
627
  - Employees/customers only created if count threshold not met
628
+ - Database seeder is idempotent across all 9 business types
522
629
 
523
630
  ## Sandbox Limitations
524
631
 
@@ -526,11 +633,11 @@ Some Clover sandbox operations may return errors or behave differently than prod
526
633
 
527
634
  | Feature | Sandbox Support | Notes |
528
635
  |---------|-----------------|-------|
529
- | Service Charge Creation | Limited | Must pre-configure in dashboard |
530
- | Cash Event Creation | Limited | Returns 405, simulated locally |
531
- | Item Tax Rate Fetch | Limited | Returns 405, simulated locally |
532
- | Credit Card Payments | Full | Via Ecommerce API |
533
- | Order Creation | Full | Today's date only |
636
+ | Service Charge Creation | Limited | Must pre-configure in dashboard |
637
+ | Cash Event Creation | Limited | Returns 405, simulated locally |
638
+ | Item Tax Rate Fetch | Limited | Returns 405, simulated locally |
639
+ | Credit Card Payments | Full | Via Ecommerce API |
640
+ | Order Creation | Full | Today's date only |
534
641
 
535
642
  The simulator handles these limitations gracefully with fallback behavior.
536
643
 
@@ -538,8 +645,9 @@ The simulator handles these limitations gracefully with fallback behavior.
538
645
 
539
646
  - **Sandbox URL**: `https://sandbox.dev.clover.com/`
540
647
  - **API Version**: v3
541
- - **Authentication**: Bearer token (OAuth)
648
+ - **Authentication**: Bearer token (OAuth) for Platform API; apikey header for tokenization
542
649
  - **Date Limitation**: Clover sandbox only allows creating orders for TODAY
650
+ - **Ecommerce API**: Separate endpoints for card tokenization, charges, and refunds
543
651
 
544
652
  ## License
545
653
 
@@ -217,11 +217,14 @@ module CloverSandboxSimulator
217
217
  @merchant_name = merchant["CLOVER_MERCHANT_NAME"]
218
218
  # CLOVER_API_TOKEN = static API token (never expires)
219
219
  # CLOVER_ACCESS_TOKEN = OAuth JWT token (expires, can be refreshed)
220
- # Prefer static API token if available, fall back to OAuth token
220
+ # PRIVATE_TOKEN = Ecommerce API key (can also serve as Bearer token for Platform API)
221
+ # Prefer static API token, fall back to OAuth token, then PRIVATE_TOKEN
221
222
  if merchant["CLOVER_API_TOKEN"].to_s.length > 10
222
223
  @api_token = merchant["CLOVER_API_TOKEN"]
223
224
  elsif merchant["CLOVER_ACCESS_TOKEN"].to_s.length > 10
224
225
  @api_token = merchant["CLOVER_ACCESS_TOKEN"]
226
+ elsif merchant["PRIVATE_TOKEN"].to_s.length > 10
227
+ @api_token = merchant["PRIVATE_TOKEN"]
225
228
  end
226
229
  @refresh_token = merchant["CLOVER_REFRESH_TOKEN"] if merchant["CLOVER_REFRESH_TOKEN"].to_s.length > 10
227
230
  @public_token = merchant["PUBLIC_TOKEN"] unless merchant["PUBLIC_TOKEN"].to_s.empty?
@@ -0,0 +1,24 @@
1
+ {
2
+ "categories": [
3
+ {
4
+ "name": "Haircuts",
5
+ "sort_order": 1,
6
+ "description": "Cuts and trims for all ages"
7
+ },
8
+ {
9
+ "name": "Color Services",
10
+ "sort_order": 2,
11
+ "description": "Color, highlights, and balayage"
12
+ },
13
+ {
14
+ "name": "Spa Treatments",
15
+ "sort_order": 3,
16
+ "description": "Massage and facials"
17
+ },
18
+ {
19
+ "name": "Nail Services",
20
+ "sort_order": 4,
21
+ "description": "Manicures and pedicures"
22
+ }
23
+ ]
24
+ }
@@ -0,0 +1,88 @@
1
+ {
2
+ "combos": [
3
+ {
4
+ "id": "cut_and_color",
5
+ "name": "Cut & Color Package",
6
+ "description": "Haircut + any color service for 10% off",
7
+ "discount_type": "percentage",
8
+ "discount_value": 10,
9
+ "required_components": [
10
+ {
11
+ "category": "Haircuts",
12
+ "quantity": 1
13
+ },
14
+ {
15
+ "category": "Color Services",
16
+ "quantity": 1
17
+ }
18
+ ],
19
+ "applies_to": "total",
20
+ "max_discount_amount": 2500,
21
+ "active": true
22
+ },
23
+ {
24
+ "id": "mani_pedi",
25
+ "name": "Mani-Pedi Combo",
26
+ "description": "Manicure + Pedicure for 15% off",
27
+ "discount_type": "percentage",
28
+ "discount_value": 15,
29
+ "required_components": [
30
+ {
31
+ "category": "Nail Services",
32
+ "quantity": 2
33
+ }
34
+ ],
35
+ "applies_to": "total",
36
+ "max_discount_amount": 1500,
37
+ "active": true
38
+ },
39
+ {
40
+ "id": "spa_day",
41
+ "name": "Spa Day Package",
42
+ "description": "Massage + Facial + Manicure for $25 off",
43
+ "discount_type": "fixed",
44
+ "discount_value": 2500,
45
+ "required_components": [
46
+ {
47
+ "category": "Spa Treatments",
48
+ "quantity": 2
49
+ },
50
+ {
51
+ "category": "Nail Services",
52
+ "quantity": 1
53
+ }
54
+ ],
55
+ "applies_to": "total",
56
+ "max_discount_amount": null,
57
+ "active": true
58
+ },
59
+ {
60
+ "id": "bridal_package",
61
+ "name": "Bridal Package",
62
+ "description": "Haircut + Color + Manicure + Facial for 20% off",
63
+ "discount_type": "percentage",
64
+ "discount_value": 20,
65
+ "required_components": [
66
+ {
67
+ "category": "Haircuts",
68
+ "quantity": 1
69
+ },
70
+ {
71
+ "category": "Color Services",
72
+ "quantity": 1
73
+ },
74
+ {
75
+ "category": "Nail Services",
76
+ "quantity": 1
77
+ },
78
+ {
79
+ "category": "Spa Treatments",
80
+ "quantity": 1
81
+ }
82
+ ],
83
+ "applies_to": "total",
84
+ "max_discount_amount": 5000,
85
+ "active": true
86
+ }
87
+ ]
88
+ }
@@ -0,0 +1,96 @@
1
+ {
2
+ "coupon_codes": [
3
+ {
4
+ "code": "NEWCLIENT20",
5
+ "name": "New Client 20% Off",
6
+ "description": "20% off for first-time clients",
7
+ "discount_type": "percentage",
8
+ "discount_value": 20,
9
+ "min_order_amount": 0,
10
+ "max_discount_amount": 5000,
11
+ "valid_from": "2024-01-01T00:00:00Z",
12
+ "valid_until": "2027-12-31T23:59:59Z",
13
+ "usage_limit": null,
14
+ "usage_count": 0,
15
+ "single_use_per_customer": true,
16
+ "new_customers_only": true,
17
+ "stackable": false,
18
+ "applicable_categories": null,
19
+ "excluded_categories": null,
20
+ "active": true
21
+ },
22
+ {
23
+ "code": "RELAX15",
24
+ "name": "Relaxation Discount",
25
+ "description": "15% off any spa treatment",
26
+ "discount_type": "percentage",
27
+ "discount_value": 15,
28
+ "min_order_amount": 0,
29
+ "max_discount_amount": 2500,
30
+ "valid_from": "2024-01-01T00:00:00Z",
31
+ "valid_until": "2027-12-31T23:59:59Z",
32
+ "usage_limit": null,
33
+ "usage_count": 0,
34
+ "single_use_per_customer": false,
35
+ "stackable": false,
36
+ "applicable_categories": ["Spa Treatments"],
37
+ "excluded_categories": null,
38
+ "active": true
39
+ },
40
+ {
41
+ "code": "NAILS10",
42
+ "name": "$10 Off Nails",
43
+ "description": "$10 off any nail service",
44
+ "discount_type": "fixed",
45
+ "discount_value": 1000,
46
+ "min_order_amount": 2500,
47
+ "max_discount_amount": null,
48
+ "valid_from": "2024-01-01T00:00:00Z",
49
+ "valid_until": "2027-12-31T23:59:59Z",
50
+ "usage_limit": 200,
51
+ "usage_count": 42,
52
+ "single_use_per_customer": true,
53
+ "stackable": false,
54
+ "applicable_categories": ["Nail Services"],
55
+ "excluded_categories": null,
56
+ "active": true
57
+ },
58
+ {
59
+ "code": "BIRTHDAY25",
60
+ "name": "Birthday Special",
61
+ "description": "25% off for your birthday month",
62
+ "discount_type": "percentage",
63
+ "discount_value": 25,
64
+ "min_order_amount": 0,
65
+ "max_discount_amount": null,
66
+ "valid_from": "2024-01-01T00:00:00Z",
67
+ "valid_until": "2027-12-31T23:59:59Z",
68
+ "usage_limit": null,
69
+ "usage_count": 0,
70
+ "single_use_per_customer": true,
71
+ "birthday_required": true,
72
+ "stackable": false,
73
+ "applicable_categories": null,
74
+ "excluded_categories": null,
75
+ "active": true
76
+ },
77
+ {
78
+ "code": "REFER20",
79
+ "name": "Referral Code",
80
+ "description": "20% off when referred by a friend",
81
+ "discount_type": "percentage",
82
+ "discount_value": 20,
83
+ "min_order_amount": 0,
84
+ "max_discount_amount": 4000,
85
+ "valid_from": "2024-01-01T00:00:00Z",
86
+ "valid_until": "2027-12-31T23:59:59Z",
87
+ "usage_limit": null,
88
+ "usage_count": 0,
89
+ "single_use_per_customer": true,
90
+ "stackable": false,
91
+ "applicable_categories": null,
92
+ "excluded_categories": null,
93
+ "active": true
94
+ }
95
+ ]
96
+ }
@@ -0,0 +1,93 @@
1
+ {
2
+ "discounts": [
3
+ {
4
+ "id": "new_client",
5
+ "name": "New Client Special",
6
+ "percentage": 20,
7
+ "description": "20% off first visit for new clients",
8
+ "type": "customer",
9
+ "auto_apply": false
10
+ },
11
+ {
12
+ "id": "referral_discount",
13
+ "name": "Referral Reward",
14
+ "percentage": 15,
15
+ "description": "15% off when referred by an existing client",
16
+ "type": "customer",
17
+ "auto_apply": false
18
+ },
19
+ {
20
+ "id": "senior_discount",
21
+ "name": "Senior Discount",
22
+ "percentage": 10,
23
+ "description": "10% off for seniors 65+",
24
+ "type": "customer",
25
+ "auto_apply": false
26
+ },
27
+ {
28
+ "id": "loyalty_bronze",
29
+ "name": "Loyalty - Bronze",
30
+ "percentage": 5,
31
+ "description": "5% off for 5+ visits",
32
+ "type": "loyalty",
33
+ "min_visits": 5,
34
+ "auto_apply": true
35
+ },
36
+ {
37
+ "id": "loyalty_silver",
38
+ "name": "Loyalty - Silver",
39
+ "percentage": 10,
40
+ "description": "10% off for 10+ visits",
41
+ "type": "loyalty",
42
+ "min_visits": 10,
43
+ "auto_apply": true
44
+ },
45
+ {
46
+ "id": "loyalty_gold",
47
+ "name": "Loyalty - Gold",
48
+ "percentage": 15,
49
+ "description": "15% off for 25+ visits",
50
+ "type": "loyalty",
51
+ "min_visits": 25,
52
+ "auto_apply": true
53
+ },
54
+ {
55
+ "id": "ten_off_color",
56
+ "name": "$10 Off Color Service",
57
+ "amount": 1000,
58
+ "description": "$10 off any color service over $80",
59
+ "type": "threshold",
60
+ "min_order_amount": 8000,
61
+ "auto_apply": false
62
+ },
63
+ {
64
+ "id": "twenty_off",
65
+ "name": "$20 Off",
66
+ "amount": 2000,
67
+ "description": "$20 off services over $100",
68
+ "type": "threshold",
69
+ "min_order_amount": 10000,
70
+ "auto_apply": false
71
+ },
72
+ {
73
+ "id": "nail_addon_discount",
74
+ "name": "Nail Add-On 50% Off",
75
+ "percentage": 50,
76
+ "description": "50% off nail art when added to any manicure or pedicure",
77
+ "type": "line_item",
78
+ "applicable_categories": ["Nail Services"],
79
+ "auto_apply": false
80
+ },
81
+ {
82
+ "id": "weekday_special",
83
+ "name": "Weekday Special",
84
+ "percentage": 10,
85
+ "description": "10% off services Monday-Wednesday",
86
+ "type": "time_based",
87
+ "time_rules": {
88
+ "valid_days": [1, 2, 3]
89
+ },
90
+ "auto_apply": true
91
+ }
92
+ ]
93
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "gift_cards": [
3
+ {
4
+ "card_number": "7012345678901234",
5
+ "initial_balance": 5000,
6
+ "current_balance": 5000,
7
+ "status": "ACTIVE",
8
+ "description": "$50 Salon Gift Card - Full balance"
9
+ },
10
+ {
11
+ "card_number": "7023456789012345",
12
+ "initial_balance": 10000,
13
+ "current_balance": 10000,
14
+ "status": "ACTIVE",
15
+ "description": "$100 Salon Gift Card - Full balance"
16
+ },
17
+ {
18
+ "card_number": "7034567890123456",
19
+ "initial_balance": 15000,
20
+ "current_balance": 15000,
21
+ "status": "ACTIVE",
22
+ "description": "$150 Salon Gift Card - Full balance"
23
+ },
24
+ {
25
+ "card_number": "7045678901234567",
26
+ "initial_balance": 10000,
27
+ "current_balance": 4500,
28
+ "status": "ACTIVE",
29
+ "description": "$100 Salon Gift Card - Partially used ($45 remaining)"
30
+ },
31
+ {
32
+ "card_number": "7056789012345678",
33
+ "initial_balance": 20000,
34
+ "current_balance": 20000,
35
+ "status": "ACTIVE",
36
+ "description": "$200 Salon Gift Card - Full balance"
37
+ }
38
+ ],
39
+ "purchase_denominations": [
40
+ { "amount": 5000, "label": "$50 Salon Gift Card" },
41
+ { "amount": 10000, "label": "$100 Salon Gift Card" },
42
+ { "amount": 15000, "label": "$150 Salon Gift Card" },
43
+ { "amount": 20000, "label": "$200 Salon Gift Card" },
44
+ { "amount": 25000, "label": "$250 Salon Gift Card" }
45
+ ],
46
+ "note": "Salon gift cards — popular for gifts and celebrations"
47
+ }
@@ -0,0 +1,100 @@
1
+ {
2
+ "items": [
3
+ {
4
+ "name": "Women's Haircut",
5
+ "price": 5500,
6
+ "category": "Haircuts",
7
+ "description": "Full haircut and style (45 min)"
8
+ },
9
+ {
10
+ "name": "Men's Haircut",
11
+ "price": 3000,
12
+ "category": "Haircuts",
13
+ "description": "Classic cut and finish (30 min)"
14
+ },
15
+ {
16
+ "name": "Children's Haircut",
17
+ "price": 2000,
18
+ "category": "Haircuts",
19
+ "description": "Kids cut, ages 12 and under (20 min)"
20
+ },
21
+ {
22
+ "name": "Bang Trim",
23
+ "price": 1500,
24
+ "category": "Haircuts",
25
+ "description": "Quick bang trim between cuts (15 min)"
26
+ },
27
+ {
28
+ "name": "Full Color",
29
+ "price": 12000,
30
+ "category": "Color Services",
31
+ "description": "All-over single process color (120 min)"
32
+ },
33
+ {
34
+ "name": "Highlights (Partial)",
35
+ "price": 9000,
36
+ "category": "Color Services",
37
+ "description": "Partial foil highlights (90 min)"
38
+ },
39
+ {
40
+ "name": "Highlights (Full)",
41
+ "price": 15000,
42
+ "category": "Color Services",
43
+ "description": "Full head foil highlights (120 min)"
44
+ },
45
+ {
46
+ "name": "Balayage",
47
+ "price": 18000,
48
+ "category": "Color Services",
49
+ "description": "Hand-painted color technique (150 min)"
50
+ },
51
+ {
52
+ "name": "Swedish Massage (60min)",
53
+ "price": 9500,
54
+ "category": "Spa Treatments",
55
+ "description": "Relaxation full-body massage"
56
+ },
57
+ {
58
+ "name": "Deep Tissue Massage (60min)",
59
+ "price": 11000,
60
+ "category": "Spa Treatments",
61
+ "description": "Therapeutic deep pressure massage"
62
+ },
63
+ {
64
+ "name": "Hot Stone Massage (60min)",
65
+ "price": 12000,
66
+ "category": "Spa Treatments",
67
+ "description": "Heated basalt stone therapy massage"
68
+ },
69
+ {
70
+ "name": "Facial (60min)",
71
+ "price": 8500,
72
+ "category": "Spa Treatments",
73
+ "description": "Customized facial with extractions"
74
+ },
75
+ {
76
+ "name": "Manicure",
77
+ "price": 2500,
78
+ "category": "Nail Services",
79
+ "description": "Classic manicure with polish (30 min)"
80
+ },
81
+ {
82
+ "name": "Pedicure",
83
+ "price": 3500,
84
+ "category": "Nail Services",
85
+ "description": "Classic pedicure with polish (45 min)"
86
+ },
87
+ {
88
+ "name": "Gel Manicure",
89
+ "price": 4000,
90
+ "category": "Nail Services",
91
+ "description": "Long-lasting gel polish manicure (45 min)"
92
+ },
93
+ {
94
+ "name": "Acrylic Full Set",
95
+ "price": 5500,
96
+ "category": "Nail Services",
97
+ "description": "Full set of acrylic nail extensions (60 min)"
98
+ }
99
+ ]
100
+ }
@@ -0,0 +1,49 @@
1
+ {
2
+ "modifier_groups": [
3
+ {
4
+ "name": "Stylist Level",
5
+ "min_required": 0,
6
+ "max_allowed": 1,
7
+ "modifiers": [
8
+ { "name": "Junior Stylist", "price": 0 },
9
+ { "name": "Senior Stylist", "price": 1500 },
10
+ { "name": "Master Stylist", "price": 3000 },
11
+ { "name": "Artistic Director", "price": 5000 }
12
+ ]
13
+ },
14
+ {
15
+ "name": "Add-On Treatments",
16
+ "min_required": 0,
17
+ "max_allowed": 3,
18
+ "modifiers": [
19
+ { "name": "Deep Conditioning Treatment", "price": 2500 },
20
+ { "name": "Scalp Treatment", "price": 2000 },
21
+ { "name": "Gloss Treatment", "price": 3500 },
22
+ { "name": "Olaplex Treatment", "price": 4500 },
23
+ { "name": "Keratin Treatment", "price": 8000 }
24
+ ]
25
+ },
26
+ {
27
+ "name": "Nail Art",
28
+ "min_required": 0,
29
+ "max_allowed": 1,
30
+ "modifiers": [
31
+ { "name": "Simple Design (2 nails)", "price": 500 },
32
+ { "name": "Full Art (all nails)", "price": 1500 },
33
+ { "name": "Chrome/Ombre Finish", "price": 1000 },
34
+ { "name": "French Tips", "price": 800 }
35
+ ]
36
+ },
37
+ {
38
+ "name": "Massage Upgrade",
39
+ "min_required": 0,
40
+ "max_allowed": 2,
41
+ "modifiers": [
42
+ { "name": "Aromatherapy", "price": 1000 },
43
+ { "name": "CBD Oil", "price": 1500 },
44
+ { "name": "Extended 30 min", "price": 5000 },
45
+ { "name": "Couples Room", "price": 2000 }
46
+ ]
47
+ }
48
+ ]
49
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "tax_rates": [
3
+ {
4
+ "name": "Service Tax",
5
+ "rate": 8.25,
6
+ "is_default": true,
7
+ "description": "Standard sales tax on salon and spa services"
8
+ }
9
+ ],
10
+ "category_tax_mapping": {
11
+ "Haircuts": ["Service Tax"],
12
+ "Color Services": ["Service Tax"],
13
+ "Spa Treatments": ["Service Tax"],
14
+ "Nail Services": ["Service Tax"],
15
+ "default": ["Service Tax"]
16
+ }
17
+ }
@@ -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": 25
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": 20
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
+ }
@@ -10,7 +10,7 @@ require "dotenv"
10
10
  Dotenv.load
11
11
 
12
12
  module CloverSandboxSimulator
13
- VERSION = "1.4.0"
13
+ VERSION = "1.6.0"
14
14
 
15
15
  class Error < StandardError; end
16
16
  class ConfigurationError < Error; end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clover_sandbox_simulator
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - dan1d
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-02-07 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rest-client
@@ -258,6 +257,15 @@ files:
258
257
  - lib/clover_sandbox_simulator/data/restaurant/modifiers.json
259
258
  - lib/clover_sandbox_simulator/data/restaurant/tax_rates.json
260
259
  - lib/clover_sandbox_simulator/data/restaurant/tenders.json
260
+ - lib/clover_sandbox_simulator/data/salon_spa/categories.json
261
+ - lib/clover_sandbox_simulator/data/salon_spa/combos.json
262
+ - lib/clover_sandbox_simulator/data/salon_spa/coupon_codes.json
263
+ - lib/clover_sandbox_simulator/data/salon_spa/discounts.json
264
+ - lib/clover_sandbox_simulator/data/salon_spa/gift_cards.json
265
+ - lib/clover_sandbox_simulator/data/salon_spa/items.json
266
+ - lib/clover_sandbox_simulator/data/salon_spa/modifiers.json
267
+ - lib/clover_sandbox_simulator/data/salon_spa/tax_rates.json
268
+ - lib/clover_sandbox_simulator/data/salon_spa/tenders.json
261
269
  - lib/clover_sandbox_simulator/database.rb
262
270
  - lib/clover_sandbox_simulator/db/factories/api_requests.rb
263
271
  - lib/clover_sandbox_simulator/db/factories/business_types.rb
@@ -309,7 +317,6 @@ homepage: https://github.com/dan1d/clover_sandbox_simulator
309
317
  licenses:
310
318
  - MIT
311
319
  metadata: {}
312
- post_install_message:
313
320
  rdoc_options: []
314
321
  require_paths:
315
322
  - lib
@@ -324,8 +331,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
324
331
  - !ruby/object:Gem::Version
325
332
  version: '0'
326
333
  requirements: []
327
- rubygems_version: 3.4.10
328
- signing_key:
334
+ rubygems_version: 3.6.9
329
335
  specification_version: 4
330
336
  summary: Clover Sandbox Simulator for generating realistic restaurant data
331
337
  test_files: []