digiwin_dsp 0.2.2 → 0.2.4
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 +42 -1
- data/README.md +11 -0
- data/lib/digiwin_dsp/resources/base.rb +29 -0
- data/lib/digiwin_dsp/resources/cancellation.rb +2 -17
- data/lib/digiwin_dsp/resources/invoice.rb +2 -17
- data/lib/digiwin_dsp/resources/order.rb +2 -17
- data/lib/digiwin_dsp/resources/return.rb +2 -17
- data/lib/digiwin_dsp/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: feebd7c9c5d89e9d6306b00ecccb402151c9e299201ecf3b98cfbf7c9a1590a1
|
|
4
|
+
data.tar.gz: 7c9fbb5aa913649c417a4f23caf6bf9f3b10bc92b6c2efb34e9cc1cdce8808ad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 292e2d148f9af342959a826cbed33999cbd81b169719fa79882b309bfdfb6b1800e88ed18dfcd3d0210784d85f7df9dea1e02e63b0a0f9e67e276e235c7c403d
|
|
7
|
+
data.tar.gz: 437cd4412d96aa9914b99cea75ca5ce06274870aada7a2462b53d64e18eb5ebb03b9dbee07bd78cadab08880652aabe49e7ce88ff987c043be7530ff031c3712
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,45 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.2.4] - 2026-05-22
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`Resources::Base`** — shared parent for the 4 resource classes. Each subclass now declares two constants (`PATH`, `SERIALIZER`); the `.create` class shortcut, `#create` instance flow, and the `response_detail` safety check live in one place.
|
|
14
|
+
- **VCR replay coverage.** New `spec/digiwin_dsp/live_replay_spec.rb` + cassettes under `spec/fixtures/cassettes/` verify the gem parses real DSP UAT responses correctly. Credentials filtered via `spec/support/vcr.rb`. Re-record with `RECORD_CASSETTES=1` + real env vars.
|
|
15
|
+
- **`dotenv` auto-loaded in `bin/console`.** Drops a `.env.local` into the IRB session so manual UAT testing is plug-and-play (`bin/console` → `DigiwinDsp::Resources::Order.create(...)`).
|
|
16
|
+
- **GitHub Release auto-created by `release.yml`.** Workflow now extracts the version's CHANGELOG section and posts it with the built `.gem` artifact — no more manual `gh release create` after each version bump.
|
|
17
|
+
|
|
18
|
+
### Docs
|
|
19
|
+
|
|
20
|
+
- Idempotency section in README clarified: DSP UAT ignores `X-Idempotency-Key` (live-verified). Dedup is natural-key only (`form_no + platform_id`). The kwarg is still useful as a trace ID.
|
|
21
|
+
|
|
22
|
+
## [0.2.3] - 2026-05-22
|
|
23
|
+
|
|
24
|
+
### Docs
|
|
25
|
+
|
|
26
|
+
- Document the `order_status` enum (`"2"` cancel / `"3"` new / `"5"` invoice / `"7"` return) in README and `docs/dsp-api-spec.md`. DSP rejects others with `WrongStatus:order_status錯誤,請固定給N(...)`. All four live-verified against UAT. The OpenAPI examples don't surface this constraint, so live smoke had to discover each value.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- `scripts/smoke.rb` accepts `ORDER_STATUS=…` env override so operators can probe DSP's WrongStatus path without editing the script.
|
|
31
|
+
|
|
32
|
+
## [0.2.2] - 2026-05-21
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- **`Message:"DSP 序號驗證失敗"` now classifies as
|
|
37
|
+
`DigiwinDsp::AuthenticationError`.** Discovered via live UAT smoke
|
|
38
|
+
test: when the `DSP-api-key` header is missing or invalid, DSP
|
|
39
|
+
returns HTTP 200 (not 401/403) with `Status:Failure` and that
|
|
40
|
+
message. Previously fell through to generic `Error`, defeating
|
|
41
|
+
typed-rescue logic.
|
|
42
|
+
|
|
43
|
+
### Docs
|
|
44
|
+
|
|
45
|
+
- `docs/dsp-api-spec.md` documents the auth-failure envelope shape +
|
|
46
|
+
the form_no-prefix behavior on `Message`.
|
|
47
|
+
|
|
9
48
|
## [0.2.1] - 2026-05-21
|
|
10
49
|
|
|
11
50
|
### Fixed
|
|
@@ -140,7 +179,9 @@ Initial release. Covers the four Self-hosted Website Module (自有官網模組)
|
|
|
140
179
|
- The gem is **synchronous on purpose**. Callers wrap requests in their own background job runner (e.g. ActiveJob) when needed.
|
|
141
180
|
- Idempotency: clients can send `X-Idempotency-Key` via the `idempotency_key:` kwarg. DSP also dedupes server-side by `form_no + platform_id`.
|
|
142
181
|
|
|
143
|
-
[Unreleased]: https://github.com/7a6163/digiwin_dsp/compare/v0.2.
|
|
182
|
+
[Unreleased]: https://github.com/7a6163/digiwin_dsp/compare/v0.2.4...HEAD
|
|
183
|
+
[0.2.4]: https://github.com/7a6163/digiwin_dsp/compare/v0.2.3...v0.2.4
|
|
184
|
+
[0.2.3]: https://github.com/7a6163/digiwin_dsp/compare/v0.2.2...v0.2.3
|
|
144
185
|
[0.2.2]: https://github.com/7a6163/digiwin_dsp/compare/v0.2.1...v0.2.2
|
|
145
186
|
[0.2.1]: https://github.com/7a6163/digiwin_dsp/compare/v0.2.0...v0.2.1
|
|
146
187
|
[0.2.0]: https://github.com/7a6163/digiwin_dsp/compare/v0.1.1...v0.2.0
|
data/README.md
CHANGED
|
@@ -141,6 +141,17 @@ Each has its own required-field set (8 / 11 / 19 fields respectively). Inspect `
|
|
|
141
141
|
DigiwinDsp::Serializers::CancellationSerializer::REQUIRED_FIELDS
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
+
### `order_status` enum
|
|
145
|
+
|
|
146
|
+
Each endpoint requires a specific `order_status` value inside `request_detail`. DSP rejects others with `WrongStatus:order_status錯誤,請固定給N(...)`. The OpenAPI examples don't document this — verified live against UAT 2026-05-21:
|
|
147
|
+
|
|
148
|
+
| Resource | `order_status` | Meaning |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
| `Resources::Order` | `"3"` | 新增訂單 (new order) |
|
|
151
|
+
| `Resources::Cancellation` | `"2"` | 取消訂單 (cancel order) |
|
|
152
|
+
| `Resources::Invoice` | `"5"` | 發票更新 (invoice update) |
|
|
153
|
+
| `Resources::Return` | `"7"` | 退貨訂單 (return order) |
|
|
154
|
+
|
|
144
155
|
### Idempotency
|
|
145
156
|
|
|
146
157
|
Pass `idempotency_key:` to attach an `X-Idempotency-Key` request header. DSP also dedupes server-side by `form_no + platform_id` and returns `Duplicated:訂單不可重複` on a re-send (mapped to `DuplicateRequestError`).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DigiwinDsp
|
|
4
|
+
module Resources
|
|
5
|
+
# Subclasses declare two constants:
|
|
6
|
+
# PATH — endpoint path (e.g. "/v1/SalesOrder/add")
|
|
7
|
+
# SERIALIZER — a module/class responding to `.serialize(records, digi_header:)`
|
|
8
|
+
#
|
|
9
|
+
# Base then handles the .create class shortcut, the instance #create flow,
|
|
10
|
+
# and the response_detail safety check.
|
|
11
|
+
class Base
|
|
12
|
+
def self.create(records, idempotency_key: nil, digi_header: nil)
|
|
13
|
+
new.create(records, idempotency_key: idempotency_key, digi_header: digi_header)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize(client = Client.new)
|
|
17
|
+
@client = client
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def create(records, idempotency_key: nil, digi_header: nil)
|
|
21
|
+
body = self.class::SERIALIZER.serialize(records, digi_header: digi_header)
|
|
22
|
+
response = @client.post(self.class::PATH, body, idempotency_key: idempotency_key)
|
|
23
|
+
response.fetch("response_detail") do
|
|
24
|
+
raise DigiwinDsp::ServerError, "DSP returned Status=Success without response_detail"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -2,24 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module DigiwinDsp
|
|
4
4
|
module Resources
|
|
5
|
-
class Cancellation
|
|
5
|
+
class Cancellation < Base
|
|
6
6
|
PATH = "/v1/SalesOrder/cancel"
|
|
7
|
-
|
|
8
|
-
def self.create(records, idempotency_key: nil, digi_header: nil)
|
|
9
|
-
new.create(records, idempotency_key: idempotency_key, digi_header: digi_header)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def initialize(client = Client.new)
|
|
13
|
-
@client = client
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def create(records, idempotency_key: nil, digi_header: nil)
|
|
17
|
-
body = Serializers::CancellationSerializer.serialize(records, digi_header: digi_header)
|
|
18
|
-
response = @client.post(PATH, body, idempotency_key: idempotency_key)
|
|
19
|
-
response.fetch("response_detail") do
|
|
20
|
-
raise DigiwinDsp::ServerError, "DSP returned Status=Success without response_detail"
|
|
21
|
-
end
|
|
22
|
-
end
|
|
7
|
+
SERIALIZER = Serializers::CancellationSerializer
|
|
23
8
|
end
|
|
24
9
|
end
|
|
25
10
|
end
|
|
@@ -2,24 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module DigiwinDsp
|
|
4
4
|
module Resources
|
|
5
|
-
class Invoice
|
|
5
|
+
class Invoice < Base
|
|
6
6
|
PATH = "/v1/SalesOrder/invoice"
|
|
7
|
-
|
|
8
|
-
def self.create(records, idempotency_key: nil, digi_header: nil)
|
|
9
|
-
new.create(records, idempotency_key: idempotency_key, digi_header: digi_header)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def initialize(client = Client.new)
|
|
13
|
-
@client = client
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def create(records, idempotency_key: nil, digi_header: nil)
|
|
17
|
-
body = Serializers::InvoiceSerializer.serialize(records, digi_header: digi_header)
|
|
18
|
-
response = @client.post(PATH, body, idempotency_key: idempotency_key)
|
|
19
|
-
response.fetch("response_detail") do
|
|
20
|
-
raise DigiwinDsp::ServerError, "DSP returned Status=Success without response_detail"
|
|
21
|
-
end
|
|
22
|
-
end
|
|
7
|
+
SERIALIZER = Serializers::InvoiceSerializer
|
|
23
8
|
end
|
|
24
9
|
end
|
|
25
10
|
end
|
|
@@ -2,24 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module DigiwinDsp
|
|
4
4
|
module Resources
|
|
5
|
-
class Order
|
|
5
|
+
class Order < Base
|
|
6
6
|
PATH = "/v1/SalesOrder/add"
|
|
7
|
-
|
|
8
|
-
def self.create(records, idempotency_key: nil, digi_header: nil)
|
|
9
|
-
new.create(records, idempotency_key: idempotency_key, digi_header: digi_header)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def initialize(client = Client.new)
|
|
13
|
-
@client = client
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def create(records, idempotency_key: nil, digi_header: nil)
|
|
17
|
-
body = Serializers::SalesOrderSerializer.serialize(records, digi_header: digi_header)
|
|
18
|
-
response = @client.post(PATH, body, idempotency_key: idempotency_key)
|
|
19
|
-
response.fetch("response_detail") do
|
|
20
|
-
raise DigiwinDsp::ServerError, "DSP returned Status=Success without response_detail"
|
|
21
|
-
end
|
|
22
|
-
end
|
|
7
|
+
SERIALIZER = Serializers::SalesOrderSerializer
|
|
23
8
|
end
|
|
24
9
|
end
|
|
25
10
|
end
|
|
@@ -2,24 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module DigiwinDsp
|
|
4
4
|
module Resources
|
|
5
|
-
class Return
|
|
5
|
+
class Return < Base
|
|
6
6
|
PATH = "/v1/SalesOrder/return"
|
|
7
|
-
|
|
8
|
-
def self.create(records, idempotency_key: nil, digi_header: nil)
|
|
9
|
-
new.create(records, idempotency_key: idempotency_key, digi_header: digi_header)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def initialize(client = Client.new)
|
|
13
|
-
@client = client
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def create(records, idempotency_key: nil, digi_header: nil)
|
|
17
|
-
body = Serializers::ReturnSerializer.serialize(records, digi_header: digi_header)
|
|
18
|
-
response = @client.post(PATH, body, idempotency_key: idempotency_key)
|
|
19
|
-
response.fetch("response_detail") do
|
|
20
|
-
raise DigiwinDsp::ServerError, "DSP returned Status=Success without response_detail"
|
|
21
|
-
end
|
|
22
|
-
end
|
|
7
|
+
SERIALIZER = Serializers::ReturnSerializer
|
|
23
8
|
end
|
|
24
9
|
end
|
|
25
10
|
end
|
data/lib/digiwin_dsp/version.rb
CHANGED
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.2.
|
|
4
|
+
version: 0.2.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Zac
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -68,6 +68,7 @@ files:
|
|
|
68
68
|
- lib/digiwin_dsp/authenticator.rb
|
|
69
69
|
- lib/digiwin_dsp/client.rb
|
|
70
70
|
- lib/digiwin_dsp/configuration.rb
|
|
71
|
+
- lib/digiwin_dsp/resources/base.rb
|
|
71
72
|
- lib/digiwin_dsp/resources/cancellation.rb
|
|
72
73
|
- lib/digiwin_dsp/resources/invoice.rb
|
|
73
74
|
- lib/digiwin_dsp/resources/order.rb
|