digiwin_dsp 0.3.0 → 0.3.1
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 +23 -1
- data/README.md +1 -1
- data/lib/digiwin_dsp/client.rb +7 -1
- data/lib/digiwin_dsp/resources/webhook_subscription.rb +5 -0
- data/lib/digiwin_dsp/version.rb +1 -1
- data/lib/digiwin_dsp/webhooks/event.rb +2 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3cfde42cbd2b4448e9c5e4927e9ecb65f61ae19a46474154ae1349d73cd2461c
|
|
4
|
+
data.tar.gz: 6d35ad2fd9430c5440f626b15f3c98c9a8dd627c2732bb349bc355f6693d9de3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 95d2787c766fa0a316542b37d0b5620738e9dcff687562875698e5c1d0f3a3ffaaa2e93a81f24b34e0f6e27047a9c53d22e1368725879f36a6f48116b02f2b7c
|
|
7
|
+
data.tar.gz: c8f1b7781c06e3fa745d4e2a6770d7442dd443a38e10ca4ce6767b5aaa82bbf1016ef8aeb961922ebe9f41321d6702be561a1c82810223335a0a340c6f6eb27b
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,27 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.3.1] - 2026-06-12
|
|
10
|
+
|
|
11
|
+
Hardening patch from a full gem + docs review. All fixes grounded in the vendor YAML specs.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **TLS failures now raise `DigiwinDsp::NetworkError`.** `Faraday::SSLError` sits directly under `Faraday::Error` (not `ConnectionFailed`), so certificate problems previously leaked as raw Faraday exceptions that `rescue DigiwinDsp::Error` could not catch.
|
|
16
|
+
- **Three more DSP failure messages classify into typed exceptions** instead of falling through to generic `Error`:
|
|
17
|
+
- `Shipped:訂單已出貨,不可取消` (DSPOOFFICIAL002) → `ValidationError` — permanent; the order left the warehouse
|
|
18
|
+
- `Processing:新增訂單處理中,不可取消` (DSPOOFFICIAL002) → `RateLimitError` — retryable once ERP processes the add
|
|
19
|
+
- `SalesNotCreate:銷貨單未成立` (DSPOOFFICIAL004) → `RateLimitError` — retryable once ERP converts the sales doc
|
|
20
|
+
Sidekiq/ActiveJob retry strategies can now distinguish "don't retry" from "retry later" on cancel and invoice flows.
|
|
21
|
+
- **`Webhooks::Event.parse_json` / `.extract_request` are now private class methods.** They were internal helpers accidentally exposed on all three event classes.
|
|
22
|
+
- **`WebhookSubscription` rejects non-`https://` callback addresses** at registration time. DSPOOFFICIAL100 mandates HTTPS callbacks, and with no HMAC signing a plaintext callback would be indefensible. (Previously the README claimed this was enforced when it wasn't.)
|
|
23
|
+
|
|
24
|
+
### Docs
|
|
25
|
+
|
|
26
|
+
- `dsp-api-spec.md`: corrected the e-invoice carrier field name — `Resources::Invoice` sends **`carrier_type`** (DSPOOFFICIAL004:164), not `carrier_code`. `carrier_code` is only on `Resources::Order` and the inbound webhook. Optional fields aren't validated client-side, so the wrong name silently drops carrier data.
|
|
27
|
+
- `dsp-api-spec.md`: failure-message table now covers 002 (cancel) and 004 (invoice) sources, not just 001.
|
|
28
|
+
- README: webhook security bullet now describes the actual https enforcement.
|
|
29
|
+
|
|
9
30
|
## [0.3.0] - 2026-05-28
|
|
10
31
|
|
|
11
32
|
DSP webhook support (DSPOOFFICIAL100). Lets a Rails app register a callback URL with DSP, then receive and parse the three documented ERP-originated push events: inventory updates, shipping/logistics status, and invoice issuance.
|
|
@@ -205,7 +226,8 @@ Initial release. Covers the four Self-hosted Website Module (自有官網模組)
|
|
|
205
226
|
- The gem is **synchronous on purpose**. Callers wrap requests in their own background job runner (e.g. ActiveJob) when needed.
|
|
206
227
|
- Idempotency: clients can send `X-Idempotency-Key` via the `idempotency_key:` kwarg. DSP also dedupes server-side by `form_no + platform_id`.
|
|
207
228
|
|
|
208
|
-
[Unreleased]: https://github.com/7a6163/digiwin_dsp/compare/v0.3.
|
|
229
|
+
[Unreleased]: https://github.com/7a6163/digiwin_dsp/compare/v0.3.1...HEAD
|
|
230
|
+
[0.3.1]: https://github.com/7a6163/digiwin_dsp/compare/v0.3.0...v0.3.1
|
|
209
231
|
[0.3.0]: https://github.com/7a6163/digiwin_dsp/compare/v0.2.4...v0.3.0
|
|
210
232
|
[0.2.4]: https://github.com/7a6163/digiwin_dsp/compare/v0.2.3...v0.2.4
|
|
211
233
|
[0.2.3]: https://github.com/7a6163/digiwin_dsp/compare/v0.2.2...v0.2.3
|
data/README.md
CHANGED
|
@@ -213,7 +213,7 @@ end
|
|
|
213
213
|
```
|
|
214
214
|
|
|
215
215
|
> ⚠️ **DSP does NOT sign inbound webhooks.** There is no HMAC header. Defend the callback endpoint with:
|
|
216
|
-
> - HTTPS-only
|
|
216
|
+
> - HTTPS-only — `WebhookSubscription` rejects non-`https://` addresses at registration time (DSP's own spec mandates HTTPS callbacks)
|
|
217
217
|
> - An unguessable URL path (treat it as a secret)
|
|
218
218
|
> - An IP allowlist for DSP's egress range if your network team can get one
|
|
219
219
|
> - Replying `200 OK` within 30 seconds (DSP will retry and may eventually block your endpoint if too many calls fail)
|
data/lib/digiwin_dsp/client.rb
CHANGED
|
@@ -33,6 +33,9 @@ module DigiwinDsp
|
|
|
33
33
|
[/Duplicated:/, DuplicateRequestError], # order already exists
|
|
34
34
|
[/Processing:資料處理中/, RateLimitError], # transient; retry later
|
|
35
35
|
[/Processing:取消訂單處理中/, ValidationError], # cancel in flight
|
|
36
|
+
[/Processing:新增訂單處理中/, RateLimitError], # add in flight; cancel retryable after ERP processes (002)
|
|
37
|
+
[/Shipped:/, ValidationError], # already shipped — cancel permanently impossible (002)
|
|
38
|
+
[/SalesNotCreate:/, RateLimitError], # ERP hasn't converted sales doc yet; invoice retryable (004)
|
|
36
39
|
[/WrongStatus:/, ValidationError], # bad payload
|
|
37
40
|
[/系統異常:/, ServerError] # DSP internal error
|
|
38
41
|
].freeze
|
|
@@ -52,7 +55,10 @@ module DigiwinDsp
|
|
|
52
55
|
req.body = body
|
|
53
56
|
end
|
|
54
57
|
handle_response(response)
|
|
55
|
-
rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
|
|
58
|
+
rescue Faraday::ConnectionFailed, Faraday::TimeoutError, Faraday::SSLError => e
|
|
59
|
+
# SSLError sits directly under Faraday::Error (not ConnectionFailed),
|
|
60
|
+
# so it needs an explicit entry — otherwise TLS failures leak as raw
|
|
61
|
+
# Faraday exceptions that `rescue DigiwinDsp::Error` won't catch.
|
|
56
62
|
raise NetworkError, e.message
|
|
57
63
|
end
|
|
58
64
|
|
|
@@ -43,6 +43,11 @@ module DigiwinDsp
|
|
|
43
43
|
"action must be one of #{ACTIONS.inspect} (got #{action.inspect})"
|
|
44
44
|
end
|
|
45
45
|
raise DigiwinDsp::ValidationError, "address is required" if address.nil? || address.to_s.empty?
|
|
46
|
+
|
|
47
|
+
# DSPOOFFICIAL100 mandates HTTPS for the callback ("必須在 30 秒內以
|
|
48
|
+
# HTTPS 回應") — and with no HMAC signing, a plaintext callback URL
|
|
49
|
+
# would be indefensible anyway.
|
|
50
|
+
raise DigiwinDsp::ValidationError, "address must be an https:// URL (got #{address.inspect})" unless address.start_with?("https://")
|
|
46
51
|
return unless address.length > ADDRESS_MAX_LENGTH
|
|
47
52
|
|
|
48
53
|
raise DigiwinDsp::ValidationError,
|
data/lib/digiwin_dsp/version.rb
CHANGED
|
@@ -30,6 +30,8 @@ module DigiwinDsp
|
|
|
30
30
|
raise(ParseError, "envelope missing digi_body.std_data.parameter.request")
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
private_class_method :parse_json, :extract_request
|
|
34
|
+
|
|
33
35
|
def initialize(digi_header:, request:, raw:)
|
|
34
36
|
@digi_header = digi_header
|
|
35
37
|
@request = request
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: digiwin_dsp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Zac
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-06-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|