bootpay 1.2.0 → 3.0.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/.gitignore +8 -9
- data/.rspec +2 -0
- data/CHANGELOG.md +63 -21
- data/CODE_OF_CONDUCT.md +1 -1
- data/Gemfile +2 -4
- data/LICENSE.txt +1 -1
- data/README.md +309 -196
- data/Rakefile +3 -3
- data/bin/console +1 -1
- data/bootpay.gemspec +23 -20
- data/lib/bootpay/bootpay-rest-client.rb +51 -0
- data/lib/bootpay/concern/authenticate.rb +69 -0
- data/lib/bootpay/concern/cash_receipt.rb +83 -0
- data/lib/bootpay/concern/easy.rb +18 -0
- data/lib/bootpay/concern/escrow.rb +25 -0
- data/lib/bootpay/concern/payment.rb +126 -0
- data/lib/bootpay/concern/reseller.rb +97 -0
- data/lib/bootpay/concern/rest.rb +56 -0
- data/lib/bootpay/concern/sdk.rb +52 -0
- data/lib/bootpay/concern/seller.rb +15 -0
- data/lib/bootpay/concern/service.rb +15 -0
- data/lib/bootpay/concern/subscription.rb +211 -0
- data/lib/bootpay/concern/token.rb +33 -0
- data/lib/bootpay/concern/user_token.rb +23 -0
- data/lib/bootpay/concern/wallet.rb +20 -0
- data/lib/bootpay/concern/webhook.rb +18 -0
- data/lib/bootpay/concern.rb +35 -0
- data/lib/bootpay-backend-ruby.rb +6 -0
- data/lib/bootpay.rb +10 -66
- data/lib/bootpay_storage/bootpay-storage-rest-client.rb +46 -0
- data/lib/bootpay_storage/concern/csv.rb +18 -0
- data/lib/bootpay_storage/concern/image.rb +30 -0
- data/lib/bootpay_storage/concern/rest.rb +176 -0
- data/lib/bootpay_storage/concern/token.rb +9 -0
- data/lib/bootpay_storage/concern.rb +12 -0
- data/lib/bootpay_storage/response.rb +14 -0
- data/lib/bootpay_store/bootpay-store-rest-client.rb +47 -0
- data/lib/bootpay_store/concern/alimtalk_message.rb +67 -0
- data/lib/bootpay_store/concern/alimtalk_official.rb +63 -0
- data/lib/bootpay_store/concern/alimtalk_optout.rb +72 -0
- data/lib/bootpay_store/concern/alimtalk_send.rb +83 -0
- data/lib/bootpay_store/concern/alimtalk_sender.rb +105 -0
- data/lib/bootpay_store/concern/alimtalk_template.rb +215 -0
- data/lib/bootpay_store/concern/alimtalk_webhook.rb +84 -0
- data/lib/bootpay_store/concern/invoice.rb +102 -0
- data/lib/bootpay_store/concern/mall_setting.rb +385 -0
- data/lib/bootpay_store/concern/order.rb +74 -0
- data/lib/bootpay_store/concern/order_subscription.rb +391 -0
- data/lib/bootpay_store/concern/payment.rb +119 -0
- data/lib/bootpay_store/concern/product.rb +175 -0
- data/lib/bootpay_store/concern/rest.rb +128 -0
- data/lib/bootpay_store/concern/store.rb +31 -0
- data/lib/bootpay_store/concern/supervisor.rb +211 -0
- data/lib/bootpay_store/concern/token.rb +24 -0
- data/lib/bootpay_store/concern/user.rb +325 -0
- data/lib/bootpay_store/concern/user_group.rb +221 -0
- data/lib/bootpay_store/concern/webhook.rb +17 -0
- data/lib/bootpay_store/concern.rb +45 -0
- data/lib/bootpay_store/response.rb +14 -0
- data/lib/version.rb +9 -0
- metadata +77 -49
- data/.DS_Store +0 -0
- data/.env.example +0 -23
- data/lib/.DS_Store +0 -0
- data/lib/bootpay/.DS_Store +0 -0
- data/lib/bootpay/authentication.rb +0 -61
- data/lib/bootpay/automatic_transfer.rb +0 -56
- data/lib/bootpay/billing.rb +0 -157
- data/lib/bootpay/cancel.rb +0 -29
- data/lib/bootpay/cash_receipt.rb +0 -77
- data/lib/bootpay/commerce/cart.rb +0 -20
- data/lib/bootpay/commerce/category.rb +0 -39
- data/lib/bootpay/commerce/commerce_resource.rb +0 -196
- data/lib/bootpay/commerce/coupon.rb +0 -41
- data/lib/bootpay/commerce/invoice.rb +0 -46
- data/lib/bootpay/commerce/order.rb +0 -61
- data/lib/bootpay/commerce/order_cancel.rb +0 -52
- data/lib/bootpay/commerce/order_subscription.rb +0 -117
- data/lib/bootpay/commerce/order_subscription_adjustment.rb +0 -29
- data/lib/bootpay/commerce/order_subscription_bill.rb +0 -50
- data/lib/bootpay/commerce/order_subscription_request.rb +0 -60
- data/lib/bootpay/commerce/point.rb +0 -36
- data/lib/bootpay/commerce/product.rb +0 -63
- data/lib/bootpay/commerce/store.rb +0 -21
- data/lib/bootpay/commerce/user.rb +0 -75
- data/lib/bootpay/commerce/user_group.rb +0 -70
- data/lib/bootpay/easy.rb +0 -25
- data/lib/bootpay/escrow.rb +0 -24
- data/lib/bootpay/link.rb +0 -60
- data/lib/bootpay/naverpay.rb +0 -17
- data/lib/bootpay/payment_resource.rb +0 -31
- data/lib/bootpay/reseller.rb +0 -12
- data/lib/bootpay/rest.rb +0 -46
- data/lib/bootpay/submit.rb +0 -20
- data/lib/bootpay/token.rb +0 -33
- data/lib/bootpay/verification.rb +0 -55
- data/lib/bootpay/version.rb +0 -25
- data/lib/bootpay/wallet.rb +0 -56
- data/lib/bootpay_commerce.rb +0 -152
- /data/lib/{response.rb → bootpay/response.rb} +0 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
module BootpayStore::Concern::OrderSubscription
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
included do
|
|
4
|
+
# 계약된 구독정보를 가져온다
|
|
5
|
+
# Comment by GOSOMI
|
|
6
|
+
# @date: 2025-06-20
|
|
7
|
+
# @date: 26-08-14 limit 인자 추가. 서버(v1/order_subscriptions_controller#index)는
|
|
8
|
+
# `params[:limit].presence || 20` 으로 이미 받고 있었는데 SDK 가 안 보내고 있었다.
|
|
9
|
+
# 기본값 20 은 서버 기본과 같아 기존 호출 결과가 바뀌지 않는다.
|
|
10
|
+
# ⚠️ 날짜 키는 search_date_from/to (또는 s_at/e_at). orders 의 css_at/cse_at 와 다르다.
|
|
11
|
+
# @date: 26-08-26 order_number 인자 추가. 서버(#index)가 params[:order_number] 로 주문번호 역조회를
|
|
12
|
+
# 지원하는데 SDK 에 인자가 없어 주문번호로 구독을 찾을 수 없었다.
|
|
13
|
+
def order_subscriptions(page: 1, limit: 20, keyword: nil, search_date_from: nil, search_date_to: nil,
|
|
14
|
+
request_type: nil, user_group_id: nil, status: nil, user_id: nil,
|
|
15
|
+
order_number: nil, idempotency_key: nil)
|
|
16
|
+
request(
|
|
17
|
+
uri: 'order_subscriptions',
|
|
18
|
+
method: :get,
|
|
19
|
+
headers: {
|
|
20
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
21
|
+
'Bootpay-Role' => 'user'
|
|
22
|
+
},
|
|
23
|
+
params: {
|
|
24
|
+
page: page,
|
|
25
|
+
limit: limit,
|
|
26
|
+
keyword: keyword,
|
|
27
|
+
search_date_from: search_date_from,
|
|
28
|
+
search_date_to: search_date_to,
|
|
29
|
+
request_type: request_type,
|
|
30
|
+
user_group_id: user_group_id,
|
|
31
|
+
status: status,
|
|
32
|
+
user_id: user_id,
|
|
33
|
+
order_number: order_number
|
|
34
|
+
}.compact
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# 구독 상세를 조회한다
|
|
39
|
+
def order_subscription_detail(order_subscription_id:, idempotency_key: nil)
|
|
40
|
+
request(
|
|
41
|
+
uri: "order_subscriptions/#{order_subscription_id}",
|
|
42
|
+
method: :get,
|
|
43
|
+
headers: {
|
|
44
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
45
|
+
'Bootpay-Role' => 'user'
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# ─────────────────────────────────────────────────────────────
|
|
51
|
+
# 구독 계약변경 · 조정항목 · 빌 조회 (@comment_by Claude (alfred) / @date: 26-08-14)
|
|
52
|
+
# ─────────────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
# 구독 계약 내용을 변경한다 (PUT /v1/order_subscriptions/:id)
|
|
55
|
+
# 바뀐 값만 보내면 된다 (나머지는 서버가 그대로 유지).
|
|
56
|
+
#
|
|
57
|
+
# price 는 회차별 결제 금액의 **기준금액**이다. 바꾸면 결제예정(READY) 회차의 청구액이
|
|
58
|
+
# 즉시 다시 계산되고, 이후 회차도 이 금액으로 만들어진다. 이미 결제된 회차는 그대로다.
|
|
59
|
+
# 0 이하는 받지 않는다. 특정 회차만 가감하려면 order_subscription_adjustment_create 를 쓴다.
|
|
60
|
+
# (관리자 화면의 금액 변경과 같은 구현을 탄다) (@date: 26-08-24)
|
|
61
|
+
#
|
|
62
|
+
# memo 는 변경이력(SUBSCRIPTION_ACTION_UPDATE)에 남길 사유다. 서버가 읽고 있었는데
|
|
63
|
+
# SDK 에 인자가 없었다. (@date: 26-08-26)
|
|
64
|
+
def order_subscription_update(order_subscription_id:, product_id: nil, product_option_id: nil,
|
|
65
|
+
order_name: nil, total_subscription_duration: nil, quantity: nil,
|
|
66
|
+
address_id: nil, username: nil, phone: nil, email: nil,
|
|
67
|
+
use_free_trial: nil, free_trial_day: nil,
|
|
68
|
+
service_start_at: nil, service_end_at: nil, price: nil,
|
|
69
|
+
memo: nil, idempotency_key: nil)
|
|
70
|
+
request(
|
|
71
|
+
uri: "order_subscriptions/#{order_subscription_id}",
|
|
72
|
+
method: :put,
|
|
73
|
+
headers: {
|
|
74
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
75
|
+
'Bootpay-Role' => 'supervisor'
|
|
76
|
+
},
|
|
77
|
+
payload: {
|
|
78
|
+
product_id: product_id,
|
|
79
|
+
product_option_id: product_option_id,
|
|
80
|
+
order_name: order_name,
|
|
81
|
+
total_subscription_duration: total_subscription_duration,
|
|
82
|
+
quantity: quantity,
|
|
83
|
+
address_id: address_id,
|
|
84
|
+
username: username,
|
|
85
|
+
phone: phone,
|
|
86
|
+
email: email,
|
|
87
|
+
use_free_trial: use_free_trial,
|
|
88
|
+
free_trial_day: free_trial_day,
|
|
89
|
+
service_start_at: service_start_at,
|
|
90
|
+
service_end_at: service_end_at,
|
|
91
|
+
price: price,
|
|
92
|
+
memo: memo
|
|
93
|
+
}.compact
|
|
94
|
+
)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# 가감산 조정항목을 추가한다 (POST /v1/order_subscriptions/:id/adjustments)
|
|
98
|
+
# ⚠️ /adjustments 한 경로에 POST·PUT·DELETE 세 동사가 걸려 있다. method 를 반드시 명시할 것.
|
|
99
|
+
# type 미전달 시 서버가 price>0 이면 SETUP_PRICE, 아니면 PERIOD_DISCOUNT 로 자동 판정한다.
|
|
100
|
+
#
|
|
101
|
+
# 회차 지정 방법 3가지 (아래로 갈수록 넓다):
|
|
102
|
+
# - duration: 5 → 5회차 한 건만
|
|
103
|
+
# - duration_from: 3, duration_to: 7 → 3~7회차 각각 한 건씩 (총 5건)
|
|
104
|
+
# - duration_from: 3, is_unlimited: true → 3회차부터 계약 끝까지 (레코드는 1건, duration_to 는 무시)
|
|
105
|
+
# 상한은 계약 총회차이며, 총회차가 무제한인 계약은 60회차까지다.
|
|
106
|
+
# 이미 결제가 끝난 회차는 거절된다. 범위 중 한 회차라도 최종 금액이 음수면 전부 거절된다(부분 반영 없음).
|
|
107
|
+
def order_subscription_adjustment_create(order_subscription_id:, name: nil, price: 0, duration: 1,
|
|
108
|
+
tax_free_price: 0, type: nil, duration_from: nil,
|
|
109
|
+
duration_to: nil, is_unlimited: nil, idempotency_key: nil)
|
|
110
|
+
request(
|
|
111
|
+
uri: "order_subscriptions/#{order_subscription_id}/adjustments",
|
|
112
|
+
method: :post,
|
|
113
|
+
headers: {
|
|
114
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
115
|
+
'Bootpay-Role' => 'supervisor'
|
|
116
|
+
},
|
|
117
|
+
payload: {
|
|
118
|
+
name: name,
|
|
119
|
+
price: price,
|
|
120
|
+
duration: duration,
|
|
121
|
+
tax_free_price: tax_free_price,
|
|
122
|
+
type: type,
|
|
123
|
+
duration_from: duration_from,
|
|
124
|
+
duration_to: duration_to,
|
|
125
|
+
is_unlimited: is_unlimited
|
|
126
|
+
}.compact
|
|
127
|
+
)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# 특정 회차의 조정항목을 통째로 교체한다 (PUT /v1/order_subscriptions/:id/adjustments)
|
|
131
|
+
# adjustments 는 배열. 서버는 duration(회차) 단위로 갈아끼운다.
|
|
132
|
+
def order_subscription_adjustment_update(order_subscription_id:, duration: 1, adjustments: [],
|
|
133
|
+
idempotency_key: nil)
|
|
134
|
+
request(
|
|
135
|
+
uri: "order_subscriptions/#{order_subscription_id}/adjustments",
|
|
136
|
+
method: :put,
|
|
137
|
+
headers: {
|
|
138
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
139
|
+
'Bootpay-Role' => 'supervisor'
|
|
140
|
+
},
|
|
141
|
+
payload: {
|
|
142
|
+
duration: duration,
|
|
143
|
+
adjustments: adjustments
|
|
144
|
+
}.compact
|
|
145
|
+
)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# 조정항목을 삭제한다 (DELETE /v1/order_subscriptions/:id/adjustments)
|
|
149
|
+
def order_subscription_adjustment_delete(order_subscription_id:, order_subscription_adjustment_id:,
|
|
150
|
+
idempotency_key: nil)
|
|
151
|
+
request(
|
|
152
|
+
uri: "order_subscriptions/#{order_subscription_id}/adjustments",
|
|
153
|
+
method: :delete,
|
|
154
|
+
headers: {
|
|
155
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
156
|
+
'Bootpay-Role' => 'supervisor'
|
|
157
|
+
},
|
|
158
|
+
payload: { order_subscription_adjustment_id: order_subscription_adjustment_id }
|
|
159
|
+
)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# 구독 빌(회차) 목록을 조회한다 (GET /v1/order_subscription_bills)
|
|
163
|
+
# ⚠️ 경로가 order_subscription_bills — 언더스코어다 (하이픈 아님).
|
|
164
|
+
def order_subscription_bill_list(order_subscription_id: nil, page: 1, limit: 20, status: nil,
|
|
165
|
+
idempotency_key: nil)
|
|
166
|
+
request(
|
|
167
|
+
uri: 'order_subscription_bills',
|
|
168
|
+
method: :get,
|
|
169
|
+
headers: {
|
|
170
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
171
|
+
'Bootpay-Role' => 'user'
|
|
172
|
+
},
|
|
173
|
+
params: {
|
|
174
|
+
order_subscription_id: order_subscription_id,
|
|
175
|
+
page: page,
|
|
176
|
+
limit: limit,
|
|
177
|
+
status: status
|
|
178
|
+
}.compact
|
|
179
|
+
)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# ─────────────────────────────────────────────────────────────
|
|
183
|
+
# 구독 진행중 요청 (requests/ing) (@comment_by Claude (alfred) / @date: 26-08-14)
|
|
184
|
+
#
|
|
185
|
+
# ⚠️ 동사가 제각각이다. routes 정본 기준:
|
|
186
|
+
# pause · purchase · termination · transfer → POST
|
|
187
|
+
# resume → PUT ← 이것만 다르다
|
|
188
|
+
# calculate_termination_fee → GET
|
|
189
|
+
# "오타겠지" 하며 resume 을 POST 로 바꾸지 말 것.
|
|
190
|
+
#
|
|
191
|
+
# ⚠️ supervisor_request_order_subscription_* (PUT order_subscriptions/:id/*) 와는 다른 라우트다.
|
|
192
|
+
# 이쪽은 구매자가 "요청"을 올리는 면, 저쪽은 관리자가 즉시 실행하는 면.
|
|
193
|
+
# ─────────────────────────────────────────────────────────────
|
|
194
|
+
|
|
195
|
+
# 구독 일시중지 요청 (POST /v1/order_subscriptions/requests/ing/pause)
|
|
196
|
+
def order_subscription_requests_ing_pause(order_subscription_id:, reason: nil, paused_at: nil,
|
|
197
|
+
expected_resume_at: nil, idempotency_key: nil)
|
|
198
|
+
request(
|
|
199
|
+
uri: 'order_subscriptions/requests/ing/pause',
|
|
200
|
+
method: :post,
|
|
201
|
+
headers: {
|
|
202
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
203
|
+
'Bootpay-Role' => 'user'
|
|
204
|
+
},
|
|
205
|
+
payload: {
|
|
206
|
+
order_subscription_id: order_subscription_id,
|
|
207
|
+
reason: reason,
|
|
208
|
+
paused_at: paused_at,
|
|
209
|
+
expected_resume_at: expected_resume_at
|
|
210
|
+
}.compact
|
|
211
|
+
)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# 구독 재개 요청 (PUT /v1/order_subscriptions/requests/ing/resume)
|
|
215
|
+
# ⚠️ requests/ing 계열 중 유일하게 PUT 이다.
|
|
216
|
+
def order_subscription_requests_ing_resume(order_subscription_id:, reason: nil, idempotency_key: nil)
|
|
217
|
+
request(
|
|
218
|
+
uri: 'order_subscriptions/requests/ing/resume',
|
|
219
|
+
method: :put,
|
|
220
|
+
headers: {
|
|
221
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
222
|
+
'Bootpay-Role' => 'user'
|
|
223
|
+
},
|
|
224
|
+
payload: {
|
|
225
|
+
order_subscription_id: order_subscription_id,
|
|
226
|
+
reason: reason
|
|
227
|
+
}.compact
|
|
228
|
+
)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# 중도인수 요청 (POST /v1/order_subscriptions/requests/ing/purchase)
|
|
232
|
+
def order_subscription_requests_ing_purchase(order_subscription_id:, price: nil, tax_free_price: nil,
|
|
233
|
+
reason: nil, idempotency_key: nil)
|
|
234
|
+
request(
|
|
235
|
+
uri: 'order_subscriptions/requests/ing/purchase',
|
|
236
|
+
method: :post,
|
|
237
|
+
headers: {
|
|
238
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
239
|
+
'Bootpay-Role' => 'user'
|
|
240
|
+
},
|
|
241
|
+
payload: {
|
|
242
|
+
order_subscription_id: order_subscription_id,
|
|
243
|
+
price: price,
|
|
244
|
+
tax_free_price: tax_free_price,
|
|
245
|
+
reason: reason
|
|
246
|
+
}.compact
|
|
247
|
+
)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# 중도해지 요청 (POST /v1/order_subscriptions/requests/ing/termination)
|
|
251
|
+
def order_subscription_requests_ing_termination(order_subscription_id:, order_number: nil, reason: nil,
|
|
252
|
+
termination_fee: nil, last_bill_refund_price: nil,
|
|
253
|
+
final_fee: nil, service_end_at: nil, idempotency_key: nil)
|
|
254
|
+
request(
|
|
255
|
+
uri: 'order_subscriptions/requests/ing/termination',
|
|
256
|
+
method: :post,
|
|
257
|
+
headers: {
|
|
258
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
259
|
+
'Bootpay-Role' => 'user'
|
|
260
|
+
},
|
|
261
|
+
payload: {
|
|
262
|
+
order_subscription_id: order_subscription_id,
|
|
263
|
+
order_number: order_number,
|
|
264
|
+
reason: reason,
|
|
265
|
+
termination_fee: termination_fee,
|
|
266
|
+
last_bill_refund_price: last_bill_refund_price,
|
|
267
|
+
final_fee: final_fee,
|
|
268
|
+
service_end_at: service_end_at
|
|
269
|
+
}.compact
|
|
270
|
+
)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# 구독 이전/승계 요청 (POST /v1/order_subscriptions/requests/ing/transfer)
|
|
274
|
+
def order_subscription_requests_ing_transfer(order_subscription_id:, new_user_id: nil, new_username: nil,
|
|
275
|
+
new_user_email: nil, new_user_phone: nil, new_user_address: nil,
|
|
276
|
+
wallet_id: nil, reason: nil, idempotency_key: nil)
|
|
277
|
+
request(
|
|
278
|
+
uri: 'order_subscriptions/requests/ing/transfer',
|
|
279
|
+
method: :post,
|
|
280
|
+
headers: {
|
|
281
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
282
|
+
'Bootpay-Role' => 'user'
|
|
283
|
+
},
|
|
284
|
+
payload: {
|
|
285
|
+
order_subscription_id: order_subscription_id,
|
|
286
|
+
new_user_id: new_user_id,
|
|
287
|
+
new_username: new_username,
|
|
288
|
+
new_user_email: new_user_email,
|
|
289
|
+
new_user_phone: new_user_phone,
|
|
290
|
+
new_user_address: new_user_address,
|
|
291
|
+
wallet_id: wallet_id,
|
|
292
|
+
reason: reason
|
|
293
|
+
}.compact
|
|
294
|
+
)
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# 중도해지 수수료 사전계산 (GET /v1/order_subscriptions/requests/ing/calculate_termination_fee)
|
|
298
|
+
# 해지 요청 전에 얼마가 나오는지 미리 보여줄 때 쓴다.
|
|
299
|
+
def order_subscription_calculate_termination_fee(order_subscription_id:, order_number: nil,
|
|
300
|
+
idempotency_key: nil)
|
|
301
|
+
request(
|
|
302
|
+
uri: 'order_subscriptions/requests/ing/calculate_termination_fee',
|
|
303
|
+
method: :get,
|
|
304
|
+
headers: {
|
|
305
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
306
|
+
'Bootpay-Role' => 'user'
|
|
307
|
+
},
|
|
308
|
+
params: {
|
|
309
|
+
order_subscription_id: order_subscription_id,
|
|
310
|
+
order_number: order_number
|
|
311
|
+
}.compact
|
|
312
|
+
)
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# ─────────────────────────────────────────────────────────────
|
|
316
|
+
# 구독 요청 리소스 (order-subscription-requests) ⚠️ 하이픈 경로
|
|
317
|
+
# 하이픈 경로는 order-subscription-requests 와 user-groups 둘뿐이다.
|
|
318
|
+
# order_subscriptions · order_subscription_bills 는 언더스코어 — 복사해 고칠 때 가장 흔히 틀리는 지점.
|
|
319
|
+
# ─────────────────────────────────────────────────────────────
|
|
320
|
+
|
|
321
|
+
# 구독 변경요청 목록 (GET /v1/order-subscription-requests)
|
|
322
|
+
# project_id 를 주면 supervisor 모드(프로젝트 전체 검색), 없으면 본인 요청만.
|
|
323
|
+
def order_subscription_request_list(project_id: nil, order_subscription_id: nil, page: 1, limit: 20,
|
|
324
|
+
keyword: nil, s_at: nil, e_at: nil, status: nil,
|
|
325
|
+
request_type: nil, user_id: nil, user_group_id: nil,
|
|
326
|
+
idempotency_key: nil)
|
|
327
|
+
request(
|
|
328
|
+
uri: 'order-subscription-requests',
|
|
329
|
+
method: :get,
|
|
330
|
+
headers: {
|
|
331
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
332
|
+
'Bootpay-Role' => project_id.present? ? 'supervisor' : 'user'
|
|
333
|
+
},
|
|
334
|
+
params: {
|
|
335
|
+
project_id: project_id,
|
|
336
|
+
order_subscription_id: order_subscription_id,
|
|
337
|
+
page: page,
|
|
338
|
+
limit: limit,
|
|
339
|
+
keyword: keyword,
|
|
340
|
+
s_at: s_at,
|
|
341
|
+
e_at: e_at,
|
|
342
|
+
status: status,
|
|
343
|
+
request_type: request_type,
|
|
344
|
+
user_id: user_id,
|
|
345
|
+
user_group_id: user_group_id
|
|
346
|
+
}.compact
|
|
347
|
+
)
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
# 구독 변경요청 상세 (GET /v1/order-subscription-requests/:id)
|
|
351
|
+
def order_subscription_request_detail(request_history_id:, project_id: nil, idempotency_key: nil)
|
|
352
|
+
request(
|
|
353
|
+
uri: "order-subscription-requests/#{request_history_id}",
|
|
354
|
+
method: :get,
|
|
355
|
+
headers: {
|
|
356
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
357
|
+
'Bootpay-Role' => project_id.present? ? 'supervisor' : 'user'
|
|
358
|
+
},
|
|
359
|
+
params: { project_id: project_id }.compact
|
|
360
|
+
)
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
# 구독 변경요청 승인/반려 (PUT /v1/order-subscription-requests/:id)
|
|
364
|
+
# ⚠️ 승인과 반려는 별도 액션이 아니다. 라우트는 index/show/update 셋뿐이고
|
|
365
|
+
# approval: 'approve' | 'reject' 파라미터로 갈린다.
|
|
366
|
+
# 서버가 params[:action] 을 Rails 예약어로 쓰기 때문에 키 이름이 approval 이다.
|
|
367
|
+
def order_subscription_request_update(request_history_id:, approval:, reason: nil,
|
|
368
|
+
price: nil, tax_free_price: nil, termination_fee: nil,
|
|
369
|
+
last_bill_refund_price: nil, final_fee: nil, service_end_at: nil,
|
|
370
|
+
idempotency_key: nil)
|
|
371
|
+
request(
|
|
372
|
+
uri: "order-subscription-requests/#{request_history_id}",
|
|
373
|
+
method: :put,
|
|
374
|
+
headers: {
|
|
375
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
376
|
+
'Bootpay-Role' => 'supervisor'
|
|
377
|
+
},
|
|
378
|
+
payload: {
|
|
379
|
+
approval: approval,
|
|
380
|
+
reason: reason,
|
|
381
|
+
price: price,
|
|
382
|
+
tax_free_price: tax_free_price,
|
|
383
|
+
termination_fee: termination_fee,
|
|
384
|
+
last_bill_refund_price: last_bill_refund_price,
|
|
385
|
+
final_fee: final_fee,
|
|
386
|
+
service_end_at: service_end_at
|
|
387
|
+
}.compact
|
|
388
|
+
)
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
module BootpayStore::Concern::Payment
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
included do
|
|
5
|
+
# 주문 취소
|
|
6
|
+
# Comment by GOSOMI
|
|
7
|
+
# @date: 2025-04-04
|
|
8
|
+
def request_order_cancel(idempotency_key: nil, cancel_id: nil, order_number:, cancel_products: nil, cancel_price: nil,
|
|
9
|
+
cancel_tax_free_price: 0, cancel_requester: '시스템', cancel_message: '요청취소', cancel_immediately: false,
|
|
10
|
+
cancel_order_subscription_bills: nil)
|
|
11
|
+
request(
|
|
12
|
+
uri: 'order/cancel',
|
|
13
|
+
headers: {
|
|
14
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
15
|
+
'Bootpay-Role' => 'user'
|
|
16
|
+
},
|
|
17
|
+
payload:
|
|
18
|
+
{
|
|
19
|
+
order_number: order_number,
|
|
20
|
+
request_cancel_parameters: {
|
|
21
|
+
cancel_id: cancel_id,
|
|
22
|
+
cancel_products: cancel_products,
|
|
23
|
+
cancel_order_subscription_bills: cancel_order_subscription_bills,
|
|
24
|
+
cancel_price: cancel_price,
|
|
25
|
+
cancel_tax_free_price: cancel_tax_free_price,
|
|
26
|
+
cancel_requester: cancel_requester,
|
|
27
|
+
cancel_message: cancel_message,
|
|
28
|
+
cancel_immediately: cancel_immediately
|
|
29
|
+
}.compact
|
|
30
|
+
}.compact
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# 주문 취소 요청을 철회한다
|
|
35
|
+
# def request_order_cancel_revoke(idempotency_key: nil, order_cancellation_request_id:)
|
|
36
|
+
# request(
|
|
37
|
+
# uri: "order/cancel/#{order_cancellation_request_id}",
|
|
38
|
+
# method: :delete,
|
|
39
|
+
# headers: {
|
|
40
|
+
# 'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid
|
|
41
|
+
# }
|
|
42
|
+
# )
|
|
43
|
+
# end
|
|
44
|
+
|
|
45
|
+
# (관리자)
|
|
46
|
+
# 주문 취소 요청을 반려처리 한다
|
|
47
|
+
def reject_order_cancel(idempotency_key: nil, order_cancellation_request_id:, message: nil)
|
|
48
|
+
request(
|
|
49
|
+
uri: "order/cancel/#{order_cancellation_request_id}/reject",
|
|
50
|
+
method: :put,
|
|
51
|
+
headers: {
|
|
52
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
53
|
+
'Bootpay-Role' => 'supervisor'
|
|
54
|
+
},
|
|
55
|
+
payload: {
|
|
56
|
+
message: message
|
|
57
|
+
}.compact
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# (관리자)
|
|
62
|
+
# 주문 취소 요청을 승인처리 한다
|
|
63
|
+
# @date: 26-08-14 인자명 통일 — 서버(v1/order/cancel_controller)는 approve/reject/withdraw 셋 다
|
|
64
|
+
# params[:id] 를 order_cancellation_request_id 로 동일하게 취급한다. reject 와 이름이 달라 다른 값처럼
|
|
65
|
+
# 보였던 문제를 order_cancellation_request_id: 로 맞춘다. 구 이름도 계속 받는다(하위호환).
|
|
66
|
+
def approve_order_cancel(idempotency_key: nil, order_cancellation_request_id: nil,
|
|
67
|
+
order_cancellation_request_history_id: nil, message: nil)
|
|
68
|
+
cancellation_id = order_cancellation_request_id.presence || order_cancellation_request_history_id
|
|
69
|
+
request(
|
|
70
|
+
uri: "order/cancel/#{cancellation_id}/approve",
|
|
71
|
+
method: :put,
|
|
72
|
+
headers: {
|
|
73
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
74
|
+
'Bootpay-Role' => 'supervisor'
|
|
75
|
+
},
|
|
76
|
+
payload: {
|
|
77
|
+
message: message
|
|
78
|
+
}.compact
|
|
79
|
+
)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# 주문 취소 요청 내역을 조회한다 (GET /v1/order/cancel)
|
|
83
|
+
# @comment_by Claude (alfred)
|
|
84
|
+
# @date: 26-08-14
|
|
85
|
+
# order_number 또는 order_id 로 필터. 둘 다 없으면 전체.
|
|
86
|
+
# approve/reject/withdraw 에 넘길 :id 를 여기서 얻는다 — 이게 없어서 승인/반려가 사실상 쓸 수 없었다.
|
|
87
|
+
def order_cancel_list(order_number: nil, order_id: nil, idempotency_key: nil)
|
|
88
|
+
request(
|
|
89
|
+
uri: 'order/cancel',
|
|
90
|
+
method: :get,
|
|
91
|
+
headers: {
|
|
92
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
93
|
+
'Bootpay-Role' => 'user'
|
|
94
|
+
},
|
|
95
|
+
params: {
|
|
96
|
+
order_number: order_number,
|
|
97
|
+
order_id: order_id
|
|
98
|
+
}.compact
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# (구매자) 주문 취소 요청을 철회한다 (PUT /v1/order/cancel/:id/withdraw)
|
|
103
|
+
# @comment_by Claude (alfred)
|
|
104
|
+
# @date: 26-08-14
|
|
105
|
+
# ⚠️ 주석 처리된 request_order_cancel_revoke(DELETE order/cancel/:id) 와 다른 라우트다.
|
|
106
|
+
# 서버에는 destroy(DELETE :id)와 withdraw(PUT :id/withdraw)가 둘 다 있고 같은 모델 메서드를 부른다.
|
|
107
|
+
# 매뉴얼이 문서화한 쪽은 withdraw 이므로 이쪽을 쓴다.
|
|
108
|
+
def order_cancel_withdraw(order_cancellation_request_id:, idempotency_key: nil)
|
|
109
|
+
request(
|
|
110
|
+
uri: "order/cancel/#{order_cancellation_request_id}/withdraw",
|
|
111
|
+
method: :put,
|
|
112
|
+
headers: {
|
|
113
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
114
|
+
'Bootpay-Role' => 'user'
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|