digiwin_dsp 0.3.1 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3cfde42cbd2b4448e9c5e4927e9ecb65f61ae19a46474154ae1349d73cd2461c
4
- data.tar.gz: 6d35ad2fd9430c5440f626b15f3c98c9a8dd627c2732bb349bc355f6693d9de3
3
+ metadata.gz: 3c97b2b31a4aef72b75b7597df9577f3107963906fc673f8b95edc40bd4102e8
4
+ data.tar.gz: 323356c76f98fb9e443e23317f4fba1a40e2029507de73d84f6c017cf26658d8
5
5
  SHA512:
6
- metadata.gz: 95d2787c766fa0a316542b37d0b5620738e9dcff687562875698e5c1d0f3a3ffaaa2e93a81f24b34e0f6e27047a9c53d22e1368725879f36a6f48116b02f2b7c
7
- data.tar.gz: c8f1b7781c06e3fa745d4e2a6770d7442dd443a38e10ca4ce6767b5aaa82bbf1016ef8aeb961922ebe9f41321d6702be561a1c82810223335a0a340c6f6eb27b
6
+ metadata.gz: d4016d3746fa67d7ee637b7f6bd49b7a7f639e731adf0846277b276cd22efeb3595d909d9c2ff802c2e6ce7b5ffec05b35f5a08ed8b0e5971209cbd3f9f5c344
7
+ data.tar.gz: 6c507083e6ac8225ccfa6d3f80cc5cd876bb3b4378fc1f4d3f9078fe5299e523b03fa21323e62e4da1b86cf1647b801440647da334d5c1ae6569060644613508
data/CHANGELOG.md CHANGED
@@ -6,6 +6,37 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.4.1] - 2026-06-13
10
+
11
+ ### Added
12
+
13
+ - **`pay_type` codes 9115–9130** (16 new payment methods) synced from the updated DSPOOFFICIAL001 spec into `Enums::PayType`, `docs/dsp-api-spec.md`, and `docs/dsp-specs/DSPOOFFICIAL001.yaml`: POS結帳, Zingala 零卡分期, 現金, 悠遊卡, 一卡通, 愛金卡, 台灣 Pay, Pi 錢包, 歐付寶, 微信, 全支付, iCashPay, 全盈支付, 支付寶, 台新 Pay, 貨到信用卡一次付款. `Enums::PayType::ALL` now has 31 entries.
14
+
15
+ ## [0.4.0] - 2026-06-12
16
+
17
+ Ergonomics + cleanup release. One breaking change (dead config removal).
18
+
19
+ ### BREAKING
20
+
21
+ - **`Configuration#api_secret` removed** (accessor, `DIGIWIN_DSP_API_SECRET` ENV read, README row, `.env.local.example` line). Reserved since v0.1.0 for "future HMAC signing" — DSPOOFFICIAL100 confirmed DSP doesn't sign webhooks, no gem code ever read it, and advertising it implied a security mechanism that didn't exist. **Migration:** delete `c.api_secret = ...` from your configure block (it would now raise `NoMethodError` at boot); a lingering ENV var is harmless.
22
+
23
+ ### Added
24
+
25
+ - **`DigiwinDsp::Enums`** — DSP code tables as Ruby constants so callers stop hardcoding `"9104"`:
26
+ `OrderStatus`, `PayType` (15), `ShippingType` (9), `InvoiceStatus` (5), `InvoiceType` (10), `CarrierType` (5), `IsPay`, plus inbound-webhook `UpdateMode` and `DistributorCode`. Each has a frozen `ALL` array for caller-side validations. No forced client-side validation — DSP still rejects unknown codes via `WrongStatus:` → `ValidationError`.
27
+ - **Unknown-envelope warning.** If a 2xx Hash body matches neither known envelope shape (`Status/Message` nor `std_data.execution`), `Client` now `logger.warn`s before passing it through — so if DSP ships a third envelope, failures can't silently read as success.
28
+ - **Multi-line `last_record` live-verified.** A 2-line order with `"N"` on the non-final line was accepted by UAT (2026-06-12). The YAML spec's "blank means not-last" alternative conflicts with the gem's required-field check; the documented `"N"` convention is now the verified path.
29
+
30
+ ### Changed
31
+
32
+ - `WebhookSubscription::ACTIONS` now derives from `Webhooks::ACTION_REGISTRY.keys` — what you can subscribe to is exactly what the gem can parse (single source of truth; previously two parallel lists that could drift).
33
+
34
+ ### Docs
35
+
36
+ - README gains a **Troubleshooting / FAQ** section (HTTP-200-failure gotcha, `序號驗證失敗`, `SalesNotCreate` timing, `Shipped:` permanence, `WrongStatus` self-correction, dedupe-on-`form_no` surprises, webhook-delivery checklist, ERP invoice-visibility caveat).
37
+ - README documents the **built-in Faraday retry** (up to 4 attempts, exponential backoff + jitter) and how it stacks with ActiveJob/Sidekiq retries — worst-case latency math included.
38
+ - README flags DSPOOFFICIAL004's 個案 caveat: invoice data is only visible inside the ERP after per-customer Digiwin customization.
39
+
9
40
  ## [0.3.1] - 2026-06-12
