bootpay 3.0.0 → 3.2.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/CHANGELOG.md +64 -0
- data/Gemfile +1 -1
- data/bootpay.gemspec +0 -1
- data/lib/bootpay/concern/token.rb +8 -8
- data/lib/bootpay_store/bootpay-store-rest-client.rb +15 -0
- data/lib/bootpay_store/concern/alimtalk_message.rb +4 -4
- data/lib/bootpay_store/concern/alimtalk_official.rb +4 -4
- data/lib/bootpay_store/concern/alimtalk_optout.rb +5 -5
- data/lib/bootpay_store/concern/alimtalk_send.rb +17 -8
- data/lib/bootpay_store/concern/alimtalk_sender.rb +8 -8
- data/lib/bootpay_store/concern/alimtalk_template.rb +11 -11
- data/lib/bootpay_store/concern/alimtalk_webhook.rb +13 -10
- data/lib/bootpay_store/concern/deposit.rb +115 -0
- data/lib/bootpay_store/concern/faq.rb +97 -0
- data/lib/bootpay_store/concern/inquiry.rb +138 -0
- data/lib/bootpay_store/concern/notice.rb +100 -0
- data/lib/bootpay_store/concern/payout.rb +69 -0
- data/lib/bootpay_store/concern/product.rb +9 -4
- data/lib/bootpay_store/concern/product_qna.rb +149 -0
- data/lib/bootpay_store/concern/product_review.rb +145 -0
- data/lib/bootpay_store/concern/rest.rb +14 -3
- data/lib/bootpay_store/concern.rb +14 -0
- data/lib/version.rb +1 -1
- metadata +10 -3
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
module BootpayStore::Concern::Deposit
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
# 뱅크알람 입금대기 웹훅 이벤트 (입금 웹훅 본문의 event)
|
|
5
|
+
BANK_DEPOSIT_WEBHOOK_EVENT_RECEIVED = 400 # 입금 알림을 처음 저장했다 (주문 연결 전)
|
|
6
|
+
BANK_DEPOSIT_WEBHOOK_EVENT_MATCHED = 401 # 입금대기 주문 한 건과 연결되어 입금 확인됐다
|
|
7
|
+
BANK_DEPOSIT_WEBHOOK_EVENT_AMBIGUOUS = 402 # 같은 금액의 입금대기 주문이 여럿이라 판매자가 골라야 한다
|
|
8
|
+
BANK_DEPOSIT_WEBHOOK_EVENT_UNMATCHED = 403 # 연결할 입금대기 주문이 없다
|
|
9
|
+
BANK_DEPOSIT_WEBHOOK_EVENT_CONFIRMED_MANUALLY = 404 # 판매자가 관리자에서 직접 입금을 확인했다
|
|
10
|
+
BANK_DEPOSIT_WEBHOOK_EVENT_EXPIRED = 405 # 입금 기한이 지나 닫혔다
|
|
11
|
+
BANK_DEPOSIT_WEBHOOK_EVENT_CANCELLED = 406 # 입금대기 중인 주문을 취소했다
|
|
12
|
+
BANK_DEPOSIT_WEBHOOK_EVENT_REVERTED = 407 # 입금 확인을 되돌려 다시 입금대기로 바꿨다
|
|
13
|
+
|
|
14
|
+
included do
|
|
15
|
+
# 판매자 입금 계좌 목록 (GET /v1/sdk/deposits/accounts) — supervisor 전용
|
|
16
|
+
# @comment_by Claude
|
|
17
|
+
# @date: 26-11-12
|
|
18
|
+
# 첫 계좌가 대표 계좌(primary: true)다.
|
|
19
|
+
def deposit_accounts(idempotency_key: nil)
|
|
20
|
+
request(
|
|
21
|
+
uri: 'sdk/deposits/accounts',
|
|
22
|
+
method: :get,
|
|
23
|
+
headers: {
|
|
24
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
25
|
+
'Bootpay-Role' => 'supervisor'
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# 입금 웹훅 서명 비밀값 발급 (POST /v1/sdk/deposits/webhook_secret) — supervisor 전용
|
|
31
|
+
# @comment_by Claude
|
|
32
|
+
# @date: 26-11-12
|
|
33
|
+
# ⚠️ 원문은 이 응답에서만 오고, 부를 때마다 바뀐다.
|
|
34
|
+
# 웹훅은 X-Bootpay-Signature: sha256=HMAC_SHA256(secret, "{X-Bootpay-Timestamp}.{raw_body}") 로 서명된다.
|
|
35
|
+
def deposit_webhook_secret(idempotency_key: nil)
|
|
36
|
+
request(
|
|
37
|
+
uri: 'sdk/deposits/webhook_secret',
|
|
38
|
+
method: :post,
|
|
39
|
+
headers: {
|
|
40
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
41
|
+
'Bootpay-Role' => 'supervisor'
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# 입금대기 등록 (POST /v1/sdk/deposits) — supervisor 전용
|
|
47
|
+
# @comment_by Claude
|
|
48
|
+
# @date: 26-11-12
|
|
49
|
+
# 같은 merchant_order_id 로 금액·입금자명·계좌가 같은 재호출은 기존 주문을 돌려주고, 하나라도 다르면 18110.
|
|
50
|
+
# webhook_url 을 주려면 deposit_webhook_secret 으로 비밀값을 먼저 발급받아야 한다(18131).
|
|
51
|
+
# notify(구매자 알림톡, 유료): { deposit_guide:, deposit_paid:, link: } — buyer_phone 필수(18134), link 는 https(18135).
|
|
52
|
+
def deposit_create(merchant_order_id:, price:, depositor:, order_name: nil, memo: nil, buyer_name: nil,
|
|
53
|
+
buyer_phone: nil, buyer_email: nil, account_id: nil, webhook_url: nil, notify: nil,
|
|
54
|
+
idempotency_key: nil)
|
|
55
|
+
request(
|
|
56
|
+
uri: 'sdk/deposits',
|
|
57
|
+
method: :post,
|
|
58
|
+
headers: {
|
|
59
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
60
|
+
'Bootpay-Role' => 'supervisor'
|
|
61
|
+
},
|
|
62
|
+
payload: {
|
|
63
|
+
merchant_order_id: merchant_order_id,
|
|
64
|
+
price: price,
|
|
65
|
+
depositor: depositor,
|
|
66
|
+
order_name: order_name,
|
|
67
|
+
memo: memo,
|
|
68
|
+
buyer_name: buyer_name,
|
|
69
|
+
buyer_phone: buyer_phone,
|
|
70
|
+
buyer_email: buyer_email,
|
|
71
|
+
account_id: account_id,
|
|
72
|
+
webhook_url: webhook_url,
|
|
73
|
+
notify: notify.is_a?(Hash) ? notify.compact : notify
|
|
74
|
+
}.compact
|
|
75
|
+
)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# 입금대기 조회 (GET /v1/sdk/deposits/:id) — supervisor 전용
|
|
79
|
+
# @comment_by Claude
|
|
80
|
+
# @date: 26-11-12
|
|
81
|
+
# deposit_id 는 가맹점 주문번호(merchant_order_id) 또는 부트페이 주문번호. 자유 문자열이라 경로 인코딩한다.
|
|
82
|
+
def deposit_detail(deposit_id:, idempotency_key: nil)
|
|
83
|
+
request(
|
|
84
|
+
uri: "sdk/deposits/#{deposit_path_segment(deposit_id)}",
|
|
85
|
+
method: :get,
|
|
86
|
+
headers: {
|
|
87
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
88
|
+
'Bootpay-Role' => 'supervisor'
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# 입금대기 취소 (DELETE /v1/sdk/deposits/:id) — supervisor 전용
|
|
94
|
+
# @comment_by Claude
|
|
95
|
+
# @date: 26-11-12
|
|
96
|
+
# 이미 닫힌 주문은 그대로 돌려준다. 입금 확인된 주문은 18108.
|
|
97
|
+
def deposit_cancel(deposit_id:, idempotency_key: nil)
|
|
98
|
+
request(
|
|
99
|
+
uri: "sdk/deposits/#{deposit_path_segment(deposit_id)}",
|
|
100
|
+
method: :delete,
|
|
101
|
+
headers: {
|
|
102
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
103
|
+
'Bootpay-Role' => 'supervisor'
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
# 경로 세그먼트 인코딩 — 공백은 %20, / 는 %2F (다른 SDK 와 같은 결과)
|
|
111
|
+
def deposit_path_segment(value)
|
|
112
|
+
URI.encode_www_form_component(value.to_s).gsub('+', '%20')
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
module BootpayStore::Concern::Faq
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
included do
|
|
5
|
+
# FAQ 목록 (GET /v1/faqs)
|
|
6
|
+
# @comment_by Claude
|
|
7
|
+
# @date: 26-09-29
|
|
8
|
+
# supervisor: true 면 운영자 모드(Bootpay-Role: supervisor) — view: 'all' 로 비공개 FAQ 까지 조회할 수 있다.
|
|
9
|
+
# 고객 모드는 몰 FAQ 사용여부가 꺼져 있으면 BOARD_FEATURE_DISABLED 로 거절된다.
|
|
10
|
+
def faqs(page: 1, limit: 20, keyword: nil, view: nil, supervisor: false, idempotency_key: nil)
|
|
11
|
+
request(
|
|
12
|
+
uri: 'faqs',
|
|
13
|
+
method: :get,
|
|
14
|
+
headers: {
|
|
15
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
16
|
+
'Bootpay-Role' => supervisor ? 'supervisor' : 'user'
|
|
17
|
+
},
|
|
18
|
+
params: {
|
|
19
|
+
page: page,
|
|
20
|
+
limit: limit,
|
|
21
|
+
keyword: keyword,
|
|
22
|
+
view: view
|
|
23
|
+
}.compact
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# FAQ 단건 (GET /v1/faqs/:id)
|
|
28
|
+
# @comment_by Claude
|
|
29
|
+
# @date: 26-09-29
|
|
30
|
+
# 비공개 FAQ 는 supervisor: true 일 때만 보인다(아니면 404 POST_NOT_FOUND).
|
|
31
|
+
def faq_detail(faq_id:, supervisor: false, idempotency_key: nil)
|
|
32
|
+
request(
|
|
33
|
+
uri: "faqs/#{faq_id}",
|
|
34
|
+
method: :get,
|
|
35
|
+
headers: {
|
|
36
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
37
|
+
'Bootpay-Role' => supervisor ? 'supervisor' : 'user'
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# FAQ 등록 (POST /v1/faqs) — supervisor 전용
|
|
43
|
+
# @comment_by Claude
|
|
44
|
+
# @date: 26-09-29
|
|
45
|
+
def faq_create(title:, content:, images: nil, is_display: nil, idempotency_key: nil)
|
|
46
|
+
request(
|
|
47
|
+
uri: 'faqs',
|
|
48
|
+
method: :post,
|
|
49
|
+
headers: {
|
|
50
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
51
|
+
'Bootpay-Role' => 'supervisor'
|
|
52
|
+
},
|
|
53
|
+
payload: {
|
|
54
|
+
title: title,
|
|
55
|
+
content: content,
|
|
56
|
+
images: images,
|
|
57
|
+
is_display: is_display
|
|
58
|
+
}.compact
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# FAQ 수정 (PUT /v1/faqs/:id) — supervisor 전용
|
|
63
|
+
# @comment_by Claude
|
|
64
|
+
# @date: 26-09-29
|
|
65
|
+
# 보낸 필드만 바뀐다. images 는 보내면 목록 전체를 교체한다([] 면 모두 삭제).
|
|
66
|
+
def faq_update(faq_id:, title: nil, content: nil, images: nil, is_display: nil, idempotency_key: nil)
|
|
67
|
+
request(
|
|
68
|
+
uri: "faqs/#{faq_id}",
|
|
69
|
+
method: :put,
|
|
70
|
+
headers: {
|
|
71
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
72
|
+
'Bootpay-Role' => 'supervisor'
|
|
73
|
+
},
|
|
74
|
+
payload: {
|
|
75
|
+
title: title,
|
|
76
|
+
content: content,
|
|
77
|
+
images: images,
|
|
78
|
+
is_display: is_display
|
|
79
|
+
}.compact
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# FAQ 삭제 (DELETE /v1/faqs/:id) — supervisor 전용
|
|
84
|
+
# @comment_by Claude
|
|
85
|
+
# @date: 26-09-29
|
|
86
|
+
def faq_delete(faq_id:, idempotency_key: nil)
|
|
87
|
+
request(
|
|
88
|
+
uri: "faqs/#{faq_id}",
|
|
89
|
+
method: :delete,
|
|
90
|
+
headers: {
|
|
91
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
92
|
+
'Bootpay-Role' => 'supervisor'
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
module BootpayStore::Concern::Inquiry
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
included do
|
|
5
|
+
# 1:1 문의 목록 (GET /v1/inquiries)
|
|
6
|
+
# @comment_by Claude
|
|
7
|
+
# @date: 26-09-29
|
|
8
|
+
# 회원 모드: user_id(Bootpay 회원 _id 또는 외부 회원 ID)·login_id·user_jwt 중 하나로 회원을 정하고 본인 문의만 본다.
|
|
9
|
+
# supervisor: true 면 몰 전체 문의 — 이때 user_id 는 작성 회원 필터(선택)다.
|
|
10
|
+
# answered: true 답변 완료만 / false 미답변만 / nil 전체
|
|
11
|
+
def inquiries(user_id: nil, login_id: nil, user_jwt: nil, answered: nil, page: 1, limit: 20,
|
|
12
|
+
supervisor: false, idempotency_key: nil)
|
|
13
|
+
request(
|
|
14
|
+
uri: 'inquiries',
|
|
15
|
+
method: :get,
|
|
16
|
+
headers: {
|
|
17
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
18
|
+
'Bootpay-Role' => supervisor ? 'supervisor' : 'user',
|
|
19
|
+
'Bootpay-User-JWT' => user_jwt
|
|
20
|
+
}.compact,
|
|
21
|
+
params: {
|
|
22
|
+
user_id: user_id,
|
|
23
|
+
login_id: login_id,
|
|
24
|
+
answered: answered.nil? ? nil : answered.to_s,
|
|
25
|
+
page: page,
|
|
26
|
+
limit: limit
|
|
27
|
+
}.compact
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# 1:1 문의 단건 (GET /v1/inquiries/:id)
|
|
32
|
+
# @comment_by Claude
|
|
33
|
+
# @date: 26-09-29
|
|
34
|
+
# 회원 모드는 작성 회원 본인 문의만(다른 회원 문의는 404). supervisor: true 면 몰의 모든 문의.
|
|
35
|
+
def inquiry_detail(inquiry_id:, user_id: nil, login_id: nil, user_jwt: nil, supervisor: false, idempotency_key: nil)
|
|
36
|
+
request(
|
|
37
|
+
uri: "inquiries/#{inquiry_id}",
|
|
38
|
+
method: :get,
|
|
39
|
+
headers: {
|
|
40
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
41
|
+
'Bootpay-Role' => supervisor ? 'supervisor' : 'user',
|
|
42
|
+
'Bootpay-User-JWT' => user_jwt
|
|
43
|
+
}.compact,
|
|
44
|
+
params: {
|
|
45
|
+
user_id: user_id,
|
|
46
|
+
login_id: login_id
|
|
47
|
+
}.compact
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# 1:1 문의 작성 (POST /v1/inquiries) — 회원 전용
|
|
52
|
+
# @comment_by Claude
|
|
53
|
+
# @date: 26-09-29
|
|
54
|
+
# product_id 는 이 몰의 상품, order_id 는 작성 회원의 주문이어야 한다. option 은 상품 옵션 문구(product_id 필요).
|
|
55
|
+
def inquiry_create(content:, user_id: nil, login_id: nil, user_jwt: nil, title: nil, product_id: nil,
|
|
56
|
+
option: nil, order_id: nil, idempotency_key: nil)
|
|
57
|
+
request(
|
|
58
|
+
uri: 'inquiries',
|
|
59
|
+
method: :post,
|
|
60
|
+
headers: {
|
|
61
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
62
|
+
'Bootpay-Role' => 'user',
|
|
63
|
+
'Bootpay-User-JWT' => user_jwt
|
|
64
|
+
}.compact,
|
|
65
|
+
payload: {
|
|
66
|
+
user_id: user_id,
|
|
67
|
+
login_id: login_id,
|
|
68
|
+
title: title,
|
|
69
|
+
content: content,
|
|
70
|
+
product_id: product_id,
|
|
71
|
+
option: option,
|
|
72
|
+
order_id: order_id
|
|
73
|
+
}.compact
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# 1:1 문의 수정 (PUT /v1/inquiries/:id) — 작성 회원 본인, 답변 전만
|
|
78
|
+
# @comment_by Claude
|
|
79
|
+
# @date: 26-09-29
|
|
80
|
+
# 답변이 달린 문의는 409 INQUIRY_ALREADY_ANSWERED. title 에 '' 를 보내면 제목을 지운다.
|
|
81
|
+
def inquiry_update(inquiry_id:, user_id: nil, login_id: nil, user_jwt: nil, title: nil, content: nil,
|
|
82
|
+
idempotency_key: nil)
|
|
83
|
+
request(
|
|
84
|
+
uri: "inquiries/#{inquiry_id}",
|
|
85
|
+
method: :put,
|
|
86
|
+
headers: {
|
|
87
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
88
|
+
'Bootpay-Role' => 'user',
|
|
89
|
+
'Bootpay-User-JWT' => user_jwt
|
|
90
|
+
}.compact,
|
|
91
|
+
payload: {
|
|
92
|
+
user_id: user_id,
|
|
93
|
+
login_id: login_id,
|
|
94
|
+
title: title,
|
|
95
|
+
content: content
|
|
96
|
+
}.compact
|
|
97
|
+
)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# 1:1 문의 삭제 (DELETE /v1/inquiries/:id) — 작성 회원 본인 또는 supervisor
|
|
101
|
+
# @comment_by Claude
|
|
102
|
+
# @date: 26-09-29
|
|
103
|
+
# 달린 답변도 함께 삭제된다.
|
|
104
|
+
def inquiry_delete(inquiry_id:, user_id: nil, login_id: nil, user_jwt: nil, supervisor: false, idempotency_key: nil)
|
|
105
|
+
request(
|
|
106
|
+
uri: "inquiries/#{inquiry_id}",
|
|
107
|
+
method: :delete,
|
|
108
|
+
headers: {
|
|
109
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
110
|
+
'Bootpay-Role' => supervisor ? 'supervisor' : 'user',
|
|
111
|
+
'Bootpay-User-JWT' => user_jwt
|
|
112
|
+
}.compact,
|
|
113
|
+
params: {
|
|
114
|
+
user_id: user_id,
|
|
115
|
+
login_id: login_id
|
|
116
|
+
}.compact
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# 1:1 문의 답변 등록·수정 (PUT /v1/inquiries/:id/answer) — supervisor 전용
|
|
121
|
+
# @comment_by Claude
|
|
122
|
+
# @date: 26-09-29
|
|
123
|
+
# 답변이 없으면 만들고, 있으면 내용을 바꾼다. 응답은 답변이 반영된 문의 객체다.
|
|
124
|
+
def inquiry_answer(inquiry_id:, content:, idempotency_key: nil)
|
|
125
|
+
request(
|
|
126
|
+
uri: "inquiries/#{inquiry_id}/answer",
|
|
127
|
+
method: :put,
|
|
128
|
+
headers: {
|
|
129
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
130
|
+
'Bootpay-Role' => 'supervisor'
|
|
131
|
+
},
|
|
132
|
+
payload: {
|
|
133
|
+
content: content
|
|
134
|
+
}
|
|
135
|
+
)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
module BootpayStore::Concern::Notice
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
included do
|
|
5
|
+
# 공지사항 목록 (GET /v1/notices)
|
|
6
|
+
# @comment_by Claude
|
|
7
|
+
# @date: 26-09-29
|
|
8
|
+
# supervisor: true 면 운영자 모드(Bootpay-Role: supervisor) — view: 'all' 로 비공개 공지까지 조회할 수 있다.
|
|
9
|
+
# 고객 모드는 몰 공지사항 사용여부가 꺼져 있으면 BOARD_FEATURE_DISABLED 로 거절된다.
|
|
10
|
+
def notices(page: 1, limit: 20, keyword: nil, view: nil, supervisor: false, idempotency_key: nil)
|
|
11
|
+
request(
|
|
12
|
+
uri: 'notices',
|
|
13
|
+
method: :get,
|
|
14
|
+
headers: {
|
|
15
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
16
|
+
'Bootpay-Role' => supervisor ? 'supervisor' : 'user'
|
|
17
|
+
},
|
|
18
|
+
params: {
|
|
19
|
+
page: page,
|
|
20
|
+
limit: limit,
|
|
21
|
+
keyword: keyword,
|
|
22
|
+
view: view
|
|
23
|
+
}.compact
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# 공지사항 단건 (GET /v1/notices/:id)
|
|
28
|
+
# @comment_by Claude
|
|
29
|
+
# @date: 26-09-29
|
|
30
|
+
# 비공개 공지는 supervisor: true 일 때만 보인다(아니면 404 POST_NOT_FOUND).
|
|
31
|
+
def notice_detail(notice_id:, supervisor: false, idempotency_key: nil)
|
|
32
|
+
request(
|
|
33
|
+
uri: "notices/#{notice_id}",
|
|
34
|
+
method: :get,
|
|
35
|
+
headers: {
|
|
36
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
37
|
+
'Bootpay-Role' => supervisor ? 'supervisor' : 'user'
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# 공지사항 등록 (POST /v1/notices) — supervisor 전용
|
|
43
|
+
# @comment_by Claude
|
|
44
|
+
# @date: 26-09-29
|
|
45
|
+
def notice_create(title:, content:, images: nil, is_notice: nil, is_display: nil, idempotency_key: nil)
|
|
46
|
+
request(
|
|
47
|
+
uri: 'notices',
|
|
48
|
+
method: :post,
|
|
49
|
+
headers: {
|
|
50
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
51
|
+
'Bootpay-Role' => 'supervisor'
|
|
52
|
+
},
|
|
53
|
+
payload: {
|
|
54
|
+
title: title,
|
|
55
|
+
content: content,
|
|
56
|
+
images: images,
|
|
57
|
+
is_notice: is_notice,
|
|
58
|
+
is_display: is_display
|
|
59
|
+
}.compact
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# 공지사항 수정 (PUT /v1/notices/:id) — supervisor 전용
|
|
64
|
+
# @comment_by Claude
|
|
65
|
+
# @date: 26-09-29
|
|
66
|
+
# 보낸 필드만 바뀐다. images 는 보내면 목록 전체를 교체한다([] 면 모두 삭제).
|
|
67
|
+
def notice_update(notice_id:, title: nil, content: nil, images: nil, is_notice: nil, is_display: nil,
|
|
68
|
+
idempotency_key: nil)
|
|
69
|
+
request(
|
|
70
|
+
uri: "notices/#{notice_id}",
|
|
71
|
+
method: :put,
|
|
72
|
+
headers: {
|
|
73
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
74
|
+
'Bootpay-Role' => 'supervisor'
|
|
75
|
+
},
|
|
76
|
+
payload: {
|
|
77
|
+
title: title,
|
|
78
|
+
content: content,
|
|
79
|
+
images: images,
|
|
80
|
+
is_notice: is_notice,
|
|
81
|
+
is_display: is_display
|
|
82
|
+
}.compact
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# 공지사항 삭제 (DELETE /v1/notices/:id) — supervisor 전용
|
|
87
|
+
# @comment_by Claude
|
|
88
|
+
# @date: 26-09-29
|
|
89
|
+
def notice_delete(notice_id:, idempotency_key: nil)
|
|
90
|
+
request(
|
|
91
|
+
uri: "notices/#{notice_id}",
|
|
92
|
+
method: :delete,
|
|
93
|
+
headers: {
|
|
94
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
95
|
+
'Bootpay-Role' => 'supervisor'
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module BootpayStore::Concern::Payout
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
included do
|
|
5
|
+
# 입점사 지급 요청 등록 (POST /v1/sdk/payouts) — supervisor 전용
|
|
6
|
+
# @comment_by Claude
|
|
7
|
+
# @date: 26-11-12
|
|
8
|
+
# 가맹점 지정 금액(manual) 정산 쇼핑몰이 입점사와 지급액을 정해 지급 원장에 등록한다. 실제 송금은 부트페이 배치가 한다.
|
|
9
|
+
# 같은 merchant_payout_id 재호출은 처음 만든 항목을 돌려준다(금액·입점사·지급일은 바꿀 수 없다).
|
|
10
|
+
# payout_date: 'YYYY-MM-DD' (미지정시 오늘). 정산 방식이 manual 이 아니면 18360, PG 미등록 입점사는 18378.
|
|
11
|
+
def payout_create(sub_seller_id:, amount:, merchant_payout_id:, order_number: nil, payout_date: nil,
|
|
12
|
+
idempotency_key: nil)
|
|
13
|
+
request(
|
|
14
|
+
uri: 'sdk/payouts',
|
|
15
|
+
method: :post,
|
|
16
|
+
headers: {
|
|
17
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
18
|
+
'Bootpay-Role' => 'supervisor'
|
|
19
|
+
},
|
|
20
|
+
payload: {
|
|
21
|
+
sub_seller_id: sub_seller_id,
|
|
22
|
+
amount: amount,
|
|
23
|
+
merchant_payout_id: merchant_payout_id,
|
|
24
|
+
order_number: order_number,
|
|
25
|
+
payout_date: payout_date
|
|
26
|
+
}.compact
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# 입점사 지급 항목 조회 (GET /v1/sdk/payouts/:id) — supervisor 전용
|
|
31
|
+
# @comment_by Claude
|
|
32
|
+
# @date: 26-11-12
|
|
33
|
+
# payout_id 는 merchant_payout_id 또는 지급 항목 id. 없으면 404 PAYOUT_RESULT_INVALID(18366).
|
|
34
|
+
def payout_detail(payout_id:, idempotency_key: nil)
|
|
35
|
+
request(
|
|
36
|
+
uri: "sdk/payouts/#{URI.encode_www_form_component(payout_id.to_s).gsub('+', '%20')}",
|
|
37
|
+
method: :get,
|
|
38
|
+
headers: {
|
|
39
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
40
|
+
'Bootpay-Role' => 'supervisor'
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# 입점사 지급 목록 (GET /v1/sdk/payouts) — supervisor 전용
|
|
46
|
+
# @comment_by Claude
|
|
47
|
+
# @date: 26-11-12
|
|
48
|
+
# 최근 생성 순. 응답 data 는 항목 배열이다(전체 개수 없음 — 받은 수가 limit 보다 적으면 마지막 페이지).
|
|
49
|
+
# status: ready · held · sending · requested · processing · succeeded · failed · cancelled · unknown · void
|
|
50
|
+
def payouts(status: nil, sub_seller_id: nil, from: nil, to: nil, page: nil, limit: nil, idempotency_key: nil)
|
|
51
|
+
request(
|
|
52
|
+
uri: 'sdk/payouts',
|
|
53
|
+
method: :get,
|
|
54
|
+
headers: {
|
|
55
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
56
|
+
'Bootpay-Role' => 'supervisor'
|
|
57
|
+
},
|
|
58
|
+
params: {
|
|
59
|
+
status: status,
|
|
60
|
+
sub_seller_id: sub_seller_id,
|
|
61
|
+
from: from,
|
|
62
|
+
to: to,
|
|
63
|
+
page: page,
|
|
64
|
+
limit: limit
|
|
65
|
+
}.compact
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -67,6 +67,8 @@ module BootpayStore::Concern::Product
|
|
|
67
67
|
# @date: 26-08-14
|
|
68
68
|
# images 가 있으면 multipart, 없으면 JSON 으로 보낸다.
|
|
69
69
|
# 컨트롤러가 읽는 필드는 _product_params 참조 — 여기 명시하지 않은 값도 attrs 로 그대로 전달된다.
|
|
70
|
+
# @date: 26-11-02 Bootpay-Role manager → user. 서버 스코프는 user:product_create/update/delete/status 뿐이라
|
|
71
|
+
# manager 로 보내면 manager:product_* 를 찾다 401 API_ROLE_NOT_SUPPORT(-50) 로 막혔다 (수정·삭제·상태변경도 같다)
|
|
70
72
|
def product_create(name:, display_price: nil, desc: nil, content: nil, category_id: nil,
|
|
71
73
|
type: nil, stock: nil, status_sale: nil, status_display: nil,
|
|
72
74
|
use_subscription: nil, subscription_setting_id: nil,
|
|
@@ -88,7 +90,7 @@ module BootpayStore::Concern::Product
|
|
|
88
90
|
|
|
89
91
|
headers = {
|
|
90
92
|
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
91
|
-
'Bootpay-Role' => '
|
|
93
|
+
'Bootpay-Role' => 'user'
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
if images.present?
|
|
@@ -104,6 +106,7 @@ module BootpayStore::Concern::Product
|
|
|
104
106
|
# @comment_by Claude (alfred)
|
|
105
107
|
# @date: 26-08-14
|
|
106
108
|
# 바뀐 값만 보내면 된다. category_id 는 키 존재 여부로 '해제 의사'를 판별하므로 주의.
|
|
109
|
+
# @date: 26-11-02 Bootpay-Role manager → user (product_create 주석 참고)
|
|
107
110
|
def product_update(product_id:, name: nil, display_price: nil, desc: nil, content: nil,
|
|
108
111
|
category_id: nil, stock: nil, status_sale: nil, status_display: nil,
|
|
109
112
|
save_by: nil, idempotency_key: nil, **attrs)
|
|
@@ -112,7 +115,7 @@ module BootpayStore::Concern::Product
|
|
|
112
115
|
method: :put,
|
|
113
116
|
headers: {
|
|
114
117
|
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
115
|
-
'Bootpay-Role' => '
|
|
118
|
+
'Bootpay-Role' => 'user'
|
|
116
119
|
},
|
|
117
120
|
payload: {
|
|
118
121
|
name: name,
|
|
@@ -131,13 +134,14 @@ module BootpayStore::Concern::Product
|
|
|
131
134
|
# 상품을 삭제한다 (DELETE /v1/products/:id)
|
|
132
135
|
# @comment_by Claude (alfred)
|
|
133
136
|
# @date: 26-08-14
|
|
137
|
+
# @date: 26-11-02 Bootpay-Role manager → user (product_create 주석 참고)
|
|
134
138
|
def product_delete(product_id:, idempotency_key: nil)
|
|
135
139
|
request(
|
|
136
140
|
uri: "products/#{product_id}",
|
|
137
141
|
method: :delete,
|
|
138
142
|
headers: {
|
|
139
143
|
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
140
|
-
'Bootpay-Role' => '
|
|
144
|
+
'Bootpay-Role' => 'user'
|
|
141
145
|
}
|
|
142
146
|
)
|
|
143
147
|
end
|
|
@@ -146,6 +150,7 @@ module BootpayStore::Concern::Product
|
|
|
146
150
|
# @comment_by Claude (alfred)
|
|
147
151
|
# @date: 26-08-14
|
|
148
152
|
# 컨트롤러 _status_params 기준. 재고(stock)는 여기가 아니라 product_update 로 바꾼다.
|
|
153
|
+
# @date: 26-11-02 Bootpay-Role manager → user (product_create 주석 참고)
|
|
149
154
|
def product_status(product_id:, status_sale: nil, status_display: nil, status_frozen: nil,
|
|
150
155
|
status_review: nil, use_display_period: nil, display_start_at: nil, display_end_at: nil,
|
|
151
156
|
use_sale_period: nil, sale_start_at: nil, sale_end_at: nil,
|
|
@@ -155,7 +160,7 @@ module BootpayStore::Concern::Product
|
|
|
155
160
|
method: :put,
|
|
156
161
|
headers: {
|
|
157
162
|
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
158
|
-
'Bootpay-Role' => '
|
|
163
|
+
'Bootpay-Role' => 'user'
|
|
159
164
|
},
|
|
160
165
|
payload: {
|
|
161
166
|
status_sale: status_sale,
|