einvoice 1.3 → 1.5.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/.coderabbit.yaml +14 -0
- data/.github/workflows/build.yml +10 -7
- data/.github/workflows/cron.yml +23 -10
- data/CHANGELOG.md +74 -0
- data/Gemfile +11 -4
- data/README.md +98 -10
- data/Rakefile +44 -6
- data/einvoice.gemspec +11 -6
- data/lib/einvoice/client.rb +9 -1
- data/lib/einvoice/configuration.rb +5 -2
- data/lib/einvoice/connection.rb +3 -2
- data/lib/einvoice/donation_unit_list.json +1313 -1078
- data/lib/einvoice/provider.rb +1 -2
- data/lib/einvoice/tradevan/model/issue_data.rb +2 -2
- data/lib/einvoice/tradevan/model/issue_item.rb +2 -2
- data/lib/einvoice/tradevan/model/void_data.rb +2 -2
- data/lib/einvoice/tradevan/provider.rb +9 -46
- data/lib/einvoice/tradevan/validator/issue_data_validator.rb +7 -7
- data/lib/einvoice/version.rb +1 -1
- data/lib/einvoice.rb +0 -1
- data/lib/faraday/response/decode_tradevan.rb +5 -6
- data/lib/faraday/response/parse_xml.rb +14 -0
- metadata +19 -45
- data/lib/einvoice/utils.rb +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0ce2293f378b646e5ae9ab94d5cce8b539a7dd441d8db03472ae3c6f4bbd9735
|
|
4
|
+
data.tar.gz: 0d8e775b71d10cb37f3892cc40bd8e46e1ce872721ec7cb1c0864807d6a5f24d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 233c9f4194869b5e61420c7b255f768befe0f09cb3f952f1c300c7d9b8e417d98053461f1b794cf5f7a9a7c4b4a428b38b99db0005e77429d9686bf3afad1bda
|
|
7
|
+
data.tar.gz: 11f5ba7e0132eb0dc9eb4d0fc16cd48252b950b3c189f2c45efa4757bfbc43936c3c97155692d2e3b989bf038e528e20f5ee023031817fed9ab0a3a7bbb564d7
|
data/.coderabbit.yaml
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
reviews:
|
|
2
|
+
profile: chill
|
|
3
|
+
request_changes_workflow: false
|
|
4
|
+
auto_review:
|
|
5
|
+
enabled: true
|
|
6
|
+
drafts: false
|
|
7
|
+
path_filters:
|
|
8
|
+
- "!lib/einvoice/donation_unit_list.json"
|
|
9
|
+
path_instructions:
|
|
10
|
+
- path: "lib/einvoice/tradevan/**"
|
|
11
|
+
instructions: >
|
|
12
|
+
This is legacy 1.x code kept for backward compatibility.
|
|
13
|
+
Do not suggest large-scale refactors or architecture changes here.
|
|
14
|
+
Focus only on correctness bugs and security issues.
|
data/.github/workflows/build.yml
CHANGED
|
@@ -2,9 +2,9 @@ name: build
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
|
-
branches: [
|
|
5
|
+
branches: [ 1-x-stable ]
|
|
6
6
|
pull_request:
|
|
7
|
-
branches: [
|
|
7
|
+
branches: [ 1-x-stable ]
|
|
8
8
|
|
|
9
9
|
permissions:
|
|
10
10
|
contents: read
|
|
@@ -16,7 +16,7 @@ jobs:
|
|
|
16
16
|
ruby-version: ['3.1', '3.2', '3.3', '3.4']
|
|
17
17
|
runs-on: ubuntu-latest
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
20
|
- name: Set up Ruby
|
|
21
21
|
uses: ruby/setup-ruby@v1
|
|
22
22
|
with:
|
|
@@ -30,7 +30,10 @@ jobs:
|
|
|
30
30
|
- name: Run tests
|
|
31
31
|
run: bundle exec rspec
|
|
32
32
|
|
|
33
|
-
- name:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
- name: Upload coverage to Codecov
|
|
34
|
+
if: matrix.ruby-version == '3.4'
|
|
35
|
+
uses: codecov/codecov-action@v5
|
|
36
|
+
with:
|
|
37
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
38
|
+
files: ./coverage/lcov.info
|
|
39
|
+
fail_ci_if_error: true
|
data/.github/workflows/cron.yml
CHANGED
|
@@ -2,17 +2,30 @@ name: Daily update
|
|
|
2
2
|
on:
|
|
3
3
|
schedule:
|
|
4
4
|
- cron: 0 0 * * *
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
|
|
5
10
|
jobs:
|
|
6
11
|
build:
|
|
7
|
-
runs-on: ubuntu-
|
|
12
|
+
runs-on: ubuntu-latest
|
|
8
13
|
steps:
|
|
9
|
-
- uses: actions/checkout@
|
|
10
|
-
- uses:
|
|
11
|
-
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: ruby/setup-ruby@v1
|
|
16
|
+
with:
|
|
17
|
+
ruby-version: '3.3'
|
|
18
|
+
bundler-cache: true
|
|
19
|
+
- name: Update donation unit list
|
|
20
|
+
run: bundle exec rake update_donation_unit
|
|
21
|
+
- name: Commit and push changes
|
|
12
22
|
run: |
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
23
|
+
if git diff --quiet; then
|
|
24
|
+
echo "Donation unit list is up to date"
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
git config user.name "github-actions[bot]"
|
|
28
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
29
|
+
git add lib/einvoice/donation_unit_list.json
|
|
30
|
+
git commit -m "Automated donation unit list update"
|
|
31
|
+
git push
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
|
+
|
|
8
|
+
## [1.5.0] - 2026-09-11
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- Tradevan `IssueData#payload` and `VoidData#payload` now exclude
|
|
12
|
+
`context_for_validation`. On Rails 8 this internal ivar was sent as a
|
|
13
|
+
business field once `valid?` had run, and Tradevan rejected the whole
|
|
14
|
+
request. Thanks @dlackty.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- **Ruby 3.1 or newer is now required.** CI covers 3.1 through 3.4.
|
|
18
|
+
- **Faraday 2 is now required** (`~> 2.1`); `faraday_middleware` is gone,
|
|
19
|
+
replaced by a built-in `Faraday::Response::ParseXml`. If you pin
|
|
20
|
+
`faraday` to 1.x, stay on 1.4.0.
|
|
21
|
+
- `Einvoice::Utils` and the `gyoku` dependency have been removed. Nothing
|
|
22
|
+
in the gem called them.
|
|
23
|
+
|
|
24
|
+
### Internal
|
|
25
|
+
- Added request-level Tradevan provider specs.
|
|
26
|
+
- CI runs on `1-x-stable`; the donation unit list task parses with `CSV`.
|
|
27
|
+
- README documents the allowance operations and 1.x maintenance mode.
|
|
28
|
+
|
|
29
|
+
## [1.4.0] - 2026-08-08
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
- **TLS certificate verification is now enabled by default.** Previously every
|
|
33
|
+
request was sent with `ssl: { verify: false }`, regardless of configuration.
|
|
34
|
+
If you were relying on that behavior (e.g. against an endpoint with an
|
|
35
|
+
incomplete certificate chain), set `config.ssl_verify = false` or pass
|
|
36
|
+
`ssl_verify: false` to `Provider.new` to restore the old behavior.
|
|
37
|
+
- `Client` now delegates to the provider via `public_send` instead of `send`,
|
|
38
|
+
and implements `respond_to_missing?`. Private provider methods (e.g.
|
|
39
|
+
`encrypt`, `connection`) are no longer reachable through `Client`.
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
- `TotalValidator` comparison was inverted and compared a `String` against an
|
|
43
|
+
`Integer`, so it never actually validated anything. It now correctly fails
|
|
44
|
+
when `total` doesn't match the sum of item totals.
|
|
45
|
+
- `AllowanceNumberValidator` and `IssueItem#invoiceTime`'s format regexp had
|
|
46
|
+
broken escape sequences (`\A` and `\d` collapsing to literal characters in a
|
|
47
|
+
double-quoted string), causing them to reject all valid input.
|
|
48
|
+
- `ItemListValidator` pushed directly onto `record.errors[:itemList]`, which
|
|
49
|
+
is deprecated in Rails 6.1 and removed in 7.0. It now uses `errors.add` and
|
|
50
|
+
actually registers errors again.
|
|
51
|
+
- Tradevan response decoding used `JSON.load`, which is unsafe for untrusted
|
|
52
|
+
input. Switched to `JSON.parse`.
|
|
53
|
+
- `lib/einvoice/donation_unit_list.json` was stale since 2023-12 (the
|
|
54
|
+
scheduled update workflow had been silently broken), causing
|
|
55
|
+
`DonationUnitValidator` to reject currently valid donation codes and accept
|
|
56
|
+
retired ones. The list has been refreshed (~340 entries changed).
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
- Specs for `Client` delegation, `Configuration#ssl_verify`,
|
|
60
|
+
`Provider#connection` SSL behavior, the validator fixes above, and the
|
|
61
|
+
previously-untested `decode_tradevan` middleware.
|
|
62
|
+
|
|
63
|
+
### Internal
|
|
64
|
+
- CI coverage reporting migrated from Code Climate (discontinued) to Codecov.
|
|
65
|
+
- The scheduled `cron.yml` workflow that refreshes the donation unit list
|
|
66
|
+
has been repaired — it depended on two archived GitHub Actions
|
|
67
|
+
(`actions/setup-ruby`, `mikeal/publish-to-github-action`) and hadn't run
|
|
68
|
+
successfully since 2023-12.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
Versions prior to 1.4.0 were not tracked in this file. See the
|
|
73
|
+
[release history](https://github.com/abookyun/einvoice/releases) and
|
|
74
|
+
[commit log](https://github.com/abookyun/einvoice/commits/main/) for earlier changes.
|
data/Gemfile
CHANGED
|
@@ -3,7 +3,14 @@ source 'https://rubygems.org'
|
|
|
3
3
|
# Specify your gem's dependencies in einvoice.gemspec
|
|
4
4
|
gemspec
|
|
5
5
|
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
gem "
|
|
6
|
+
# Remove this pin once we drop Ruby 3.1 support. json 3.0 dropped quirks_mode,
|
|
7
|
+
# which activesupport 7.2.3.2 still passes; 7.2.3.2 is the newest activesupport
|
|
8
|
+
# that works on Ruby 3.1.
|
|
9
|
+
gem "json", "< 3.0"
|
|
10
|
+
|
|
11
|
+
# Used by the update_donation_unit rake task; csv leaves the default gems in Ruby 3.4.
|
|
12
|
+
gem "csv", require: false, group: :development
|
|
13
|
+
|
|
14
|
+
gem "ostruct", require: false, group: :development
|
|
15
|
+
gem "simplecov", require: false, group: :test
|
|
16
|
+
gem "simplecov-lcov", require: false, group: :test
|
data/README.md
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
# Einvoice
|
|
2
2
|
[](https://github.com/abookyun/einvoice/actions/workflows/build.yml)
|
|
3
|
-
[](https://codecov.io/github/abookyun/einvoice)
|
|
4
|
+
|
|
5
|
+
> **The 1.x line is moving to maintenance mode.** A provider-agnostic 2.0
|
|
6
|
+
> rewrite is in progress on `main`; once it lands, 1.x continues on the
|
|
7
|
+
> [`1-x-stable`](https://github.com/abookyun/einvoice/tree/1-x-stable) branch.
|
|
8
|
+
> If you depend on the current Tradevan client, pin `~> 1.4`.
|
|
5
9
|
|
|
6
10
|
## What's E-Invoice
|
|
7
11
|
|
|
@@ -42,8 +46,25 @@ Einvoice.configure do |config|
|
|
|
42
46
|
config.client_secret = ENV['EINVOICE_CLIENT_SECRET']
|
|
43
47
|
config.encryption_keys = ENV['ENCRYPTION_KEYS']
|
|
44
48
|
config.format = "json"
|
|
49
|
+
# config.ssl_verify = false # disable TLS certificate verification (default: true)
|
|
45
50
|
end
|
|
46
51
|
```
|
|
52
|
+
### SSL certificate verification
|
|
53
|
+
|
|
54
|
+
By default, `einvoice` verifies the TLS certificate of the configured
|
|
55
|
+
endpoint (`config.ssl_verify` defaults to `true`). If you need to disable
|
|
56
|
+
this — for example when testing against an endpoint with an incomplete
|
|
57
|
+
certificate chain — you can opt out:
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
config.ssl_verify = false
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Or per-provider:
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
Einvoice::Tradevan::Provider.new(ssl_verify: false)
|
|
67
|
+
```
|
|
47
68
|
|
|
48
69
|
### Initialize
|
|
49
70
|
|
|
@@ -51,7 +72,7 @@ end
|
|
|
51
72
|
client = Einvoice::Client.new(Einvoice::Tradevan::Provider.new)
|
|
52
73
|
```
|
|
53
74
|
|
|
54
|
-
### Issue an invoice
|
|
75
|
+
### Issue an invoice (開立電子發票)
|
|
55
76
|
|
|
56
77
|
```ruby
|
|
57
78
|
payload = {
|
|
@@ -122,7 +143,7 @@ result.data
|
|
|
122
143
|
# }
|
|
123
144
|
```
|
|
124
145
|
|
|
125
|
-
### Cancel an invoice
|
|
146
|
+
### Cancel an invoice (作廢電子發票)
|
|
126
147
|
|
|
127
148
|
```ruby
|
|
128
149
|
payload = {
|
|
@@ -149,7 +170,74 @@ result.data
|
|
|
149
170
|
# }
|
|
150
171
|
```
|
|
151
172
|
|
|
152
|
-
###
|
|
173
|
+
### Issue an allowance (開立折讓單)
|
|
174
|
+
|
|
175
|
+
An allowance against a previously issued invoice is sent through `issue` with `type: "A"`. Each item must reference the original invoice (`invoiceNumber` / `invoiceDate`) and carry its tax-exclusive amount (`itemExclude`).
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
payload = {
|
|
179
|
+
companyUn: "12345678",
|
|
180
|
+
orgId: "ABCDE",
|
|
181
|
+
type: "A",
|
|
182
|
+
allowanceIdentifier: "12345678_ABCDE_53b2a44e4b3d",
|
|
183
|
+
transactionNumber: "53b2a44e4b3d",
|
|
184
|
+
transactionDate: "20160426",
|
|
185
|
+
paperPrintMode: "0",
|
|
186
|
+
invoiceAlarmMode: "4",
|
|
187
|
+
allowanceExclusiveAmount: "95",
|
|
188
|
+
allowanceTax: "5",
|
|
189
|
+
allowanceInclusiveAmount: "100",
|
|
190
|
+
allowancePaperReturned: "N",
|
|
191
|
+
invoicePaperReturned: "N",
|
|
192
|
+
receiverName: "John Appleseed",
|
|
193
|
+
receiverEmail: "john@gmail.com",
|
|
194
|
+
itemList: [
|
|
195
|
+
{
|
|
196
|
+
saleIdentifier: "12345678_ABCDE_53b2a44e4b3c",
|
|
197
|
+
serialNumber: "0001",
|
|
198
|
+
invoiceNumber: "GX38551078",
|
|
199
|
+
invoiceDate: "20160425",
|
|
200
|
+
productName: "Coffee Latte",
|
|
201
|
+
qty: "1000",
|
|
202
|
+
price: "100",
|
|
203
|
+
itemExclude: "95",
|
|
204
|
+
tax: "5",
|
|
205
|
+
itemTotal: "100",
|
|
206
|
+
taxType: "T"
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
```ruby
|
|
213
|
+
result = client.issue(payload)
|
|
214
|
+
result.successful?
|
|
215
|
+
#=> true
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Notes:
|
|
219
|
+
|
|
220
|
+
* `allowanceIdentifier` must be prefixed with `"#{companyUn}_#{orgId}_"`, like `saleIdentifier` on invoices.
|
|
221
|
+
* `allowanceExclusiveAmount` + `allowanceTax` = `allowanceInclusiveAmount`.
|
|
222
|
+
|
|
223
|
+
### Void an allowance (作廢折讓單)
|
|
224
|
+
|
|
225
|
+
```ruby
|
|
226
|
+
payload = {
|
|
227
|
+
type: "A",
|
|
228
|
+
companyUn: "12345678",
|
|
229
|
+
allowanceNumber: "ABCDE20160426001",
|
|
230
|
+
allowancePaperReturned: "Y",
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
result = client.cancel(payload)
|
|
236
|
+
result.successful?
|
|
237
|
+
#=> true
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Search invoice by memberId/sellTargetCode (載具/會員發票查詢)
|
|
153
241
|
|
|
154
242
|
```ruby
|
|
155
243
|
payload = {
|
|
@@ -195,7 +283,7 @@ result.data
|
|
|
195
283
|
# ]
|
|
196
284
|
```
|
|
197
285
|
|
|
198
|
-
### Search invoice detail
|
|
286
|
+
### Search invoice detail (發票開立明細查詢)
|
|
199
287
|
|
|
200
288
|
```ruby
|
|
201
289
|
result = client.search_invoice_detail("GX38551078")
|
|
@@ -239,7 +327,7 @@ result.data
|
|
|
239
327
|
# }
|
|
240
328
|
```
|
|
241
329
|
|
|
242
|
-
### Send card info to customer
|
|
330
|
+
### Send card info to customer (電子發票載具歸戶/中獎通知作業)
|
|
243
331
|
|
|
244
332
|
```ruby
|
|
245
333
|
payload = {
|
|
@@ -259,7 +347,7 @@ result.successful?
|
|
|
259
347
|
result.data
|
|
260
348
|
```
|
|
261
349
|
|
|
262
|
-
### Get invoice mark info
|
|
350
|
+
### Get invoice mark info (電子發票字軌號碼配額取號/分配作業)
|
|
263
351
|
|
|
264
352
|
```ruby
|
|
265
353
|
payload = {
|
|
@@ -291,13 +379,13 @@ result.data
|
|
|
291
379
|
# ]
|
|
292
380
|
```
|
|
293
381
|
|
|
294
|
-
### Get donate unit list
|
|
382
|
+
### Get donate unit list (受贈機關/社福團體愛心碼清單查詢)
|
|
295
383
|
|
|
296
384
|
```ruby
|
|
297
385
|
client.get_donate_unit_list("12345678")
|
|
298
386
|
```
|
|
299
387
|
|
|
300
|
-
### Get invoice content
|
|
388
|
+
### Get invoice content (電子發票內容查詢)
|
|
301
389
|
|
|
302
390
|
```ruby
|
|
303
391
|
payload = {
|
data/Rakefile
CHANGED
|
@@ -7,13 +7,51 @@ task default: :spec
|
|
|
7
7
|
|
|
8
8
|
desc "Download latest e-invoice donation unit list and convert it to JSON"
|
|
9
9
|
task :update_donation_unit do
|
|
10
|
+
require "csv"
|
|
10
11
|
require "json"
|
|
11
12
|
require "faraday"
|
|
13
|
+
|
|
12
14
|
# From https://data.gov.tw/dataset/31868
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
url = "https://dataset.einvoice.nat.gov.tw/ods/portal/ODS303W/download/3886F055-EB77-4DF9-98E2-F3F49A7D3434/1/8B227A99-042A-4903-8B34-5715442A227D/0/?fileType=csv"
|
|
16
|
+
response = Faraday.get(url)
|
|
17
|
+
raise "Download failed: HTTP #{response.status}" unless response.status == 200
|
|
18
|
+
|
|
19
|
+
body = response.body
|
|
20
|
+
|
|
21
|
+
possible = ["UTF-8", "Big5"]
|
|
22
|
+
chosen = nil
|
|
23
|
+
utf8_text = nil
|
|
24
|
+
|
|
25
|
+
possible.each do |code|
|
|
26
|
+
begin
|
|
27
|
+
str = body.dup.force_encoding(code)
|
|
28
|
+
candidate = str.encode("UTF-8")
|
|
29
|
+
if candidate.valid_encoding?
|
|
30
|
+
chosen = code
|
|
31
|
+
utf8_text = candidate
|
|
32
|
+
break
|
|
33
|
+
end
|
|
34
|
+
rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError
|
|
35
|
+
next
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
unless chosen
|
|
40
|
+
chosen = "fallback(replace)"
|
|
41
|
+
utf8_text = body.dup.force_encoding("UTF-8").scrub("?")
|
|
42
|
+
puts "::warning::Used fallback encoding with replacement; some characters may be lost"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
utf8_text = utf8_text.delete_prefix("\uFEFF") # remove possible UTF-8 BOM
|
|
46
|
+
csv = CSV.parse(utf8_text, headers: true)
|
|
47
|
+
|
|
48
|
+
orgs = csv.map do |row|
|
|
49
|
+
code = (row['捐贈碼'] || row[2]).to_s.strip
|
|
50
|
+
name = (row['受捐贈機關或團體名稱'] || row[1]).to_s.strip
|
|
51
|
+
[code, name]
|
|
52
|
+
end.sort_by { |code, _| [code.to_i, code] }
|
|
53
|
+
|
|
54
|
+
File.write "lib/einvoice/donation_unit_list.json", JSON.pretty_generate(orgs.to_h)
|
|
17
55
|
|
|
18
|
-
|
|
19
|
-
end
|
|
56
|
+
puts "Wrote lib/einvoice/donation_unit_list.json (#{orgs.length} entries)"
|
|
57
|
+
end
|
data/einvoice.gemspec
CHANGED
|
@@ -9,25 +9,30 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.authors = ["David Yun"]
|
|
10
10
|
spec.email = ["abookyun@gmail.com"]
|
|
11
11
|
|
|
12
|
-
spec.summary = %q{
|
|
12
|
+
spec.summary = %q{An API wrapper for Taiwan e-invoice services.}
|
|
13
13
|
spec.homepage = "https://github.com/abookyun/einvoice"
|
|
14
14
|
spec.license = "MIT"
|
|
15
15
|
|
|
16
|
+
spec.metadata = {
|
|
17
|
+
"source_code_uri" => "https://github.com/abookyun/einvoice",
|
|
18
|
+
"changelog_uri" => "https://github.com/abookyun/einvoice/blob/main/CHANGELOG.md",
|
|
19
|
+
"bug_tracker_uri" => "https://github.com/abookyun/einvoice/issues",
|
|
20
|
+
"rubygems_mfa_required" => "true"
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
17
24
|
spec.bindir = "exe"
|
|
18
25
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
19
26
|
spec.require_paths = ["lib"]
|
|
20
27
|
|
|
21
|
-
spec.required_ruby_version = '>=
|
|
22
|
-
spec.add_dependency "faraday"
|
|
23
|
-
spec.add_dependency "faraday_middleware"
|
|
28
|
+
spec.required_ruby_version = '>= 3.1'
|
|
29
|
+
spec.add_dependency "faraday", "~> 2.1"
|
|
24
30
|
spec.add_dependency "multi_xml"
|
|
25
31
|
spec.add_dependency "activemodel"
|
|
26
32
|
spec.add_dependency "activesupport"
|
|
27
|
-
spec.add_dependency "gyoku"
|
|
28
33
|
|
|
29
34
|
spec.add_development_dependency "bundler", "> 1.17"
|
|
30
|
-
spec.add_development_dependency "rake", "~>
|
|
35
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
31
36
|
spec.add_development_dependency "pry"
|
|
32
37
|
spec.add_development_dependency "rspec"
|
|
33
38
|
spec.add_development_dependency "factory_bot"
|
data/lib/einvoice/client.rb
CHANGED
|
@@ -7,7 +7,15 @@ module Einvoice
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def method_missing(m, *args, &block)
|
|
10
|
-
provider.
|
|
10
|
+
if provider.respond_to?(m)
|
|
11
|
+
provider.public_send(m, *args, &block)
|
|
12
|
+
else
|
|
13
|
+
super
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def respond_to_missing?(m, include_private = false)
|
|
18
|
+
provider.respond_to?(m) || super
|
|
11
19
|
end
|
|
12
20
|
end
|
|
13
21
|
end
|
|
@@ -8,7 +8,8 @@ module Einvoice
|
|
|
8
8
|
:client_id,
|
|
9
9
|
:client_secret,
|
|
10
10
|
:encryption_keys,
|
|
11
|
-
:format
|
|
11
|
+
:format,
|
|
12
|
+
:ssl_verify
|
|
12
13
|
].freeze
|
|
13
14
|
|
|
14
15
|
DEFAULT_CLIENT_ID = nil
|
|
@@ -17,8 +18,9 @@ module Einvoice
|
|
|
17
18
|
DEFAULT_ENDPOINT_URL = nil
|
|
18
19
|
DEFAULT_FORMAT = ""
|
|
19
20
|
DEFAULT_ENCRYPTION_KEYS = {}
|
|
21
|
+
DEFAULT_SSL_VERIFY = true
|
|
20
22
|
|
|
21
|
-
attr_accessor
|
|
23
|
+
attr_accessor(*VALID_OPTIONS_KEYS)
|
|
22
24
|
|
|
23
25
|
def self.extended(base)
|
|
24
26
|
base.reset
|
|
@@ -41,6 +43,7 @@ module Einvoice
|
|
|
41
43
|
self.endpoint_url = DEFAULT_ENDPOINT_URL
|
|
42
44
|
self.encryption_keys = DEFAULT_ENCRYPTION_KEYS
|
|
43
45
|
self.format = DEFAULT_FORMAT
|
|
46
|
+
self.ssl_verify = DEFAULT_SSL_VERIFY
|
|
44
47
|
end
|
|
45
48
|
end
|
|
46
49
|
end
|
data/lib/einvoice/connection.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
require "faraday_middleware"
|
|
2
1
|
require "faraday/response/decode_tradevan"
|
|
2
|
+
require "faraday/response/parse_xml"
|
|
3
3
|
|
|
4
4
|
module Einvoice
|
|
5
5
|
module Connection
|
|
@@ -8,7 +8,8 @@ module Einvoice
|
|
|
8
8
|
def connection(options = {})
|
|
9
9
|
connection_options = {
|
|
10
10
|
headers: { "Accept" => "application/#{format}; charset=utf-8" },
|
|
11
|
-
url: endpoint
|
|
11
|
+
url: endpoint,
|
|
12
|
+
ssl: { verify: ssl_verify != false }
|
|
12
13
|
}.merge(options)
|
|
13
14
|
|
|
14
15
|
::Faraday::Connection.new(connection_options) do |connection|
|