10
41
 
11
42
  Hardening patch from a full gem + docs review. All fixes grounded in the vendor YAML specs.
@@ -226,7 +257,9 @@ Initial release. Covers the four Self-hosted Website Module (自有官網模組)
226
257
  - The gem is **synchronous on purpose**. Callers wrap requests in their own background job runner (e.g. ActiveJob) when needed.
227
258
  - Idempotency: clients can send `X-Idempotency-Key` via the `idempotency_key:` kwarg. DSP also dedupes server-side by `form_no + platform_id`.
228
259
 
229
- [Unreleased]: https://github.com/7a6163/digiwin_dsp/compare/v0.3.1...HEAD
260
+ [Unreleased]: https://github.com/7a6163/digiwin_dsp/compare/v0.4.1...HEAD
261
+ [0.4.1]: https://github.com/7a6163/digiwin_dsp/compare/v0.4.0...v0.4.1
262
+ [0.4.0]: https://github.com/7a6163/digiwin_dsp/compare/v0.3.1...v0.4.0
230
263
  [0.3.1]: https://github.com/7a6163/digiwin_dsp/compare/v0.3.0...v0.3.1
231
264
  [0.3.0]: https://github.com/7a6163/digiwin_dsp/compare/v0.2.4...v0.3.0
232
265
  [0.2.4]: https://github.com/7a6163/digiwin_dsp/compare/v0.2.3...v0.2.4
data/README.md CHANGED
@@ -51,7 +51,6 @@ Every setting also falls back to an ENV var:
51
51
  | Setting | ENV var | Default | Notes |
52
52
  |---|---|---|---|
53
53
  | `api_key` | `DIGIWIN_DSP_API_KEY` | _(required)_ | sent as `DSP-api-key` header |
54
- | `api_secret` | `DIGIWIN_DSP_API_SECRET` | `nil` | reserved for future HMAC signing; unused today |
55
54
  | `platform_id` | `DIGIWIN_DSP_PLATFORM_ID` | `nil` | sent **per-record** in `request_detail.platform_id` (not in auth headers) |
56
55
  | `environment` | `DIGIWIN_DSP_ENV` | `:sandbox` | `:sandbox` (UAT) or `:production` |
57
56
  | `base_url` | `DIGIWIN_DSP_BASE_URL` | resolved from `environment` | must be `https://` and have a host in `allowed_hosts` |
@@ -119,7 +118,7 @@ response_detail = DigiwinDsp::Resources::Order.create(record)
119
118
  # => [{ "form_no" => "WEB202605200001", ... }]
120
119
  ```
121
120
 
122
- Multi-line orders: pass an array. Each element must carry the order-level fields plus its own line fields. Set `"last_record" => "Y"` on the final element and `"N"` on the rest:
121
+ Multi-line orders: pass an array. Each element must carry the order-level fields plus its own line fields. Set `"last_record" => "Y"` on the final element and `"N"` on the rest (live-verified against UAT 2026-06-12; the YAML spec says blank means "not last", but the gem's required-field check rejects blanks and DSP accepts the explicit `"N"`):
123
122
 
124
123
  ```ruby
