tracking_number 2.3.0 → 2.4.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 +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/data/couriers/dhl.json +74 -0
- data/lib/data/couriers/fedex.json +2 -4
- data/lib/data/couriers/usps.json +96 -1
- data/lib/tracking_number/base.rb +17 -15
- data/lib/tracking_number/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c0ef2fa722ce7a2d9cc6cfaac9c5510ef7ac79074ba4e227f9554b8157da2ee
|
4
|
+
data.tar.gz: 3a5f46d4dc5027e8bf68c4f7cf0756851e284d29b499c38d4c264b57ebc61fc4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 404a19a4f9847ade5581c5ff7c0cf950fde208d773f81f6882715d44b4395f94fc505538d46b718ad0c7fbfcdf152e512619ca86372dc1021a524ab2614cd898
|
7
|
+
data.tar.gz: c4fbe1cf3637fea233106008bc31c1b555a63ea7e04588f08446d00a5d6dd3948daf744e078a74c6e96d7f257c51986fa8712db5f3b9e1e742e0ea9d61a6c63c
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
tracking_number changelog
|
2
2
|
|
3
|
+
# [2.4.0](https://github.com/jkeen/tracking_number/compare/v2.3.0...v2.4.0) (2025-08-21)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* update to tracking_number_data 1.9.0 ([f885bfd](https://github.com/jkeen/tracking_number/commit/f885bfd956ffacb22f38967754ec14551bca8d50))
|
9
|
+
|
3
10
|
# [2.3.0](https://github.com/jkeen/tracking_number/compare/v2.2.0...v2.3.0) (2025-08-21)
|
4
11
|
|
5
12
|
|
data/lib/data/couriers/dhl.json
CHANGED
@@ -89,6 +89,80 @@
|
|
89
89
|
"GR295117494011169045"
|
90
90
|
]
|
91
91
|
}
|
92
|
+
},
|
93
|
+
{
|
94
|
+
"name": "DHL E-Commerce (30)",
|
95
|
+
"id": "dhl_ecommerce_30",
|
96
|
+
"regex": [
|
97
|
+
"\\s*(?<RoutingApplicationId>4\\s*2\\s*0\\s*)(?<DestinationZip>([0-9]\\s*){5})",
|
98
|
+
"(?!\\s*9\\s*[1-5]\\b)",
|
99
|
+
"(?<SerialNumber>",
|
100
|
+
"(?<ServiceType>(9[2-5]\\s*))",
|
101
|
+
"(?<ShipperId>([0-9]\\s*){9})",
|
102
|
+
"(?<PackageId>([0-9]\\s*){10})",
|
103
|
+
")",
|
104
|
+
"(?<CheckDigit>[0-9]\\s*)"
|
105
|
+
],
|
106
|
+
"validation": {
|
107
|
+
"checksum": {
|
108
|
+
"name": "mod10",
|
109
|
+
"evens_multiplier": 3,
|
110
|
+
"odds_multiplier": 1,
|
111
|
+
"reverse": true
|
112
|
+
}
|
113
|
+
},
|
114
|
+
"tracking_url": "https://ecommerceportal.dhl.com/track?trackingnumber=%s",
|
115
|
+
"partners": [{
|
116
|
+
"description": "DHL eCommerce hands off to USPS for the last mile",
|
117
|
+
"partner_type": "carrier",
|
118
|
+
"partner_id": "usps_22",
|
119
|
+
"validation": {
|
120
|
+
"matches_all": [
|
121
|
+
{ "regex_group_name": "RoutingApplicationId", "matches": "420" },
|
122
|
+
{ "regex_group_name": "ServiceType", "matches_regex": "9[2345]" }
|
123
|
+
]
|
124
|
+
}
|
125
|
+
},
|
126
|
+
{
|
127
|
+
"description": "DHL eCommerce hands off to USPS for the last mile",
|
128
|
+
"partner_type": "carrier",
|
129
|
+
"partner_id": "usps_91",
|
130
|
+
"validation": {
|
131
|
+
"matches_all": [
|
132
|
+
{ "regex_group_name": "RoutingApplicationId", "matches": "420" },
|
133
|
+
{ "regex_group_name": "ServiceType", "matches_regex": "9[2345]" }
|
134
|
+
]
|
135
|
+
}
|
136
|
+
}],
|
137
|
+
"additional": [
|
138
|
+
{
|
139
|
+
"name": "Service Type",
|
140
|
+
"regex_group_name": "ServiceType",
|
141
|
+
"lookup": [
|
142
|
+
{ "matches": "92", "name": "USPS Tracking (Commercial)" },
|
143
|
+
{ "matches": "93", "name": "Collect on Delivery (COD)" },
|
144
|
+
{ "matches": "94", "name": "USPS Tracking" },
|
145
|
+
{ "matches": "95", "name": "Certified Mail" }
|
146
|
+
]
|
147
|
+
}
|
148
|
+
],
|
149
|
+
"test_numbers": {
|
150
|
+
"valid": [
|
151
|
+
"420902459261290336128704042634",
|
152
|
+
"420941179261290336128704062441",
|
153
|
+
"420926029261290336128704067248",
|
154
|
+
"420902729261290336128704124163",
|
155
|
+
"420950549261290336128704133837",
|
156
|
+
"420193809261290336128704280838",
|
157
|
+
"420900469261290336128704216936"
|
158
|
+
],
|
159
|
+
"invalid": [
|
160
|
+
"420941179261290336128704062442",
|
161
|
+
"420941179261290336128704062400",
|
162
|
+
"420941179261290336128704062422"
|
163
|
+
]
|
164
|
+
}
|
92
165
|
}
|
166
|
+
|
93
167
|
]
|
94
168
|
}
|
@@ -98,7 +98,7 @@
|
|
98
98
|
"(?<ApplicationIdentifier>9\\s*2\\s*)",
|
99
99
|
")?",
|
100
100
|
"(?<SerialNumber>",
|
101
|
-
"(?<SCNC>
|
101
|
+
"(?<SCNC>6\\s*1\\s*)",
|
102
102
|
"(?<ServiceType>2\\s*9\\s*)",
|
103
103
|
"(?<ShipperId>([0-9]\\s*){8})",
|
104
104
|
"(?<PackageId>([0-9]\\s*){11}|([0-9]\\s*){7})",
|
@@ -138,11 +138,9 @@
|
|
138
138
|
"tracking_url": "https://www.fedex.com/apps/fedextrack/?tracknumbers=%s",
|
139
139
|
"test_numbers": {
|
140
140
|
"valid": [
|
141
|
-
"61299998820821171811",
|
142
141
|
"9261292700768711948021",
|
143
142
|
"420 11213 92 6129098349792366623 8",
|
144
|
-
"92 6129098349792366623 8"
|
145
|
-
"6129098349792366623 8"
|
143
|
+
"92 6129098349792366623 8"
|
146
144
|
],
|
147
145
|
"invalid": [
|
148
146
|
"9261292700768711948020",
|
data/lib/data/couriers/usps.json
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
"courier_code": "usps",
|
4
4
|
"tracking_numbers": [
|
5
5
|
{
|
6
|
-
"tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=%s",
|
7
6
|
"name": "USPS 20",
|
8
7
|
"id": "usps_20",
|
9
8
|
"description": "20 digit USPS numbers",
|
9
|
+
"tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=%s",
|
10
10
|
"regex": [
|
11
11
|
"\\s*(?<SerialNumber>",
|
12
12
|
"(?<ServiceType>([0-9]\\s*){2})",
|
@@ -57,6 +57,76 @@
|
|
57
57
|
}
|
58
58
|
]
|
59
59
|
},
|
60
|
+
{
|
61
|
+
"name": "USPS 22",
|
62
|
+
"id": "usps_22",
|
63
|
+
"description": "22 digit USPS numbers",
|
64
|
+
"tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=%s",
|
65
|
+
"regex": [
|
66
|
+
"\\s*((?<RoutingApplicationId>4\\s*2\\s*0\\s*)(?<DestinationZip>([0-9]\\s*){5}))?",
|
67
|
+
"(?<SerialNumber>",
|
68
|
+
"(?<ServiceType>(9\\s*[4-8]\\s*))",
|
69
|
+
"(?<ShipperId>([0-9]\\s*){9})",
|
70
|
+
"(?<PackageId>([0-9]\\s*){10})",
|
71
|
+
")",
|
72
|
+
"(?<CheckDigit>[0-9]\\s*)"
|
73
|
+
],
|
74
|
+
"validation": {
|
75
|
+
"checksum": {
|
76
|
+
"name": "mod10",
|
77
|
+
"evens_multiplier": 3,
|
78
|
+
"odds_multiplier": 1,
|
79
|
+
"reverse": true
|
80
|
+
}
|
81
|
+
},
|
82
|
+
"test_numbers": {
|
83
|
+
"valid": [
|
84
|
+
"420787459400111206206406260787",
|
85
|
+
"9400111206206406260787",
|
86
|
+
"9434611206206406227577",
|
87
|
+
"9434611206206407667136",
|
88
|
+
"9400111206206407628746",
|
89
|
+
"9400111206206407628845"
|
90
|
+
],
|
91
|
+
"invalid": [
|
92
|
+
"9434611206206407667131",
|
93
|
+
"9434611306206407667222",
|
94
|
+
"2334611306206407667222"
|
95
|
+
]
|
96
|
+
},
|
97
|
+
"partners": [{
|
98
|
+
"description": "DHL ECommerce uses USPS for last mile delivery",
|
99
|
+
"partner_type": "shipper",
|
100
|
+
"partner_id": "dhl_ecommerce_30",
|
101
|
+
"validation": {
|
102
|
+
"matches_all": [
|
103
|
+
{
|
104
|
+
"regex_group_name": "RoutingApplicationId",
|
105
|
+
"matches": "420"
|
106
|
+
},
|
107
|
+
{
|
108
|
+
"matches_regex": "9[24]",
|
109
|
+
"regex_group_name": "ServiceType"
|
110
|
+
}
|
111
|
+
]
|
112
|
+
}
|
113
|
+
}],
|
114
|
+
"additional": [
|
115
|
+
{
|
116
|
+
"name": "Service Type",
|
117
|
+
"regex_group_name": "ServiceType",
|
118
|
+
"lookup": [
|
119
|
+
{ "matches": "92", "name": "Signature Confirmation" },
|
120
|
+
{ "matches": "93", "name": "Collect on Delivery (COD)" },
|
121
|
+
{ "matches": "94", "name": "USPS Tracking" },
|
122
|
+
{ "matches": "95", "name": "Certified Mail" },
|
123
|
+
{ "matches": "96", "name": "Insured Mail" },
|
124
|
+
{ "matches": "97", "name": "Registered Mail" },
|
125
|
+
{ "matches": "98", "name": "Return Receipt for Merchandise" }
|
126
|
+
]
|
127
|
+
}
|
128
|
+
]
|
129
|
+
},
|
60
130
|
{
|
61
131
|
"name": "USPS 34v2",
|
62
132
|
"id": "usps_32V2",
|
@@ -131,6 +201,31 @@
|
|
131
201
|
{
|
132
202
|
"matches": "61",
|
133
203
|
"regex_group_name": "SCNC"
|
204
|
+
},
|
205
|
+
{
|
206
|
+
"regex_group_name": "ApplicationIdentifier",
|
207
|
+
"matches": "92"
|
208
|
+
}
|
209
|
+
]
|
210
|
+
}
|
211
|
+
},
|
212
|
+
{
|
213
|
+
"description": "DHL uses USPS for last mile delivery, but not all USPS91 numbers are DHL Ecommerce",
|
214
|
+
"partner_type": "shipper",
|
215
|
+
"partner_id": "dhl_ecommerce_30",
|
216
|
+
"validation": {
|
217
|
+
"matches_all": [
|
218
|
+
{
|
219
|
+
"regex_group_name": "ServiceType",
|
220
|
+
"matches": "29"
|
221
|
+
},
|
222
|
+
{
|
223
|
+
"matches": "61",
|
224
|
+
"regex_group_name": "SCNC"
|
225
|
+
},
|
226
|
+
{
|
227
|
+
"matches": "420",
|
228
|
+
"regex_group_name": "RoutingApplicationId"
|
134
229
|
}
|
135
230
|
]
|
136
231
|
}
|
data/lib/tracking_number/base.rb
CHANGED
@@ -126,16 +126,16 @@ module TrackingNumber
|
|
126
126
|
|
127
127
|
def info
|
128
128
|
Info.new({
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
129
|
+
courier: courier_info,
|
130
|
+
service_type: service_type,
|
131
|
+
service_description: service_description,
|
132
|
+
destination_zip: destination_zip,
|
133
|
+
shipper_id: shipper_id,
|
134
|
+
package_type: package_type,
|
135
|
+
tracking_url: tracking_url,
|
136
|
+
partners: partners,
|
137
|
+
decode: decode
|
138
|
+
})
|
139
139
|
end
|
140
140
|
|
141
141
|
def courier_code
|
@@ -186,8 +186,7 @@ module TrackingNumber
|
|
186
186
|
partner_hash = {}
|
187
187
|
|
188
188
|
return unless (partner_tn = find_matching_partner)
|
189
|
-
|
190
|
-
possible_twin = partner_tn.send(:find_matching_partner)
|
189
|
+
possible_twin = partner_tn.send(:find_matching_partner, self.class.const_get("ID"))
|
191
190
|
|
192
191
|
if possible_twin.instance_of?(self.class) && possible_twin.tracking_number == tracking_number
|
193
192
|
partner_hash[partner_data[:partner_type].to_sym] = partner_tn
|
@@ -295,8 +294,12 @@ module TrackingNumber
|
|
295
294
|
nil
|
296
295
|
end
|
297
296
|
|
298
|
-
def find_matching_partner
|
299
|
-
partner_info =
|
297
|
+
def find_matching_partner(partner_id = nil)
|
298
|
+
partner_info = if partner_id
|
299
|
+
(self.class.const_get(:PARTNERS) || []).select { |info| info[:partner_id]&.to_sym == partner_id.to_sym }
|
300
|
+
else
|
301
|
+
self.class.const_get(:PARTNERS) || []
|
302
|
+
end
|
300
303
|
|
301
304
|
partner_info.each do |partner_data|
|
302
305
|
klass = find_tracking_class_by_id(partner_data[:partner_id])
|
@@ -304,7 +307,6 @@ module TrackingNumber
|
|
304
307
|
return false unless klass
|
305
308
|
|
306
309
|
tn = klass.new(tracking_number)
|
307
|
-
|
308
310
|
valid = if partner_data.dig(:validation, :matches_all)
|
309
311
|
tn.valid? && match_all(partner_data.dig(:validation, :matches_all))
|
310
312
|
elsif partner_data.dig(:validation, :matches_any)
|