elia_ruby 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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +202 -0
- data/lib/elia/mcc/active_model_validator.rb +50 -0
- data/lib/elia/mcc/category.rb +107 -0
- data/lib/elia/mcc/code.rb +242 -0
- data/lib/elia/mcc/collection.rb +276 -0
- data/lib/elia/mcc/configuration.rb +85 -0
- data/lib/elia/mcc/data/.gitkeep +0 -0
- data/lib/elia/mcc/data/mcc_codes.yml +12809 -0
- data/lib/elia/mcc/data/ranges.yml +126 -0
- data/lib/elia/mcc/data/risk_categories.yml +293 -0
- data/lib/elia/mcc/errors.rb +48 -0
- data/lib/elia/mcc/railtie.rb +36 -0
- data/lib/elia/mcc/range.rb +158 -0
- data/lib/elia/mcc/serializer.rb +89 -0
- data/lib/elia/mcc/validator.rb +102 -0
- data/lib/elia/mcc/version.rb +7 -0
- data/lib/elia/mcc.rb +65 -0
- data/lib/elia_ruby/version.rb +5 -0
- data/lib/elia_ruby.rb +35 -0
- metadata +98 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# ISO 18245 MCC Ranges
|
|
2
|
+
# Defines the standard industry classification ranges for Merchant Category Codes
|
|
3
|
+
# Source: ISO 18245 Standard
|
|
4
|
+
---
|
|
5
|
+
- start: "0000"
|
|
6
|
+
end: "0699"
|
|
7
|
+
name: "Reserved"
|
|
8
|
+
description: "Reserved for ISO use"
|
|
9
|
+
reserved: true
|
|
10
|
+
|
|
11
|
+
- start: "0700"
|
|
12
|
+
end: "0999"
|
|
13
|
+
name: "Agricultural Services"
|
|
14
|
+
description: "Agricultural services including veterinary and horticultural services"
|
|
15
|
+
reserved: false
|
|
16
|
+
|
|
17
|
+
- start: "1000"
|
|
18
|
+
end: "1499"
|
|
19
|
+
name: "Reserved"
|
|
20
|
+
description: "Reserved for future use"
|
|
21
|
+
reserved: true
|
|
22
|
+
|
|
23
|
+
- start: "1500"
|
|
24
|
+
end: "2999"
|
|
25
|
+
name: "Contracted Services"
|
|
26
|
+
description: "Contracted services including general and specialty construction contractors"
|
|
27
|
+
reserved: false
|
|
28
|
+
|
|
29
|
+
- start: "3000"
|
|
30
|
+
end: "3350"
|
|
31
|
+
name: "Airlines"
|
|
32
|
+
description: "Specific airline codes for major carriers"
|
|
33
|
+
reserved: false
|
|
34
|
+
private_use: true
|
|
35
|
+
|
|
36
|
+
- start: "3351"
|
|
37
|
+
end: "3500"
|
|
38
|
+
name: "Car Rentals"
|
|
39
|
+
description: "Specific car rental company codes"
|
|
40
|
+
reserved: false
|
|
41
|
+
private_use: true
|
|
42
|
+
|
|
43
|
+
- start: "3501"
|
|
44
|
+
end: "3999"
|
|
45
|
+
name: "Lodging"
|
|
46
|
+
description: "Specific hotel and lodging establishment codes"
|
|
47
|
+
reserved: false
|
|
48
|
+
private_use: true
|
|
49
|
+
|
|
50
|
+
- start: "4000"
|
|
51
|
+
end: "4799"
|
|
52
|
+
name: "Transportation"
|
|
53
|
+
description: "Transportation services including railroads, airlines, buses, and freight"
|
|
54
|
+
reserved: false
|
|
55
|
+
|
|
56
|
+
- start: "4800"
|
|
57
|
+
end: "4999"
|
|
58
|
+
name: "Utilities"
|
|
59
|
+
description: "Utility services including telecommunications, electricity, gas, and water"
|
|
60
|
+
reserved: false
|
|
61
|
+
|
|
62
|
+
- start: "5000"
|
|
63
|
+
end: "5599"
|
|
64
|
+
name: "Retail Outlets"
|
|
65
|
+
description: "Retail outlets including wholesale, department stores, and specialty retail"
|
|
66
|
+
reserved: false
|
|
67
|
+
|
|
68
|
+
- start: "5600"
|
|
69
|
+
end: "5699"
|
|
70
|
+
name: "Clothing Outlets"
|
|
71
|
+
description: "Clothing and apparel stores"
|
|
72
|
+
reserved: false
|
|
73
|
+
|
|
74
|
+
- start: "5700"
|
|
75
|
+
end: "5999"
|
|
76
|
+
name: "Miscellaneous Retail"
|
|
77
|
+
description: "Miscellaneous retail stores including food service, pharmacies, and specialty shops"
|
|
78
|
+
reserved: false
|
|
79
|
+
|
|
80
|
+
- start: "6000"
|
|
81
|
+
end: "7299"
|
|
82
|
+
name: "Service Providers"
|
|
83
|
+
description: "Service provider businesses including financial services, lodging, and personal services"
|
|
84
|
+
reserved: false
|
|
85
|
+
|
|
86
|
+
- start: "7300"
|
|
87
|
+
end: "7529"
|
|
88
|
+
name: "Business Services"
|
|
89
|
+
description: "Business services including advertising, consulting, and equipment rental"
|
|
90
|
+
reserved: false
|
|
91
|
+
|
|
92
|
+
- start: "7530"
|
|
93
|
+
end: "7799"
|
|
94
|
+
name: "Repair Services"
|
|
95
|
+
description: "Repair and automotive services"
|
|
96
|
+
reserved: false
|
|
97
|
+
|
|
98
|
+
- start: "7800"
|
|
99
|
+
end: "7999"
|
|
100
|
+
name: "Entertainment"
|
|
101
|
+
description: "Amusement and entertainment including gambling, recreation, and sports"
|
|
102
|
+
reserved: false
|
|
103
|
+
|
|
104
|
+
- start: "8000"
|
|
105
|
+
end: "8999"
|
|
106
|
+
name: "Professional Services"
|
|
107
|
+
description: "Professional services and membership organizations including healthcare, legal, and education"
|
|
108
|
+
reserved: false
|
|
109
|
+
|
|
110
|
+
- start: "9000"
|
|
111
|
+
end: "9199"
|
|
112
|
+
name: "Reserved for ISO"
|
|
113
|
+
description: "Reserved for ISO use"
|
|
114
|
+
reserved: true
|
|
115
|
+
|
|
116
|
+
- start: "9200"
|
|
117
|
+
end: "9402"
|
|
118
|
+
name: "Government Services"
|
|
119
|
+
description: "Government services including courts, fines, taxes, and postal services"
|
|
120
|
+
reserved: false
|
|
121
|
+
|
|
122
|
+
- start: "9403"
|
|
123
|
+
end: "9999"
|
|
124
|
+
name: "Other"
|
|
125
|
+
description: "Other services and intra-company purchases"
|
|
126
|
+
reserved: false
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Risk-Based MCC Categories for Payment Control
|
|
2
|
+
# These categories are commonly used for merchant restrictions, spend controls,
|
|
3
|
+
# and risk management in payment systems.
|
|
4
|
+
---
|
|
5
|
+
airlines:
|
|
6
|
+
name: "Airlines"
|
|
7
|
+
description: "Airlines and air carriers only"
|
|
8
|
+
codes:
|
|
9
|
+
- "3000-3350" # Specific airline codes (United, Delta, American, etc.)
|
|
10
|
+
- "4415" # Air Courier Services
|
|
11
|
+
- "4511" # Airlines, Air Carriers
|
|
12
|
+
|
|
13
|
+
gambling:
|
|
14
|
+
name: "Gambling"
|
|
15
|
+
description: "Casinos, betting, lottery, and gaming"
|
|
16
|
+
codes:
|
|
17
|
+
- "7800" # Government Owned Lotteries (US only)
|
|
18
|
+
- "7801" # Government Licensed Casinos (Online Gambling)
|
|
19
|
+
- "7802" # Government Licensed Horse/Dog Racing
|
|
20
|
+
- "7995" # Betting/Casino Gambling
|
|
21
|
+
- "9406" # Government-owned Lottery (non-US)
|
|
22
|
+
|
|
23
|
+
adult:
|
|
24
|
+
name: "Adult Entertainment"
|
|
25
|
+
description: "Adult content and services"
|
|
26
|
+
codes:
|
|
27
|
+
- "5967" # Direct Marketing - Inbound Teleservices Merchant
|
|
28
|
+
- "7273" # Dating/Escort Services
|
|
29
|
+
- "7297" # Massage Parlors
|
|
30
|
+
|
|
31
|
+
crypto:
|
|
32
|
+
name: "Cryptocurrency"
|
|
33
|
+
description: "Cryptocurrency and digital asset exchanges"
|
|
34
|
+
codes:
|
|
35
|
+
- "6051" # Non-FI Money Orders, Foreign Currency, Cryptocurrency
|
|
36
|
+
- "6211" # Security Brokers/Dealers
|
|
37
|
+
|
|
38
|
+
high_risk:
|
|
39
|
+
name: "High Risk"
|
|
40
|
+
description: "Industries with high chargeback or fraud rates"
|
|
41
|
+
codes:
|
|
42
|
+
- "5962" # Direct Marketing - Travel Related
|
|
43
|
+
- "5966" # Direct Marketing - Outbound Telemarketing
|
|
44
|
+
- "5967" # Direct Marketing - Inbound Teleservices
|
|
45
|
+
- "5968" # Direct Marketing - Subscription
|
|
46
|
+
- "7841" # Video Tape Rental Stores
|
|
47
|
+
- "5933" # Pawn Shops
|
|
48
|
+
- "5935" # Wrecking and Salvage Yards
|
|
49
|
+
|
|
50
|
+
travel:
|
|
51
|
+
name: "Travel"
|
|
52
|
+
description: "Travel services (excluding airlines)"
|
|
53
|
+
codes:
|
|
54
|
+
- "3351-3500" # Car Rentals
|
|
55
|
+
- "3501-3999" # Hotels and Lodging
|
|
56
|
+
- "4411" # Cruise Lines
|
|
57
|
+
- "4722" # Travel Agencies
|
|
58
|
+
- "4723" # Package Tour Operators
|
|
59
|
+
- "7011" # Hotels and Motels
|
|
60
|
+
- "7012" # Timeshares
|
|
61
|
+
- "7032" # Sporting and Recreational Camps
|
|
62
|
+
- "7033" # Trailer Parks and Campgrounds
|
|
63
|
+
- "7512" # Car Rental
|
|
64
|
+
|
|
65
|
+
fuel:
|
|
66
|
+
name: "Fuel"
|
|
67
|
+
description: "Gas stations and fuel dispensers"
|
|
68
|
+
codes:
|
|
69
|
+
- "5172" # Petroleum Products
|
|
70
|
+
- "5541" # Service Stations
|
|
71
|
+
- "5542" # Automated Fuel Dispensers
|
|
72
|
+
- "5983" # Fuel Dealers
|
|
73
|
+
|
|
74
|
+
financial:
|
|
75
|
+
name: "Financial Services"
|
|
76
|
+
description: "Banks, money orders, wire transfers, and stored value"
|
|
77
|
+
codes:
|
|
78
|
+
- "6010" # Financial Institutions - Manual Cash
|
|
79
|
+
- "6011" # Financial Institutions - Automated Cash
|
|
80
|
+
- "6012" # Financial Institutions - Merchandise and Services
|
|
81
|
+
- "6050" # Quasi Cash - Financial Institutions
|
|
82
|
+
- "6051" # Non-FI Money Orders
|
|
83
|
+
- "6211" # Security Brokers/Dealers
|
|
84
|
+
- "6300" # Insurance Sales
|
|
85
|
+
- "6513" # Real Estate Agents
|
|
86
|
+
- "6540" # Non-FI Stored Value Card
|
|
87
|
+
- "4829" # Wire Transfers and Money Orders
|
|
88
|
+
|
|
89
|
+
legal_services:
|
|
90
|
+
name: "Legal Services"
|
|
91
|
+
description: "Attorneys, bail bonds, legal services"
|
|
92
|
+
codes:
|
|
93
|
+
- "8111" # Legal Services and Attorneys
|
|
94
|
+
- "9223" # Bail and Bond Payments
|
|
95
|
+
|
|
96
|
+
healthcare:
|
|
97
|
+
name: "Healthcare"
|
|
98
|
+
description: "Medical services, hospitals, and pharmacies"
|
|
99
|
+
codes:
|
|
100
|
+
- "4119" # Ambulance Services
|
|
101
|
+
- "5122" # Drugs and Proprietary
|
|
102
|
+
- "5912" # Drug Stores and Pharmacies
|
|
103
|
+
- "8011" # Doctors
|
|
104
|
+
- "8021" # Dentists and Orthodontists
|
|
105
|
+
- "8031" # Osteopaths
|
|
106
|
+
- "8041" # Chiropractors
|
|
107
|
+
- "8042" # Optometrists
|
|
108
|
+
- "8043" # Opticians
|
|
109
|
+
- "8049" # Podiatrists
|
|
110
|
+
- "8050" # Nursing and Personal Care Facilities
|
|
111
|
+
- "8062" # Hospitals
|
|
112
|
+
- "8071" # Medical and Dental Laboratories
|
|
113
|
+
- "8099" # Medical Services
|
|
114
|
+
|
|
115
|
+
government:
|
|
116
|
+
name: "Government"
|
|
117
|
+
description: "Government services, fines, and taxes"
|
|
118
|
+
codes:
|
|
119
|
+
- "9211" # Court Costs
|
|
120
|
+
- "9222" # Fines
|
|
121
|
+
- "9223" # Bail and Bond Payments
|
|
122
|
+
- "9311" # Tax Payments
|
|
123
|
+
- "9399" # Government Services
|
|
124
|
+
- "9402" # Postal Services - Government Only
|
|
125
|
+
- "9405" # Intra-Government Purchases
|
|
126
|
+
|
|
127
|
+
food_and_dining:
|
|
128
|
+
name: "Food and Dining"
|
|
129
|
+
description: "Restaurants, fast food, and grocery stores"
|
|
130
|
+
codes:
|
|
131
|
+
- "5411" # Grocery Stores, Supermarkets
|
|
132
|
+
- "5422" # Freezer and Locker Meat Provisioners
|
|
133
|
+
- "5441" # Candy, Nut, Confectionery
|
|
134
|
+
- "5451" # Dairy Products
|
|
135
|
+
- "5462" # Bakeries
|
|
136
|
+
- "5499" # Miscellaneous Food Stores
|
|
137
|
+
- "5811" # Caterers
|
|
138
|
+
- "5812" # Eating Places, Restaurants
|
|
139
|
+
- "5813" # Drinking Places (Bars)
|
|
140
|
+
- "5814" # Fast Food Restaurants
|
|
141
|
+
|
|
142
|
+
retail:
|
|
143
|
+
name: "General Retail"
|
|
144
|
+
description: "General merchandise and department stores"
|
|
145
|
+
codes:
|
|
146
|
+
- "5300" # Wholesale Clubs
|
|
147
|
+
- "5309" # Duty Free Stores
|
|
148
|
+
- "5310" # Discount Stores
|
|
149
|
+
- "5311" # Department Stores
|
|
150
|
+
- "5331" # Variety Stores
|
|
151
|
+
- "5399" # Miscellaneous General Merchandise
|
|
152
|
+
|
|
153
|
+
electronics:
|
|
154
|
+
name: "Electronics"
|
|
155
|
+
description: "Electronics and computer stores"
|
|
156
|
+
codes:
|
|
157
|
+
- "5045" # Computers and Peripherals
|
|
158
|
+
- "5732" # Electronics Stores
|
|
159
|
+
- "5734" # Computer Software Stores
|
|
160
|
+
- "5815" # Digital Goods - Media
|
|
161
|
+
- "5816" # Digital Goods - Games
|
|
162
|
+
- "5817" # Digital Goods - Applications
|
|
163
|
+
- "5818" # Digital Goods - Large Volume
|
|
164
|
+
|
|
165
|
+
office_supplies:
|
|
166
|
+
name: "Office Supplies"
|
|
167
|
+
description: "Office equipment and supplies"
|
|
168
|
+
codes:
|
|
169
|
+
- "5021" # Office and Commercial Furniture
|
|
170
|
+
- "5044" # Office, Photographic Equipment
|
|
171
|
+
- "5111" # Stationery, Office Supplies
|
|
172
|
+
- "5943" # Stationery, Office and School Supply Stores
|
|
173
|
+
|
|
174
|
+
education:
|
|
175
|
+
name: "Education"
|
|
176
|
+
description: "Schools and educational services"
|
|
177
|
+
codes:
|
|
178
|
+
- "8211" # Elementary and Secondary Schools
|
|
179
|
+
- "8220" # Colleges, Universities
|
|
180
|
+
- "8241" # Correspondence Schools
|
|
181
|
+
- "8244" # Business and Secretarial Schools
|
|
182
|
+
- "8249" # Trade and Vocational Schools
|
|
183
|
+
- "8299" # Educational Services
|
|
184
|
+
- "8351" # Child Care Services
|
|
185
|
+
|
|
186
|
+
professional_services:
|
|
187
|
+
name: "Professional Services"
|
|
188
|
+
description: "Consulting, accounting, and other professional services"
|
|
189
|
+
codes:
|
|
190
|
+
- "7311" # Advertising Services
|
|
191
|
+
- "7321" # Credit Reporting Agencies
|
|
192
|
+
- "7322" # Collection Agencies
|
|
193
|
+
- "7372" # Computer Programming
|
|
194
|
+
- "7375" # Information Retrieval Services
|
|
195
|
+
- "7379" # Computer Maintenance
|
|
196
|
+
- "7392" # Management Consulting
|
|
197
|
+
- "8911" # Architectural, Engineering Services
|
|
198
|
+
- "8931" # Accounting, Auditing, Bookkeeping
|
|
199
|
+
- "8999" # Professional Services
|
|
200
|
+
|
|
201
|
+
entertainment:
|
|
202
|
+
name: "Entertainment"
|
|
203
|
+
description: "Recreation and entertainment (excluding gambling)"
|
|
204
|
+
codes:
|
|
205
|
+
- "7829" # Motion Picture Production
|
|
206
|
+
- "7832" # Motion Picture Theaters
|
|
207
|
+
- "7841" # Video Tape Rentals
|
|
208
|
+
- "7911" # Dance Halls, Studios
|
|
209
|
+
- "7922" # Theatrical Producers, Ticket Agencies
|
|
210
|
+
- "7929" # Bands, Orchestras
|
|
211
|
+
- "7932" # Billiard and Pool
|
|
212
|
+
- "7933" # Bowling Alleys
|
|
213
|
+
- "7941" # Sports Clubs
|
|
214
|
+
- "7991" # Tourist Attractions
|
|
215
|
+
- "7992" # Golf Courses
|
|
216
|
+
- "7993" # Video Amusement Game Supplies
|
|
217
|
+
- "7994" # Video Game Arcades
|
|
218
|
+
- "7996" # Amusement Parks
|
|
219
|
+
- "7997" # Country Clubs
|
|
220
|
+
- "7998" # Aquariums
|
|
221
|
+
- "7999" # Recreation Services
|
|
222
|
+
|
|
223
|
+
automotive:
|
|
224
|
+
name: "Automotive"
|
|
225
|
+
description: "Automotive sales, service, and parts"
|
|
226
|
+
codes:
|
|
227
|
+
- "5013" # Motor Vehicle Supplies
|
|
228
|
+
- "5511" # Car and Truck Dealers (New and Used)
|
|
229
|
+
- "5521" # Car and Truck Dealers (Used Only)
|
|
230
|
+
- "5531" # Auto and Home Supply
|
|
231
|
+
- "5532" # Automotive Tire Stores
|
|
232
|
+
- "5533" # Automotive Parts
|
|
233
|
+
- "5541" # Service Stations
|
|
234
|
+
- "5542" # Automated Fuel Dispensers
|
|
235
|
+
- "5551" # Boat Dealers
|
|
236
|
+
- "5561" # Camper, Trailer Dealers
|
|
237
|
+
- "5571" # Motorcycle Shops
|
|
238
|
+
- "5592" # Motor Home Dealers
|
|
239
|
+
- "5598" # Snowmobile Dealers
|
|
240
|
+
- "5599" # Misc. Automotive Dealers
|
|
241
|
+
- "7512" # Car Rental
|
|
242
|
+
- "7513" # Truck Rental
|
|
243
|
+
- "7519" # Motor Home Rental
|
|
244
|
+
- "7523" # Parking Lots
|
|
245
|
+
- "7531" # Automotive Body Repair
|
|
246
|
+
- "7534" # Tire Repair
|
|
247
|
+
- "7535" # Automotive Paint
|
|
248
|
+
- "7538" # Automotive Service Shops
|
|
249
|
+
- "7542" # Car Washes
|
|
250
|
+
- "7549" # Towing Services
|
|
251
|
+
|
|
252
|
+
charities:
|
|
253
|
+
name: "Charities and Non-Profits"
|
|
254
|
+
description: "Charitable organizations and religious groups"
|
|
255
|
+
codes:
|
|
256
|
+
- "8398" # Charitable and Social Service Organizations
|
|
257
|
+
- "8641" # Civic, Social, Fraternal Associations
|
|
258
|
+
- "8651" # Political Organizations
|
|
259
|
+
- "8661" # Religious Organizations
|
|
260
|
+
- "8699" # Membership Organizations
|
|
261
|
+
|
|
262
|
+
telecom:
|
|
263
|
+
name: "Telecommunications"
|
|
264
|
+
description: "Telephone and internet services"
|
|
265
|
+
codes:
|
|
266
|
+
- "4812" # Telecommunication Equipment
|
|
267
|
+
- "4813" # Key-entry Telecom
|
|
268
|
+
- "4814" # Telecommunication Services
|
|
269
|
+
- "4815" # Monthly Summary Telephone
|
|
270
|
+
- "4816" # Computer Network Services
|
|
271
|
+
- "4821" # Telegraph Services
|
|
272
|
+
- "4899" # Cable and Pay Television
|
|
273
|
+
|
|
274
|
+
utilities:
|
|
275
|
+
name: "Utilities"
|
|
276
|
+
description: "Electric, gas, and water services"
|
|
277
|
+
codes:
|
|
278
|
+
- "4900" # Utilities - Electric, Gas, Water
|
|
279
|
+
|
|
280
|
+
construction:
|
|
281
|
+
name: "Construction"
|
|
282
|
+
description: "General and specialty contractors"
|
|
283
|
+
codes:
|
|
284
|
+
- "1520" # General Contractors
|
|
285
|
+
- "1711" # Heating, Plumbing, A/C Contractors
|
|
286
|
+
- "1731" # Electrical Contractors
|
|
287
|
+
- "1740" # Masonry, Plastering Contractors
|
|
288
|
+
- "1750" # Carpentry Contractors
|
|
289
|
+
- "1761" # Roofing, Siding Contractors
|
|
290
|
+
- "1771" # Concrete Work Contractors
|
|
291
|
+
- "1799" # Special Trade Contractors
|
|
292
|
+
- "5039" # Construction Materials
|
|
293
|
+
- "5211" # Lumber and Building Materials
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Elia
|
|
4
|
+
module Mcc
|
|
5
|
+
# Base error class for all MCC-related errors
|
|
6
|
+
class Error < StandardError; end
|
|
7
|
+
|
|
8
|
+
# Raised when an MCC code is not found in the registry
|
|
9
|
+
class NotFound < Error
|
|
10
|
+
def initialize(code)
|
|
11
|
+
super("MCC code not found: #{code.inspect}")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Raised when an invalid MCC code format is provided
|
|
16
|
+
class InvalidCode < Error
|
|
17
|
+
def initialize(code)
|
|
18
|
+
super("Invalid MCC code format: #{code.inspect}. Expected a 4-digit string or integer.")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Raised when an invalid range is specified
|
|
23
|
+
class InvalidRange < Error
|
|
24
|
+
def initialize(message = "Invalid MCC range specified")
|
|
25
|
+
super
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Raised when configuration is invalid
|
|
30
|
+
class ConfigurationError < Error; end
|
|
31
|
+
|
|
32
|
+
# Raised when data files cannot be loaded
|
|
33
|
+
class DataLoadError < Error
|
|
34
|
+
def initialize(file_path, original_error = nil)
|
|
35
|
+
message = "Failed to load MCC data from: #{file_path}"
|
|
36
|
+
message += " (#{original_error.message})" if original_error
|
|
37
|
+
super(message)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Raised when a category is not found
|
|
42
|
+
class CategoryNotFound < Error
|
|
43
|
+
def initialize(category)
|
|
44
|
+
super("Category not found: #{category.inspect}")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Elia
|
|
4
|
+
module Mcc
|
|
5
|
+
# Rails integration for the Elia::Mcc module
|
|
6
|
+
#
|
|
7
|
+
# Provides automatic setup when used within a Rails application,
|
|
8
|
+
# including configuration and ActiveModel integration.
|
|
9
|
+
class Railtie < Rails::Railtie
|
|
10
|
+
initializer "elia_mcc.configure" do |app|
|
|
11
|
+
# Allow custom data path from Rails config directory
|
|
12
|
+
Elia::Mcc.configure do |config|
|
|
13
|
+
if app.root
|
|
14
|
+
custom_data_path = app.root.join("config", "mcc_data")
|
|
15
|
+
config.data_path = custom_data_path.to_s if custom_data_path.exist?
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Load ActiveModel validator when ActiveModel is loaded
|
|
21
|
+
initializer "elia_mcc.active_model" do
|
|
22
|
+
ActiveSupport.on_load(:active_model) do
|
|
23
|
+
require "elia/mcc/active_model_validator"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Eager load MCC data after initialization if caching is enabled
|
|
28
|
+
config.after_initialize do
|
|
29
|
+
if Elia::Mcc.configuration.cache_enabled
|
|
30
|
+
# Touch the collection to trigger lazy loading
|
|
31
|
+
Elia::Mcc.count
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Elia
|
|
4
|
+
module Mcc
|
|
5
|
+
# Represents an ISO 18245 MCC range
|
|
6
|
+
#
|
|
7
|
+
# Ranges define groups of related MCC codes by industry segment
|
|
8
|
+
# according to the ISO 18245 standard.
|
|
9
|
+
class Range
|
|
10
|
+
# @return [String] the starting MCC code (inclusive)
|
|
11
|
+
attr_reader :start_code
|
|
12
|
+
|
|
13
|
+
# @return [String] the ending MCC code (inclusive)
|
|
14
|
+
attr_reader :end_code
|
|
15
|
+
|
|
16
|
+
# @return [String] the name of this range
|
|
17
|
+
attr_reader :name
|
|
18
|
+
|
|
19
|
+
# @return [String] description of this range
|
|
20
|
+
attr_reader :description
|
|
21
|
+
|
|
22
|
+
# @return [Boolean] whether this range is reserved
|
|
23
|
+
attr_reader :reserved
|
|
24
|
+
|
|
25
|
+
# Creates a new Range instance
|
|
26
|
+
#
|
|
27
|
+
# @param attributes [Hash] the range attributes
|
|
28
|
+
# @option attributes [String, Integer] :start the starting MCC code
|
|
29
|
+
# @option attributes [String, Integer] :end the ending MCC code
|
|
30
|
+
# @option attributes [String] :name the name of the range
|
|
31
|
+
# @option attributes [String] :description description of the range
|
|
32
|
+
# @option attributes [Boolean] :reserved whether the range is reserved
|
|
33
|
+
# @raise [InvalidRange] if the range is invalid
|
|
34
|
+
def initialize(attributes = {})
|
|
35
|
+
attributes = attributes.transform_keys(&:to_sym)
|
|
36
|
+
|
|
37
|
+
@start_code = normalize_code(attributes[:start] || attributes[:start_code])
|
|
38
|
+
@end_code = normalize_code(attributes[:end] || attributes[:end_code])
|
|
39
|
+
@name = attributes[:name].to_s
|
|
40
|
+
@description = attributes[:description].to_s
|
|
41
|
+
@reserved = attributes[:reserved] == true
|
|
42
|
+
|
|
43
|
+
validate!
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns whether the given code falls within this range
|
|
47
|
+
#
|
|
48
|
+
# @param mcc [String, Integer, Code] the code to check
|
|
49
|
+
# @return [Boolean] true if the code is within the range
|
|
50
|
+
def include?(mcc)
|
|
51
|
+
code = mcc.respond_to?(:mcc) ? mcc.mcc : mcc
|
|
52
|
+
normalized = normalize_code(code)
|
|
53
|
+
normalized.between?(start_code, end_code)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
alias cover? include?
|
|
57
|
+
|
|
58
|
+
# Returns whether this range is reserved
|
|
59
|
+
#
|
|
60
|
+
# @return [Boolean] true if reserved
|
|
61
|
+
def reserved?
|
|
62
|
+
@reserved == true
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Returns the number of codes in this range
|
|
66
|
+
#
|
|
67
|
+
# @return [Integer] the count of codes
|
|
68
|
+
def size
|
|
69
|
+
end_code.to_i - start_code.to_i + 1
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
alias count size
|
|
73
|
+
alias length size
|
|
74
|
+
|
|
75
|
+
# Returns all codes in this range as an array of strings
|
|
76
|
+
#
|
|
77
|
+
# @return [Array<String>] all codes in the range
|
|
78
|
+
def to_a
|
|
79
|
+
(start_code.to_i..end_code.to_i).map { |n| n.to_s.rjust(4, "0") }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Iterates over each code in the range
|
|
83
|
+
#
|
|
84
|
+
# @yield [String] each code in the range
|
|
85
|
+
# @return [Enumerator] if no block given
|
|
86
|
+
def each(&block)
|
|
87
|
+
return to_enum(:each) unless block_given?
|
|
88
|
+
|
|
89
|
+
to_a.each(&block)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Returns whether this range equals another
|
|
93
|
+
#
|
|
94
|
+
# @param other [Range] the range to compare
|
|
95
|
+
# @return [Boolean] true if the ranges are equal
|
|
96
|
+
def ==(other)
|
|
97
|
+
return false unless other.is_a?(self.class)
|
|
98
|
+
|
|
99
|
+
start_code == other.start_code && end_code == other.end_code
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
alias eql? ==
|
|
103
|
+
|
|
104
|
+
# Returns a hash code for this instance
|
|
105
|
+
#
|
|
106
|
+
# @return [Integer] the hash code
|
|
107
|
+
def hash
|
|
108
|
+
[start_code, end_code].hash
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Returns a human-readable representation
|
|
112
|
+
#
|
|
113
|
+
# @return [String] the inspection string
|
|
114
|
+
def inspect
|
|
115
|
+
"#<#{self.class.name} #{start_code}..#{end_code} name=#{name.inspect} reserved=#{reserved?}>"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Returns the range as a string
|
|
119
|
+
#
|
|
120
|
+
# @return [String] the range representation
|
|
121
|
+
def to_s
|
|
122
|
+
"#{start_code}-#{end_code}"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Returns a hash representation
|
|
126
|
+
#
|
|
127
|
+
# @return [Hash] the range as a hash
|
|
128
|
+
def to_h
|
|
129
|
+
{
|
|
130
|
+
start_code: start_code,
|
|
131
|
+
end_code: end_code,
|
|
132
|
+
name: name,
|
|
133
|
+
description: description,
|
|
134
|
+
reserved: reserved,
|
|
135
|
+
}
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
private
|
|
139
|
+
|
|
140
|
+
# Validates that the range is valid
|
|
141
|
+
#
|
|
142
|
+
# @raise [InvalidRange] if the range is invalid
|
|
143
|
+
def validate!
|
|
144
|
+
return unless start_code.to_i > end_code.to_i
|
|
145
|
+
|
|
146
|
+
raise InvalidRange, "Start code (#{start_code}) cannot be greater than end code (#{end_code})"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Normalizes a code value to a 4-digit string
|
|
150
|
+
#
|
|
151
|
+
# @param value [String, Integer] the value to normalize
|
|
152
|
+
# @return [String] the normalized 4-digit string
|
|
153
|
+
def normalize_code(value)
|
|
154
|
+
value.to_s.strip.rjust(4, "0")
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|