fiscalrail 0.5.0 → 0.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 +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +30 -1
- data/lib/fiscalrail/generated/contract.rb +189 -1
- data/lib/fiscalrail/generated/models.rb +34 -0
- data/lib/fiscalrail/resource.rb +2 -2
- data/lib/fiscalrail/resources/accounts.rb +24 -0
- data/lib/fiscalrail/transport.rb +13 -1
- data/lib/fiscalrail/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: 686707319e3f84edc7570df96ecde4325051ced614c1d7afb0706fb490730fbe
|
|
4
|
+
data.tar.gz: 9b72d4865f113b5d9e1d18668a390ec8d6900b1ab05d06ca9ef12cf933a47c90
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7b72ea35beff00c975ccb4dcb1f4953b56805cd64b330dee8cd4d39086158043574a4f10e51d28eac3639bea26cde7dbd0bfdcf068cbf66a8bd4d1838e5b4836
|
|
7
|
+
data.tar.gz: aae2526ccbe70ba3872c6859861cb972f743e72b1fc653fd28006d8236b49275583f48651e034fae59f6dbd109e36e841fec16d842efb0d8770dfd88dc9e0d04
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
- Add ES-scoped issuer certificate file uploads, representation verification,
|
|
6
|
+
submission-verification retries and pending-change cancellation.
|
|
7
|
+
- Expose active submission readiness and pending verification results from the
|
|
8
|
+
deployed API contract (47 operations).
|
|
9
|
+
- Keep certificate uploads as native multipart requests without automatic retries.
|
|
10
|
+
|
|
11
|
+
|
|
3
12
|
## 0.5.0 — 2026-09-28
|
|
4
13
|
|
|
5
14
|
- Match the deployed current-account API routes and split invoicing settings into a dedicated resource.
|
data/README.md
CHANGED
|
@@ -5,7 +5,7 @@ A Ruby client for issuing immutable invoices through FiscalRail. Ruby 3.3 or lat
|
|
|
5
5
|
Install with Bundler:
|
|
6
6
|
|
|
7
7
|
```ruby
|
|
8
|
-
gem "fiscalrail", "~> 0.
|
|
8
|
+
gem "fiscalrail", "~> 0.6.0"
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Issue an invoice
|
|
@@ -230,3 +230,32 @@ FISCALRAIL_APP_ROOT="$PWD" bundle exec ruby /absolute/path/to/ruby/test/rails_in
|
|
|
230
230
|
It creates a Test account inside a test transaction and checks customer creation, null clearing, payment defaults, issuance/replay, pagination, PDF download and amendment. Set `FISCALRAIL_SDK_PDF=/tmp/sdk-invoice.pdf` to retain the rendered PDF for inspection. This test is optional and is not part of the standalone gem CI.
|
|
231
231
|
|
|
232
232
|
See [RELEASING.md](RELEASING.md) for the release checklist.
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
## Spanish AEAT submission
|
|
236
|
+
|
|
237
|
+
Use a Live Spanish account key. Upload a `.p12`/`.pfx` file (up to 128 KiB),
|
|
238
|
+
including its private key, using native multipart upload. Omit the password for
|
|
239
|
+
an unprotected bundle. The certificate's issuer NIF must match the account.
|
|
240
|
+
|
|
241
|
+
```ruby
|
|
242
|
+
File.open("issuer.p12", "rb") do |certificate|
|
|
243
|
+
setup = client.account_tax_regimes.es.upload_certificate(
|
|
244
|
+
certificate_file: certificate,
|
|
245
|
+
certificate_password: ENV.fetch("CERTIFICATE_PASSWORD")
|
|
246
|
+
)
|
|
247
|
+
end
|
|
248
|
+
setup = client.account_tax_regimes.retrieve
|
|
249
|
+
# Inspect setup.es.pending_submission.status / error_code and setup.es.submission.ready.
|
|
250
|
+
client.account_tax_regimes.es.verify_submission # retry the pending or active check
|
|
251
|
+
client.account_tax_regimes.es.cancel_submission_change
|
|
252
|
+
client.account_tax_regimes.es.verify_representation # after granting AEAT authority
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Each mutation above is a separate operation; choose the one needed. Upload and
|
|
256
|
+
verification return the account setup while AEAT checks run asynchronously.
|
|
257
|
+
Poll the generic account tax-regime resource for pending verification status,
|
|
258
|
+
error code and the active setup's readiness. A working setup remains active until
|
|
259
|
+
a replacement verifies; failed checks retain the pending certificate for retry.
|
|
260
|
+
Cancelling removes only the pending change. Uploads are not automatically retried.
|
|
261
|
+
The ES mutations use `/account/tax-regime/es/...`; reads use `/account/tax-regime`.
|
|
@@ -2365,6 +2365,49 @@ module FiscalRail
|
|
|
2365
2365
|
],
|
|
2366
2366
|
"type": "object"
|
|
2367
2367
|
},
|
|
2368
|
+
"SpanishAccountSubmission": {
|
|
2369
|
+
"model": "SpanishAccountSubmission",
|
|
2370
|
+
"properties": {
|
|
2371
|
+
"certificate_expires_at": {
|
|
2372
|
+
"format": "date-time",
|
|
2373
|
+
"type": [
|
|
2374
|
+
"string",
|
|
2375
|
+
"null"
|
|
2376
|
+
]
|
|
2377
|
+
},
|
|
2378
|
+
"error_code": {
|
|
2379
|
+
"type": [
|
|
2380
|
+
"string",
|
|
2381
|
+
"null"
|
|
2382
|
+
]
|
|
2383
|
+
},
|
|
2384
|
+
"kind": {
|
|
2385
|
+
"type": "string"
|
|
2386
|
+
},
|
|
2387
|
+
"last_checked_at": {
|
|
2388
|
+
"format": "date-time",
|
|
2389
|
+
"type": [
|
|
2390
|
+
"string",
|
|
2391
|
+
"null"
|
|
2392
|
+
]
|
|
2393
|
+
},
|
|
2394
|
+
"ready": {
|
|
2395
|
+
"type": "boolean"
|
|
2396
|
+
},
|
|
2397
|
+
"status": {
|
|
2398
|
+
"type": "string"
|
|
2399
|
+
}
|
|
2400
|
+
},
|
|
2401
|
+
"required": [
|
|
2402
|
+
"kind",
|
|
2403
|
+
"ready",
|
|
2404
|
+
"certificate_expires_at",
|
|
2405
|
+
"status",
|
|
2406
|
+
"error_code",
|
|
2407
|
+
"last_checked_at"
|
|
2408
|
+
],
|
|
2409
|
+
"type": "object"
|
|
2410
|
+
},
|
|
2368
2411
|
"SpanishAccountTaxRegime": {
|
|
2369
2412
|
"model": "SpanishAccountTaxRegime",
|
|
2370
2413
|
"properties": {
|
|
@@ -2394,6 +2437,16 @@ module FiscalRail
|
|
|
2394
2437
|
"SpanishAccountTaxRegimeDetails": {
|
|
2395
2438
|
"model": "SpanishAccountTaxRegimeDetails",
|
|
2396
2439
|
"properties": {
|
|
2440
|
+
"pending_submission": {
|
|
2441
|
+
"oneOf": [
|
|
2442
|
+
{
|
|
2443
|
+
"$ref": "#/components/schemas/SpanishPendingSubmission"
|
|
2444
|
+
},
|
|
2445
|
+
{
|
|
2446
|
+
"type": "null"
|
|
2447
|
+
}
|
|
2448
|
+
]
|
|
2449
|
+
},
|
|
2397
2450
|
"representation": {
|
|
2398
2451
|
"oneOf": [
|
|
2399
2452
|
{
|
|
@@ -2403,10 +2456,22 @@ module FiscalRail
|
|
|
2403
2456
|
"type": "null"
|
|
2404
2457
|
}
|
|
2405
2458
|
]
|
|
2459
|
+
},
|
|
2460
|
+
"submission": {
|
|
2461
|
+
"oneOf": [
|
|
2462
|
+
{
|
|
2463
|
+
"$ref": "#/components/schemas/SpanishAccountSubmission"
|
|
2464
|
+
},
|
|
2465
|
+
{
|
|
2466
|
+
"type": "null"
|
|
2467
|
+
}
|
|
2468
|
+
]
|
|
2406
2469
|
}
|
|
2407
2470
|
},
|
|
2408
2471
|
"required": [
|
|
2409
|
-
"representation"
|
|
2472
|
+
"representation",
|
|
2473
|
+
"submission",
|
|
2474
|
+
"pending_submission"
|
|
2410
2475
|
],
|
|
2411
2476
|
"type": "object"
|
|
2412
2477
|
},
|
|
@@ -2460,6 +2525,89 @@ module FiscalRail
|
|
|
2460
2525
|
],
|
|
2461
2526
|
"type": "object"
|
|
2462
2527
|
},
|
|
2528
|
+
"SpanishPendingSubmission": {
|
|
2529
|
+
"model": "SpanishPendingSubmission",
|
|
2530
|
+
"properties": {
|
|
2531
|
+
"certificate_expires_at": {
|
|
2532
|
+
"format": "date-time",
|
|
2533
|
+
"type": [
|
|
2534
|
+
"string",
|
|
2535
|
+
"null"
|
|
2536
|
+
]
|
|
2537
|
+
},
|
|
2538
|
+
"error_code": {
|
|
2539
|
+
"type": [
|
|
2540
|
+
"string",
|
|
2541
|
+
"null"
|
|
2542
|
+
]
|
|
2543
|
+
},
|
|
2544
|
+
"kind": {
|
|
2545
|
+
"type": "string"
|
|
2546
|
+
},
|
|
2547
|
+
"last_checked_at": {
|
|
2548
|
+
"format": "date-time",
|
|
2549
|
+
"type": [
|
|
2550
|
+
"string",
|
|
2551
|
+
"null"
|
|
2552
|
+
]
|
|
2553
|
+
},
|
|
2554
|
+
"status": {
|
|
2555
|
+
"type": "string"
|
|
2556
|
+
}
|
|
2557
|
+
},
|
|
2558
|
+
"required": [
|
|
2559
|
+
"kind",
|
|
2560
|
+
"status",
|
|
2561
|
+
"error_code",
|
|
2562
|
+
"last_checked_at",
|
|
2563
|
+
"certificate_expires_at"
|
|
2564
|
+
],
|
|
2565
|
+
"type": "object"
|
|
2566
|
+
},
|
|
2567
|
+
"SubmissionConfigurationErrorResponse": {
|
|
2568
|
+
"model": "SubmissionConfigurationErrorResponse",
|
|
2569
|
+
"properties": {
|
|
2570
|
+
"error": {
|
|
2571
|
+
"model": "SubmissionConfigurationError",
|
|
2572
|
+
"properties": {
|
|
2573
|
+
"code": {
|
|
2574
|
+
"type": "string"
|
|
2575
|
+
},
|
|
2576
|
+
"details": {
|
|
2577
|
+
"items": {
|
|
2578
|
+
"model": "SubmissionConfigurationValidationDetail",
|
|
2579
|
+
"properties": {
|
|
2580
|
+
"field": {
|
|
2581
|
+
"type": "string"
|
|
2582
|
+
},
|
|
2583
|
+
"message": {
|
|
2584
|
+
"type": "string"
|
|
2585
|
+
}
|
|
2586
|
+
},
|
|
2587
|
+
"required": [
|
|
2588
|
+
"field",
|
|
2589
|
+
"message"
|
|
2590
|
+
],
|
|
2591
|
+
"type": "object"
|
|
2592
|
+
},
|
|
2593
|
+
"type": "array"
|
|
2594
|
+
},
|
|
2595
|
+
"message": {
|
|
2596
|
+
"type": "string"
|
|
2597
|
+
}
|
|
2598
|
+
},
|
|
2599
|
+
"required": [
|
|
2600
|
+
"code",
|
|
2601
|
+
"message"
|
|
2602
|
+
],
|
|
2603
|
+
"type": "object"
|
|
2604
|
+
}
|
|
2605
|
+
},
|
|
2606
|
+
"required": [
|
|
2607
|
+
"error"
|
|
2608
|
+
],
|
|
2609
|
+
"type": "object"
|
|
2610
|
+
},
|
|
2463
2611
|
"TaxId": {
|
|
2464
2612
|
"model": "TaxId",
|
|
2465
2613
|
"properties": {
|
|
@@ -2914,6 +3062,16 @@ module FiscalRail
|
|
|
2914
3062
|
}
|
|
2915
3063
|
}
|
|
2916
3064
|
},
|
|
3065
|
+
"cancelAccountSubmissionChange": {
|
|
3066
|
+
"method": "DELETE",
|
|
3067
|
+
"path": "/account/tax-regime/es/submission/pending",
|
|
3068
|
+
"parameters": [],
|
|
3069
|
+
"responses": {
|
|
3070
|
+
"200": {
|
|
3071
|
+
"$ref": "#/components/schemas/AccountTaxRegime"
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
},
|
|
2917
3075
|
"createApiKey": {
|
|
2918
3076
|
"method": "POST",
|
|
2919
3077
|
"path": "/api-keys",
|
|
@@ -3587,6 +3745,36 @@ module FiscalRail
|
|
|
3587
3745
|
"$ref": "#/components/schemas/PaymentInstruction"
|
|
3588
3746
|
}
|
|
3589
3747
|
}
|
|
3748
|
+
},
|
|
3749
|
+
"uploadAccountCertificate": {
|
|
3750
|
+
"method": "POST",
|
|
3751
|
+
"path": "/account/tax-regime/es/certificate",
|
|
3752
|
+
"parameters": [],
|
|
3753
|
+
"responses": {
|
|
3754
|
+
"202": {
|
|
3755
|
+
"$ref": "#/components/schemas/AccountTaxRegime"
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
},
|
|
3759
|
+
"verifyAccountRepresentation": {
|
|
3760
|
+
"method": "POST",
|
|
3761
|
+
"path": "/account/tax-regime/es/representation/verify",
|
|
3762
|
+
"parameters": [],
|
|
3763
|
+
"responses": {
|
|
3764
|
+
"202": {
|
|
3765
|
+
"$ref": "#/components/schemas/AccountTaxRegime"
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3768
|
+
},
|
|
3769
|
+
"verifyAccountSubmission": {
|
|
3770
|
+
"method": "POST",
|
|
3771
|
+
"path": "/account/tax-regime/es/submission/verify",
|
|
3772
|
+
"parameters": [],
|
|
3773
|
+
"responses": {
|
|
3774
|
+
"202": {
|
|
3775
|
+
"$ref": "#/components/schemas/AccountTaxRegime"
|
|
3776
|
+
}
|
|
3777
|
+
}
|
|
3590
3778
|
}
|
|
3591
3779
|
}
|
|
3592
3780
|
}
|
|
@@ -593,6 +593,15 @@ module FiscalRail
|
|
|
593
593
|
def verified_at = self["verified_at"]
|
|
594
594
|
end
|
|
595
595
|
|
|
596
|
+
class SpanishAccountSubmission < Model
|
|
597
|
+
def certificate_expires_at = self["certificate_expires_at"]
|
|
598
|
+
def error_code = self["error_code"]
|
|
599
|
+
def kind = self["kind"]
|
|
600
|
+
def last_checked_at = self["last_checked_at"]
|
|
601
|
+
def ready = self["ready"]
|
|
602
|
+
def status = self["status"]
|
|
603
|
+
end
|
|
604
|
+
|
|
596
605
|
class SpanishAccountTaxRegime < Model
|
|
597
606
|
def account = self["account"]
|
|
598
607
|
def es = self["es"]
|
|
@@ -601,7 +610,9 @@ module FiscalRail
|
|
|
601
610
|
end
|
|
602
611
|
|
|
603
612
|
class SpanishAccountTaxRegimeDetails < Model
|
|
613
|
+
def pending_submission = self["pending_submission"]
|
|
604
614
|
def representation = self["representation"]
|
|
615
|
+
def submission = self["submission"]
|
|
605
616
|
end
|
|
606
617
|
|
|
607
618
|
class SpanishInvoiceQr < Model
|
|
@@ -619,6 +630,29 @@ module FiscalRail
|
|
|
619
630
|
def verifactu = self["verifactu"]
|
|
620
631
|
end
|
|
621
632
|
|
|
633
|
+
class SpanishPendingSubmission < Model
|
|
634
|
+
def certificate_expires_at = self["certificate_expires_at"]
|
|
635
|
+
def error_code = self["error_code"]
|
|
636
|
+
def kind = self["kind"]
|
|
637
|
+
def last_checked_at = self["last_checked_at"]
|
|
638
|
+
def status = self["status"]
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
class SubmissionConfigurationError < Model
|
|
642
|
+
def code = self["code"]
|
|
643
|
+
def details = self["details"]
|
|
644
|
+
def message = self["message"]
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
class SubmissionConfigurationErrorResponse < Model
|
|
648
|
+
def error = self["error"]
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
class SubmissionConfigurationValidationDetail < Model
|
|
652
|
+
def field = self["field"]
|
|
653
|
+
def message = self["message"]
|
|
654
|
+
end
|
|
655
|
+
|
|
622
656
|
class TaxId < Model
|
|
623
657
|
def country = self["country"]
|
|
624
658
|
def id = self["id"]
|
data/lib/fiscalrail/resource.rb
CHANGED
|
@@ -10,7 +10,7 @@ module FiscalRail
|
|
|
10
10
|
|
|
11
11
|
private
|
|
12
12
|
|
|
13
|
-
def request(operation_id, path: {}, params: {}, body: nil, retry_safe: false, idempotency_key: nil, headers: {}, binary: false)
|
|
13
|
+
def request(operation_id, path: {}, params: {}, body: nil, multipart: nil, retry_safe: false, idempotency_key: nil, headers: {}, binary: false)
|
|
14
14
|
operation = Generated::OPERATIONS.fetch(operation_id)
|
|
15
15
|
route = operation.fetch("path").gsub(/\{([^}]+)\}/) do
|
|
16
16
|
value = path.fetch(Regexp.last_match(1).to_sym)
|
|
@@ -20,7 +20,7 @@ module FiscalRail
|
|
|
20
20
|
end
|
|
21
21
|
headers = headers.merge("Accept" => "application/pdf") if binary
|
|
22
22
|
response = @transport.request(method: operation.fetch("method"), path: route, params: params,
|
|
23
|
-
body: body, retry_safe: retry_safe, idempotency_key: idempotency_key, headers: headers)
|
|
23
|
+
body: body, multipart: multipart, retry_safe: retry_safe, idempotency_key: idempotency_key, headers: headers)
|
|
24
24
|
metadata = { request_id: response.headers["request-id"], idempotent_replayed: response.headers["idempotent-replayed"], idempotency_key: idempotency_key }
|
|
25
25
|
unless operation.fetch("responses").key?(response.status.to_s)
|
|
26
26
|
raise ResponseParseError.new("unexpected HTTP #{response.status}", model: operation_id, field: "$", **metadata.slice(:request_id, :idempotency_key))
|
|
@@ -29,9 +29,33 @@ module FiscalRail
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
class AccountTaxRegimes < Resource
|
|
32
|
+
def es
|
|
33
|
+
@es ||= SpanishSubmission.new(@transport)
|
|
34
|
+
end
|
|
35
|
+
|
|
32
36
|
def retrieve
|
|
33
37
|
request("retrieveAccountTaxRegime", retry_safe: true)
|
|
34
38
|
end
|
|
35
39
|
end
|
|
40
|
+
class SpanishSubmission < Resource
|
|
41
|
+
def upload_certificate(certificate_file:, certificate_password: nil)
|
|
42
|
+
content = certificate_file.read(128 * 1024 + 1) || ""
|
|
43
|
+
raise ArgumentError, "certificate_file must be at most 128 KiB" if content.bytesize > 128 * 1024
|
|
44
|
+
|
|
45
|
+
request("uploadAccountCertificate", multipart: { certificate_file: content, certificate_password: certificate_password })
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def verify_representation
|
|
49
|
+
request("verifyAccountRepresentation")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def verify_submission
|
|
53
|
+
request("verifyAccountSubmission")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def cancel_submission_change
|
|
57
|
+
request("cancelAccountSubmissionChange")
|
|
58
|
+
end
|
|
59
|
+
end
|
|
36
60
|
end
|
|
37
61
|
end
|
data/lib/fiscalrail/transport.rb
CHANGED
|
@@ -4,6 +4,7 @@ require "net/http"
|
|
|
4
4
|
require "json"
|
|
5
5
|
require "uri"
|
|
6
6
|
require "thread"
|
|
7
|
+
require "securerandom"
|
|
7
8
|
|
|
8
9
|
module FiscalRail
|
|
9
10
|
# The adapter boundary also makes custom proxy/TLS/instrumentation possible.
|
|
@@ -63,7 +64,7 @@ module FiscalRail
|
|
|
63
64
|
@api_key, @base_url, @max_retries, @adapter, @sleeper = api_key, base_url.sub(%r{/+\z}, ""), max_retries, adapter, sleeper
|
|
64
65
|
end
|
|
65
66
|
|
|
66
|
-
def request(method:, path:, body: nil, params: {}, headers: {}, retry_safe:, idempotency_key: nil)
|
|
67
|
+
def request(method:, path:, body: nil, multipart: nil, params: {}, headers: {}, retry_safe:, idempotency_key: nil)
|
|
67
68
|
uri = URI("#{@base_url}#{path}")
|
|
68
69
|
query = Serialization.json_value(params.reject { |_, value| value.nil? })
|
|
69
70
|
uri.query = URI.encode_www_form(query) unless query.empty?
|
|
@@ -74,6 +75,17 @@ module FiscalRail
|
|
|
74
75
|
request_headers["Idempotency-Key"] = idempotency_key if idempotency_key
|
|
75
76
|
request_headers["Content-Type"] = "application/json" unless body.nil?
|
|
76
77
|
encoded = body.nil? ? nil : JSON.generate(Serialization.json_value(body))
|
|
78
|
+
if multipart
|
|
79
|
+
boundary = "fiscalrail-#{SecureRandom.hex(24)}"
|
|
80
|
+
request_headers["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
|
|
81
|
+
encoded = "--#{boundary}\r\nContent-Disposition: form-data; name=\"certificate_file\"; filename=\"certificate.p12\"\r\nContent-Type: application/x-pkcs12\r\n\r\n".b
|
|
82
|
+
encoded << multipart.fetch(:certificate_file).b << "\r\n".b
|
|
83
|
+
unless multipart[:certificate_password].nil?
|
|
84
|
+
encoded << "--#{boundary}\r\nContent-Disposition: form-data; name=\"certificate_password\"\r\n\r\n".b
|
|
85
|
+
encoded << multipart.fetch(:certificate_password).b << "\r\n".b
|
|
86
|
+
end
|
|
87
|
+
encoded << "--#{boundary}--\r\n".b
|
|
88
|
+
end
|
|
77
89
|
attempt = 0
|
|
78
90
|
loop do
|
|
79
91
|
begin
|
data/lib/fiscalrail/version.rb
CHANGED