bootpay 3.0.0 → 3.1.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 +44 -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 +6 -6
- 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/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 +10 -0
- data/lib/version.rb +1 -1
- metadata +8 -3
|
@@ -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,149 @@
|
|
|
1
|
+
module BootpayStore::Concern::ProductQna
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
included do
|
|
5
|
+
# 상품문의 목록 (GET /v1/product-qnas)
|
|
6
|
+
# @comment_by Claude
|
|
7
|
+
# @date: 26-09-29
|
|
8
|
+
# 고객 모드는 product_id 필수. 다른 사람의 비밀글은 is_viewable: false 로 본문 없이 온다.
|
|
9
|
+
# 회원(user_id·login_id·user_jwt)을 보내면 그 회원이 쓴 비밀글 본문이 보인다.
|
|
10
|
+
# supervisor: true + view: 'all' 이면 몰 전체(숨김 포함) — 이때 product_id 는 선택 필터다.
|
|
11
|
+
def product_qnas(product_id: nil, view: nil, page: 1, limit: 20, user_id: nil, login_id: nil, user_jwt: nil,
|
|
12
|
+
supervisor: false, idempotency_key: nil)
|
|
13
|
+
request(
|
|
14
|
+
uri: 'product-qnas',
|
|
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
|
+
product_id: product_id,
|
|
23
|
+
view: view,
|
|
24
|
+
page: page,
|
|
25
|
+
limit: limit,
|
|
26
|
+
user_id: user_id,
|
|
27
|
+
login_id: login_id
|
|
28
|
+
}.compact
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# 상품문의 단건 (GET /v1/product-qnas/:id)
|
|
33
|
+
# @comment_by Claude
|
|
34
|
+
# @date: 26-09-29
|
|
35
|
+
# 다른 사람의 비밀글은 403 PRODUCT_QNA_SECRET_FORBIDDEN. supervisor: true 면 비밀글·숨김 글도 본다.
|
|
36
|
+
def product_qna_detail(product_qna_id:, user_id: nil, login_id: nil, user_jwt: nil, supervisor: false,
|
|
37
|
+
idempotency_key: nil)
|
|
38
|
+
request(
|
|
39
|
+
uri: "product-qnas/#{product_qna_id}",
|
|
40
|
+
method: :get,
|
|
41
|
+
headers: {
|
|
42
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
43
|
+
'Bootpay-Role' => supervisor ? 'supervisor' : 'user',
|
|
44
|
+
'Bootpay-User-JWT' => user_jwt
|
|
45
|
+
}.compact,
|
|
46
|
+
params: {
|
|
47
|
+
user_id: user_id,
|
|
48
|
+
login_id: login_id
|
|
49
|
+
}.compact
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# 상품문의 작성 (POST /v1/product-qnas)
|
|
54
|
+
# @comment_by Claude
|
|
55
|
+
# @date: 26-09-29
|
|
56
|
+
# 회원(user_id·login_id·user_jwt) 또는 비회원(guest_name + guest_password, 몰이 비회원 작성을 허용할 때).
|
|
57
|
+
# 회원 문의면 guest_* 는 무시된다.
|
|
58
|
+
def product_qna_create(product_id:, content:, title: nil, product_option_id: nil, option_text: nil,
|
|
59
|
+
is_secret: nil, guest_name: nil, guest_password: nil,
|
|
60
|
+
user_id: nil, login_id: nil, user_jwt: nil, idempotency_key: nil)
|
|
61
|
+
request(
|
|
62
|
+
uri: 'product-qnas',
|
|
63
|
+
method: :post,
|
|
64
|
+
headers: {
|
|
65
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
66
|
+
'Bootpay-Role' => 'user',
|
|
67
|
+
'Bootpay-User-JWT' => user_jwt
|
|
68
|
+
}.compact,
|
|
69
|
+
payload: {
|
|
70
|
+
product_id: product_id,
|
|
71
|
+
title: title,
|
|
72
|
+
content: content,
|
|
73
|
+
product_option_id: product_option_id,
|
|
74
|
+
option_text: option_text,
|
|
75
|
+
is_secret: is_secret,
|
|
76
|
+
guest_name: guest_name,
|
|
77
|
+
guest_password: guest_password,
|
|
78
|
+
user_id: user_id,
|
|
79
|
+
login_id: login_id
|
|
80
|
+
}.compact
|
|
81
|
+
)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# 상품문의 수정 (PUT /v1/product-qnas/:id) — 작성 회원 본인 또는 비회원 비밀번호, 답변 전만
|
|
85
|
+
# @comment_by Claude
|
|
86
|
+
# @date: 26-09-29
|
|
87
|
+
# 답변이 달린 문의는 409 PRODUCT_QNA_ALREADY_ANSWERED, 비회원 비밀번호가 틀리면 403 PRODUCT_QNA_GUEST_PASSWORD_INVALID.
|
|
88
|
+
def product_qna_update(product_qna_id:, title: nil, content: nil, is_secret: nil, guest_password: nil,
|
|
89
|
+
user_id: nil, login_id: nil, user_jwt: nil, idempotency_key: nil)
|
|
90
|
+
request(
|
|
91
|
+
uri: "product-qnas/#{product_qna_id}",
|
|
92
|
+
method: :put,
|
|
93
|
+
headers: {
|
|
94
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
95
|
+
'Bootpay-Role' => 'user',
|
|
96
|
+
'Bootpay-User-JWT' => user_jwt
|
|
97
|
+
}.compact,
|
|
98
|
+
payload: {
|
|
99
|
+
title: title,
|
|
100
|
+
content: content,
|
|
101
|
+
is_secret: is_secret,
|
|
102
|
+
guest_password: guest_password,
|
|
103
|
+
user_id: user_id,
|
|
104
|
+
login_id: login_id
|
|
105
|
+
}.compact
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# 상품문의 삭제 (DELETE /v1/product-qnas/:id) — 작성 회원 본인·비회원 비밀번호 또는 supervisor
|
|
110
|
+
# @comment_by Claude
|
|
111
|
+
# @date: 26-09-29
|
|
112
|
+
# guest_password 는 URL 쿼리가 아닌 본문으로 보낸다(서버는 둘 다 받는다).
|
|
113
|
+
def product_qna_delete(product_qna_id:, guest_password: nil, user_id: nil, login_id: nil, user_jwt: nil,
|
|
114
|
+
supervisor: false, idempotency_key: nil)
|
|
115
|
+
request(
|
|
116
|
+
uri: "product-qnas/#{product_qna_id}",
|
|
117
|
+
method: :delete,
|
|
118
|
+
headers: {
|
|
119
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
120
|
+
'Bootpay-Role' => supervisor ? 'supervisor' : 'user',
|
|
121
|
+
'Bootpay-User-JWT' => user_jwt
|
|
122
|
+
}.compact,
|
|
123
|
+
payload: {
|
|
124
|
+
guest_password: guest_password,
|
|
125
|
+
user_id: user_id,
|
|
126
|
+
login_id: login_id
|
|
127
|
+
}.compact
|
|
128
|
+
)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# 상품문의 답변 등록·수정 (PUT /v1/product-qnas/:id/answer) — supervisor 전용
|
|
132
|
+
# @comment_by Claude
|
|
133
|
+
# @date: 26-09-29
|
|
134
|
+
# 답변이 없으면 만들고, 있으면 내용을 바꾼다. 응답은 답변이 반영된 상품문의 객체다.
|
|
135
|
+
def product_qna_answer(product_qna_id:, content:, idempotency_key: nil)
|
|
136
|
+
request(
|
|
137
|
+
uri: "product-qnas/#{product_qna_id}/answer",
|
|
138
|
+
method: :put,
|
|
139
|
+
headers: {
|
|
140
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
141
|
+
'Bootpay-Role' => 'supervisor'
|
|
142
|
+
},
|
|
143
|
+
payload: {
|
|
144
|
+
content: content
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
module BootpayStore::Concern::ProductReview
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
included do
|
|
5
|
+
# 상품평 목록 (GET /v1/reviews)
|
|
6
|
+
# @comment_by Claude
|
|
7
|
+
# @date: 26-09-29
|
|
8
|
+
# 회원 모드: user_id·login_id·user_jwt 로 정한 회원이 쓴 상품평만 본다.
|
|
9
|
+
# supervisor: true 면 몰 전체 상품평 — 이때 user_id 는 작성 회원 필터(선택)다.
|
|
10
|
+
# 상품 상세의 공개 상품평 목록은 기존 GET /v1/products/:id/reviews 를 쓴다.
|
|
11
|
+
def reviews(page: 1, limit: 20, product_id: nil, view: nil, user_id: nil, login_id: nil, user_jwt: nil,
|
|
12
|
+
supervisor: false, idempotency_key: nil)
|
|
13
|
+
request(
|
|
14
|
+
uri: 'reviews',
|
|
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
|
+
page: page,
|
|
23
|
+
limit: limit,
|
|
24
|
+
product_id: product_id,
|
|
25
|
+
view: view,
|
|
26
|
+
user_id: user_id,
|
|
27
|
+
login_id: login_id
|
|
28
|
+
}.compact
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# 상품평 단건 (GET /v1/reviews/:id)
|
|
33
|
+
# @comment_by Claude
|
|
34
|
+
# @date: 26-09-29
|
|
35
|
+
# 공개 상품평은 누구나, 숨김 상품평은 작성 회원 본인 또는 supervisor 만 본다.
|
|
36
|
+
def review_detail(product_review_id:, user_id: nil, login_id: nil, user_jwt: nil, supervisor: false,
|
|
37
|
+
idempotency_key: nil)
|
|
38
|
+
request(
|
|
39
|
+
uri: "reviews/#{product_review_id}",
|
|
40
|
+
method: :get,
|
|
41
|
+
headers: {
|
|
42
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
43
|
+
'Bootpay-Role' => supervisor ? 'supervisor' : 'user',
|
|
44
|
+
'Bootpay-User-JWT' => user_jwt
|
|
45
|
+
}.compact,
|
|
46
|
+
params: {
|
|
47
|
+
user_id: user_id,
|
|
48
|
+
login_id: login_id
|
|
49
|
+
}.compact
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# 상품평 작성 (POST /v1/reviews) — 회원 전용
|
|
54
|
+
# @comment_by Claude
|
|
55
|
+
# @date: 26-09-29
|
|
56
|
+
# order_id 는 회원의 구매확정 주문, product_id(·product_option_id)는 그 주문에 담긴 상품이어야 한다.
|
|
57
|
+
# images 는 사진 URL 최대 5개(문자열 또는 { url: } 해시). 파일 업로드는 지원하지 않는다.
|
|
58
|
+
def review_create(order_id:, product_id:, rating:, content:, product_option_id: nil, images: nil,
|
|
59
|
+
user_id: nil, login_id: nil, user_jwt: nil, idempotency_key: nil)
|
|
60
|
+
request(
|
|
61
|
+
uri: 'reviews',
|
|
62
|
+
method: :post,
|
|
63
|
+
headers: {
|
|
64
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
65
|
+
'Bootpay-Role' => 'user',
|
|
66
|
+
'Bootpay-User-JWT' => user_jwt
|
|
67
|
+
}.compact,
|
|
68
|
+
payload: {
|
|
69
|
+
user_id: user_id,
|
|
70
|
+
login_id: login_id,
|
|
71
|
+
order_id: order_id,
|
|
72
|
+
product_id: product_id,
|
|
73
|
+
product_option_id: product_option_id,
|
|
74
|
+
rating: rating,
|
|
75
|
+
content: content,
|
|
76
|
+
images: images
|
|
77
|
+
}.compact
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# 상품평 수정 (PUT /v1/reviews/:id) — 작성 회원 본인, 작성 후 7일 이내
|
|
82
|
+
# @comment_by Claude
|
|
83
|
+
# @date: 26-09-29
|
|
84
|
+
# images 는 보내면 통째로 교체한다([] 면 모두 삭제). 7일이 지나면 REVIEW_EDIT_TIME_EXPIRED.
|
|
85
|
+
def review_update(product_review_id:, rating: nil, content: nil, images: nil,
|
|
86
|
+
user_id: nil, login_id: nil, user_jwt: nil, idempotency_key: nil)
|
|
87
|
+
request(
|
|
88
|
+
uri: "reviews/#{product_review_id}",
|
|
89
|
+
method: :put,
|
|
90
|
+
headers: {
|
|
91
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
92
|
+
'Bootpay-Role' => 'user',
|
|
93
|
+
'Bootpay-User-JWT' => user_jwt
|
|
94
|
+
}.compact,
|
|
95
|
+
payload: {
|
|
96
|
+
user_id: user_id,
|
|
97
|
+
login_id: login_id,
|
|
98
|
+
rating: rating,
|
|
99
|
+
content: content,
|
|
100
|
+
images: images
|
|
101
|
+
}.compact
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# 상품평 삭제 (DELETE /v1/reviews/:id) — 작성 회원 본인 또는 supervisor
|
|
106
|
+
# @comment_by Claude
|
|
107
|
+
# @date: 26-09-29
|
|
108
|
+
# 지급된 적립금 회수·상품 통계 차감이 함께 일어난다. reason 은 운영자 모드의 삭제 사유.
|
|
109
|
+
def review_delete(product_review_id:, reason: nil, user_id: nil, login_id: nil, user_jwt: nil,
|
|
110
|
+
supervisor: false, idempotency_key: nil)
|
|
111
|
+
request(
|
|
112
|
+
uri: "reviews/#{product_review_id}",
|
|
113
|
+
method: :delete,
|
|
114
|
+
headers: {
|
|
115
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
116
|
+
'Bootpay-Role' => supervisor ? 'supervisor' : 'user',
|
|
117
|
+
'Bootpay-User-JWT' => user_jwt
|
|
118
|
+
}.compact,
|
|
119
|
+
params: {
|
|
120
|
+
user_id: user_id,
|
|
121
|
+
login_id: login_id,
|
|
122
|
+
reason: reason
|
|
123
|
+
}.compact
|
|
124
|
+
)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# 상품평 판매자 답글 등록·수정 (PUT /v1/reviews/:id/reply) — supervisor 전용
|
|
128
|
+
# @comment_by Claude
|
|
129
|
+
# @date: 26-09-29
|
|
130
|
+
# 답글이 없으면 만들고, 있으면 내용을 바꾼다(10자 이상). 응답은 답글이 반영된 상품평 객체다.
|
|
131
|
+
def review_reply(product_review_id:, content:, idempotency_key: nil)
|
|
132
|
+
request(
|
|
133
|
+
uri: "reviews/#{product_review_id}/reply",
|
|
134
|
+
method: :put,
|
|
135
|
+
headers: {
|
|
136
|
+
'Idempotency-Key' => idempotency_key.presence || SecureRandom.uuid,
|
|
137
|
+
'Bootpay-Role' => 'supervisor'
|
|
138
|
+
},
|
|
139
|
+
payload: {
|
|
140
|
+
content: content
|
|
141
|
+
}
|
|
142
|
+
)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -4,6 +4,17 @@ module BootpayStore::Concern::Rest
|
|
|
4
4
|
included do
|
|
5
5
|
private
|
|
6
6
|
|
|
7
|
+
# 요청 경로에 맞는 API 기본 주소.
|
|
8
|
+
# @comment_by Claude (alfred)
|
|
9
|
+
# @date: 26-09-18
|
|
10
|
+
# 알림톡 API 는 26-09-18 부터 커머스 API(api.bootapi.com/v1)가 아니라 메시지 API(message.bootapi.com, /v1 없음)가 받는다.
|
|
11
|
+
# 경로·파라미터·응답은 그대로이고 호스트만 다르다 — 그래서 알림톡 메서드는 고치지 않고 여기서 주소만 가른다.
|
|
12
|
+
# 옛 주소(/alimtalk/*)는 410 으로 응답한다.
|
|
13
|
+
def api_base_url(uri)
|
|
14
|
+
table = uri.to_s.sub(%r{\A/}, '').start_with?('alimtalk') ? BootpayStore::RestClient::MESSAGE_API : BootpayStore::RestClient::API
|
|
15
|
+
table[@mode.to_sym]
|
|
16
|
+
end
|
|
17
|
+
|
|
7
18
|
# HTTP Request 기본 Method
|
|
8
19
|
# Comment by Gosomi
|
|
9
20
|
# Date: 2021-05-21
|
|
@@ -19,7 +30,7 @@ module BootpayStore::Concern::Rest
|
|
|
19
30
|
}.merge!(headers).compact
|
|
20
31
|
).send(
|
|
21
32
|
method.to_sym,
|
|
22
|
-
[
|
|
33
|
+
[api_base_url(uri), uri].join('/'),
|
|
23
34
|
json: payload,
|
|
24
35
|
params: params
|
|
25
36
|
)
|
|
@@ -54,7 +65,7 @@ module BootpayStore::Concern::Rest
|
|
|
54
65
|
}.merge!(headers).compact
|
|
55
66
|
).send(
|
|
56
67
|
method.to_sym,
|
|
57
|
-
[
|
|
68
|
+
[api_base_url(uri), uri].join('/'),
|
|
58
69
|
params: params
|
|
59
70
|
)
|
|
60
71
|
BootpayStore::Response.new(
|
|
@@ -86,7 +97,7 @@ module BootpayStore::Concern::Rest
|
|
|
86
97
|
bootpay_sdk_type: '300'
|
|
87
98
|
}.merge!(headers).compact
|
|
88
99
|
).post(
|
|
89
|
-
[
|
|
100
|
+
[api_base_url(uri), uri].join('/'),
|
|
90
101
|
form: form
|
|
91
102
|
)
|
|
92
103
|
BootpayStore::Response.new(
|
|
@@ -7,12 +7,17 @@ module BootpayStore
|
|
|
7
7
|
require_relative 'concern/alimtalk_sender'
|
|
8
8
|
require_relative 'concern/alimtalk_template'
|
|
9
9
|
require_relative 'concern/alimtalk_webhook'
|
|
10
|
+
require_relative 'concern/faq'
|
|
11
|
+
require_relative 'concern/inquiry'
|
|
10
12
|
require_relative 'concern/invoice'
|
|
11
13
|
require_relative 'concern/mall_setting'
|
|
14
|
+
require_relative 'concern/notice'
|
|
12
15
|
require_relative 'concern/order'
|
|
13
16
|
require_relative 'concern/order_subscription'
|
|
14
17
|
require_relative 'concern/payment'
|
|
15
18
|
require_relative 'concern/product'
|
|
19
|
+
require_relative 'concern/product_qna'
|
|
20
|
+
require_relative 'concern/product_review'
|
|
16
21
|
require_relative 'concern/rest'
|
|
17
22
|
require_relative 'concern/supervisor'
|
|
18
23
|
require_relative 'concern/token'
|
|
@@ -28,12 +33,17 @@ module BootpayStore
|
|
|
28
33
|
include AlimtalkSender
|
|
29
34
|
include AlimtalkTemplate
|
|
30
35
|
include AlimtalkWebhook
|
|
36
|
+
include Faq
|
|
37
|
+
include Inquiry
|
|
31
38
|
include Invoice
|
|
32
39
|
include MallSetting
|
|
40
|
+
include Notice
|
|
33
41
|
include Order
|
|
34
42
|
include OrderSubscription
|
|
35
43
|
include Payment
|
|
36
44
|
include Product
|
|
45
|
+
include ProductQna
|
|
46
|
+
include ProductReview
|
|
37
47
|
include Rest
|
|
38
48
|
include Supervisor
|
|
39
49
|
include Token
|
data/lib/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bootpay
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- gosomi
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -106,12 +106,17 @@ files:
|
|
|
106
106
|
- lib/bootpay_store/concern/alimtalk_sender.rb
|
|
107
107
|
- lib/bootpay_store/concern/alimtalk_template.rb
|
|
108
108
|
- lib/bootpay_store/concern/alimtalk_webhook.rb
|
|
109
|
+
- lib/bootpay_store/concern/faq.rb
|
|
110
|
+
- lib/bootpay_store/concern/inquiry.rb
|
|
109
111
|
- lib/bootpay_store/concern/invoice.rb
|
|
110
112
|
- lib/bootpay_store/concern/mall_setting.rb
|
|
113
|
+
- lib/bootpay_store/concern/notice.rb
|
|
111
114
|
- lib/bootpay_store/concern/order.rb
|
|
112
115
|
- lib/bootpay_store/concern/order_subscription.rb
|
|
113
116
|
- lib/bootpay_store/concern/payment.rb
|
|
114
117
|
- lib/bootpay_store/concern/product.rb
|
|
118
|
+
- lib/bootpay_store/concern/product_qna.rb
|
|
119
|
+
- lib/bootpay_store/concern/product_review.rb
|
|
115
120
|
- lib/bootpay_store/concern/rest.rb
|
|
116
121
|
- lib/bootpay_store/concern/store.rb
|
|
117
122
|
- lib/bootpay_store/concern/supervisor.rb
|
|
@@ -137,7 +142,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
137
142
|
requirements:
|
|
138
143
|
- - ">="
|
|
139
144
|
- !ruby/object:Gem::Version
|
|
140
|
-
version:
|
|
145
|
+
version: '0'
|
|
141
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
147
|
requirements:
|
|
143
148
|
- - ">="
|