125
124
  records = [
@@ -144,6 +143,8 @@ Each has its own required-field set (8 / 11 / 19 fields respectively). Inspect `
144
143
  DigiwinDsp::Serializers::CancellationSerializer::REQUIRED_FIELDS
145
144
  ```
146
145
 
146
+ > ⚠️ **Invoice sync requires ERP-side customization.** Per DSPOOFFICIAL004's spec note (個案), DSP accepts your invoice data unconditionally, but it only becomes *visible inside the ERP* after Digiwin performs per-customer integration work. If invoices appear to sync successfully but the ERP team can't see them, this is why — confirm the customization with your Digiwin contact before debugging your own code.
147
+
147
148
  ### `order_status` enum
148
149
 
149
150
  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:
@@ -219,6 +220,20 @@ end
219
220
  > - Replying `200 OK` within 30 seconds (DSP will retry and may eventually block your endpoint if too many calls fail)
220
221
  > - **Idempotency by `form_no` / `invoice_number` / etc. on your side** — DSP may retry the same event
221
222
 
223
+ ### Built-in retry (read before stacking job retries)
224
+
225
+ Every `Client#post` already retries transparently inside Faraday:
226
+
227
+ | Setting | Value |
228
+ |---|---|
229
+ | Attempts | up to 4 (1 original + max 3 retries) |
230
+ | Triggers | HTTP 429, 500, 502, 503, 504, connection failures |
231
+ | Backoff | exponential — ~0.5s, ~1s, ~2s between attempts, ±50% jitter |
232
+
233
+ So one `Resources::Order.create` call can take up to ~`4 × timeout + 3.5s` in the worst case (default `timeout` 10s → ~44s). **Size your job timeouts and queue latency budgets accordingly** — if you also add `retry_on` in ActiveJob/Sidekiq (recommended for `RateLimitError`, which DSP signals via the envelope and the gem does *not* retry internally), the two layers multiply.
234
+
235
+ The built-in retry covers transport-level blips; envelope-level "retry later" signals (`Processing:資料處理中`, `SalesNotCreate:` etc. → `RateLimitError`) are deliberately left to your job layer, where you control scheduling.
236
+
222
237
  ### Background jobs
223
238
 
224
239
  The gem is synchronous on purpose. Wrap calls in your own job runner:
@@ -265,6 +280,32 @@ rescue DigiwinDsp::RateLimitError, DigiwinDsp::ServerError
265
280
  end
266
281
  ```
267
282
 
283
+ ## Troubleshooting / FAQ
284
+
285
+ **"My request succeeded with HTTP 200 but raised an exception?"**
286
+ That's DSP's design — application failures come back as HTTP 200 with `Status:"Failure"` in the body. The gem parses the envelope and raises the matching typed exception. Trust the exception, not the HTTP status.
287
+
288
+ **`AuthenticationError: DSP 序號驗證失敗`**
289
+ Your `DSP-api-key` is wrong, expired, or for the other environment (UAT keys don't work on production and vice versa). Note this arrives as HTTP 200, not 401.
290
+
291
+ **`RateLimitError: ...SalesNotCreate:銷貨單未成立`** (invoice sync)
292
+ The ERP hasn't converted the order into a sales document yet — this is a timing issue, not a bug. Retry later (the exception type is retryable by design). If it persists for hours, ask your Digiwin contact whether order conversion is running.
293
+
294
+ **`ValidationError: ...Shipped:訂單已出貨,不可取消`** (cancel)
295
+ Permanent — the order left the warehouse. Don't retry; surface to your support flow instead.
296
+
297
+ **`ValidationError: ...WrongStatus:order_status錯誤,請固定給N(...)`**
298
+ You sent the wrong `order_status` for that endpoint. DSP's message tells you the expected value; or just use `DigiwinDsp::Enums::OrderStatus` constants.
299
+
300
+ **`DuplicateRequestError` on a brand-new order**
301
+ DSP dedupes on `form_no + platform_id` forever — including orders created in earlier tests. Generate unique `form_no` values per environment.
302
+
303
+ **Inventory webhook never arrives**
304
+ Webhook delivery requires (1) a successful `WebhookSubscription.create` for that exact `action`, (2) an HTTPS endpoint answering `200` within 30s, and (3) the ERP actually emitting the event. Check all three, in that order.
305
+
306
+ **Invoices sync but the ERP team can't see them**
307
+ See the invoice caveat above — DSPOOFFICIAL004 requires per-customer ERP customization (個案) before invoice data is visible in the ERP.
308
+
268
309
  ## Custom `digi_header`
269
310
 
270
311
  By default the gem **omits `digi_header`** from the request body (it's only required for certain custom Digiwin integrations). If your DSP setup expects one, pass it through:
@@ -132,11 +132,25 @@ module DigiwinDsp
132
132
  return nil if exec["code"].to_s == "0"
133
133
 
134
134
  { message: exec["description"].to_s, code: exec["code"] }
135
- elsif body["Status"].to_s.casecmp("failure").zero?
135
+ elsif body.key?("Status")
136
+ return nil unless body["Status"].to_s.casecmp("failure").zero?
137
+
136
138
  { message: body["Message"].to_s, code: body["Status"] }
139
+ else
140
+ warn_unknown_envelope(body)
141
+ nil
137
142
  end
138
143
  end
139
144
 
145
+ # Neither known envelope. If DSP ships a third shape, failures would
146
+ # otherwise pass through as "success" silently — leave a trace.
147
+ def warn_unknown_envelope(body)
148
+ @configuration.logger.warn(
149
+ "digiwin_dsp: response matched no known envelope shape " \
150
+ "(keys: #{body.keys.inspect}); passing body through unchanged"
151
+ )
152
+ end
153
+
140
154
  def classify_envelope_failure(message, code:, body:)
141
155
  klass = ENVELOPE_FAILURE_MAP.find { |regex, _| regex.match?(message) }&.last || Error
142
156
  klass.new(message, code: code, dsp_message: message, request_id: body["request_id"], http_status: 200)
@@ -21,13 +21,12 @@ module DigiwinDsp
21
21
  production: "https://digiwindsp.digiwin.com/DSP/api/webhook"
22
22
  }.freeze
23
23
 
24
- attr_accessor :api_key, :api_secret, :platform_id, :environment, :logger,
24
+ attr_accessor :api_key, :platform_id, :environment, :logger,
25
25
  :timeout, :open_timeout, :allowed_hosts
26
26
  attr_writer :base_url, :webhook_base_url
27
27
 
28
28
  def initialize
29
29
  @api_key = ENV["DIGIWIN_DSP_API_KEY"]
30
- @api_secret = ENV["DIGIWIN_DSP_API_SECRET"]
31
30
  @platform_id = ENV["DIGIWIN_DSP_PLATFORM_ID"]
32
31
  @environment = ENV.fetch("DIGIWIN_DSP_ENV") { "sandbox" }.to_sym
33
32
  @base_url = ENV["DIGIWIN_DSP_BASE_URL"]
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DigiwinDsp
4
+ # DSP wire-format code tables as Ruby constants, so callers write
5
+ # `Enums::PayType::CREDIT_CARD` instead of a bare "9104".
6
+ #
7
+ # Source of truth: docs/dsp-specs/*.yaml (see docs/dsp-api-spec.md for the
8
+ # readable digest). The gem deliberately does NOT validate these values
9
+ # client-side — DSP rejects unknown codes with `WrongStatus:` →
10
+ # `ValidationError`. The `ALL` arrays exist for caller-side checks
11
+ # (e.g. dropdowns, model validations) if you want them.
12
+ module Enums
13
+ # request_detail.order_status — fixed per endpoint (live-verified).
14
+ module OrderStatus
15
+ CANCEL = "2" # Resources::Cancellation
16
+ NEW_ORDER = "3" # Resources::Order
17
+ INVOICE = "5" # Resources::Invoice
18
+ RETURN = "7" # Resources::Return
19
+
20
+ ALL = [CANCEL, NEW_ORDER, INVOICE, RETURN].freeze
21
+ end
22
+
23
+ # request_detail.pay_type on Resources::Order (DSPOOFFICIAL001:163-195).
24
+ module PayType
25
+ OTHER = "9100" # 其他收款方式
26
+ JKO_PAY = "9101" # 街口支付
27
+ CVS_COD = "9102" # 超商取貨付款
28
+ GOOGLE_PAY = "9103"
29
+ CREDIT_CARD = "9104" # 信用卡一次付款
30
+ CASH_ON_DELIVERY = "9105" # 貨到付款
31
+ AFTEE = "9106" # AFTEE 先享後付
32
+ APPLE_PAY = "9107"
33
+ ATM = "9108" # ATM 付款
34
+ CREDIT_CARD_INSTALLMENT = "9109" # 信用卡分期付款
35
+ EASY_WALLET = "9110" # 悠遊付 (EasyWallet app — distinct from 9118 悠遊卡)
36
+ LINE_PAY = "9111"
37
+ PAYPAL_EXPRESS = "9112"
38
+ FREE_CHECKOUT = "9113" # 免費結帳
39
+ CVS_PAYMENT_CODE = "9114" # 超商代碼繳費
40
+ POS_CHECKOUT = "9115" # POS結帳
41
+ ZINGALA = "9116" # Zingala 零卡分期付款
42
+ CASH = "9117" # 現金
43
+ EASYCARD = "9118" # 悠遊卡 (physical EasyCard)
44
+ IPASS = "9119" # 一卡通
45
+ ICASH_CARD = "9120" # 愛金卡
46
+ TAIWAN_PAY = "9121" # 台灣 Pay
47
+ PI_WALLET = "9122" # Pi 錢包
48
+ OPAY = "9123" # 歐付寶
49
+ WECHAT_PAY = "9124" # 微信
50
+ PX_PAY = "9125" # 全支付
51
+ ICASH_PAY = "9126" # iCashPay
52
+ PLUS_PAY = "9127" # 全盈支付
53
+ ALIPAY = "9128" # 支付寶
54
+ TAISHIN_PAY = "9129" # 台新 Pay
55
+ COD_CREDIT_CARD = "9130" # 貨到信用卡一次付款
56
+
57
+ ALL = [OTHER, JKO_PAY, CVS_COD, GOOGLE_PAY, CREDIT_CARD, CASH_ON_DELIVERY,
58
+ AFTEE, APPLE_PAY, ATM, CREDIT_CARD_INSTALLMENT, EASY_WALLET,
59
+ LINE_PAY, PAYPAL_EXPRESS, FREE_CHECKOUT, CVS_PAYMENT_CODE,
60
+ POS_CHECKOUT, ZINGALA, CASH, EASYCARD, IPASS, ICASH_CARD,
61
+ TAIWAN_PAY, PI_WALLET, OPAY, WECHAT_PAY, PX_PAY, ICASH_PAY,
62
+ PLUS_PAY, ALIPAY, TAISHIN_PAY, COD_CREDIT_CARD].freeze
63
+ end
64
+
65
+ # request_detail.shipping_type on Resources::Order (DSPOOFFICIAL001:186-200).
66
+ module ShippingType
67
+ OTHER = "9100" # 其他取貨方式
68
+ INTERNATIONAL = "9101" # 海外宅配
69
+ HOME_DELIVERY_COD = "9102" # 宅配貨到付款
70
+ STORE_PICKUP_PAID = "9103" # 付款後門市自取
71
+ HOME_DELIVERY_PAID = "9104" # 宅配(含離島)已付款只取貨
72
+ CVS_PICKUP_PAID = "9105" # 付款後超商取貨
73
+ CVS_PICKUP_COD = "9106" # 超商取貨付款
74
+ HOME_DELIVERY_CASH = "9107" # 宅配(含離島)貨到付現
75
+ HOME_DELIVERY_CARD = "9108" # 宅配(含離島)貨到刷卡
76
+
77
+ ALL = [OTHER, INTERNATIONAL, HOME_DELIVERY_COD, STORE_PICKUP_PAID,
78
+ HOME_DELIVERY_PAID, CVS_PICKUP_PAID, CVS_PICKUP_COD,
79
+ HOME_DELIVERY_CASH, HOME_DELIVERY_CARD].freeze
80
+ end
81
+
82
+ # request_detail.invoice_status on Resources::Invoice (DSPOOFFICIAL004:110-122).
83
+ module InvoiceStatus
84
+ ISSUED = "1" # 開立
85
+ VOIDED = "2" # 作廢
86
+ ALLOWANCE = "3" # 折讓
87
+ CANCELLED = "4" # 註銷
88
+ ALLOWANCE_VOIDED = "5" # 折讓作廢
89
+
90
+ ALL = [ISSUED, VOIDED, ALLOWANCE, CANCELLED, ALLOWANCE_VOIDED].freeze
91
+ end
92
+
93
+ # request_detail.invoice_type on Resources::Invoice (DSPOOFFICIAL004:123-140).
94
+ module InvoiceType
95
+ DUPLICATE = "1" # 二聯式
96
+ TRIPLICATE = "2" # 三聯式
97
+ DUPLICATE_REGISTER = "3" # 二聯式收銀機發票
98
+ TRIPLICATE_REGISTER = "4" # 三聯式收銀機發票
99
+ COMPUTER = "5" # 電子計算機發票
100
+ EXEMPT = "6" # 免用統一發票
101
+ E_INVOICE = "7" # 電子發票 — modern default in Taiwan
102
+ CHINA_VAT_SPECIAL = "A" # 增值稅專用發票
103
+ CHINA_GENERAL = "B" # 普通發票
104
+ CHINA_EXEMPT = "C" # 免用發票
105
+
106
+ ALL = [DUPLICATE, TRIPLICATE, DUPLICATE_REGISTER, TRIPLICATE_REGISTER,
107
+ COMPUTER, EXEMPT, E_INVOICE, CHINA_VAT_SPECIAL, CHINA_GENERAL,
108
+ CHINA_EXEMPT].freeze
109
+ end
110
+
111
+ # E-invoice carrier codes (DSPOOFFICIAL004:167-176). ⚠️ Field name varies:
112
+ # `carrier_type` on Resources::Invoice, `carrier_code` on Resources::Order
113
+ # and the inbound Webhooks::InvoiceUpdate payload.
114
+ module CarrierType
115
+ IPASS = "1H0001" # 一卡通
116
+ EASYCARD = "1K0001" # 悠遊卡
117
+ ICASH = "2G0001"
118
+ MOBILE_BARCODE = "3J0002" # 手機條碼 — most common
119
+ CITIZEN_CERT = "CQ0001" # 自然人憑證
120
+
121
+ ALL = [IPASS, EASYCARD, ICASH, MOBILE_BARCODE, CITIZEN_CERT].freeze
122
+ end
123
+
124
+ # request_detail.is_pay on Resources::Invoice (DSPOOFFICIAL004:189-195).
125
+ module IsPay
126
+ UNPAID = "0"
127
+ PAID = "1"
128
+
129
+ ALL = [UNPAID, PAID].freeze
130
+ end
131
+
132
+ # spec_list[].update_mode on inbound Webhooks::InventoryUpdate
133
+ # (DSPOOFFICIAL100). "adjust" requires per-customer ERP customization.
134
+ module UpdateMode
135
+ TOTAL = "total" # stock is the new total
136
+ ADJUST = "adjust" # stock is a delta (can be negative)
137
+
138
+ ALL = [TOTAL, ADJUST].freeze
139
+ end
140
+
141
+ # distributor_code on inbound Webhooks::LogisticsUpdate (DSPOOFFICIAL100).
142
+ # Spec lists only these two; handle unknown carriers defensively.
143
+ module DistributorCode
144
+ HCT = "HCT" # 新竹倉儲
145
+ CAT = "CAT" # 統一速達(黑貓)
146
+
147
+ ALL = [HCT, CAT].freeze
148
+ end
149
+ end
150
+ end
@@ -12,11 +12,9 @@ module DigiwinDsp
12
12
  class WebhookSubscription
13
13
  PATH = "/v1/webhook"
14
14
  DEFAULT_PROD = "OFFICIALWEBSITE"
15
- ACTIONS = %w[
16
- product/inventory_update
17
- wms/logistics/package/update
18
- invoice/update
19
- ].freeze
15
+ # Single source of truth lives in Webhooks::ACTION_REGISTRY — what you
16
+ # can subscribe to is exactly what the gem can parse.
17
+ ACTIONS = Webhooks::ACTION_REGISTRY.keys.freeze
20
18
  ADDRESS_MAX_LENGTH = 500
21
19
 
22
20
  def self.create(action:, address:, platform_id: nil, prod: DEFAULT_PROD)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DigiwinDsp
4
- VERSION = "0.3.1"
4
+ VERSION = "0.4.1"
5
5
  end
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.1
4
+ version: 0.4.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-06-12 00:00:00.000000000 Z
11
+ date: 2026-06-17 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/enums.rb
71
72
  - lib/digiwin_dsp/resources/base.rb
72
73
  - lib/digiwin_dsp/resources/cancellation.rb
73
74
  - lib/digiwin_dsp/resources/invoice.rb