bootpay-backend 2.0.6__macosx-10.9-universal2.tar.gz

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.

Potentially problematic release.


This version of bootpay-backend might be problematic. Click here for more details.

Files changed (12) hide show
  1. Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site-packages/bootpay/__init__.py +3 -0
  2. Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site-packages/bootpay/bankcode.py +18 -0
  3. Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site-packages/bootpay/client.py +305 -0
  4. Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site-packages/bootpay_backend/__init__.py +3 -0
  5. Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site-packages/bootpay_backend/bankcode.py +18 -0
  6. Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site-packages/bootpay_backend/rest_client.py +305 -0
  7. Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site-packages/bootpay_backend-2.0.6-py3.9.egg-info/PKG-INFO +380 -0
  8. Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site-packages/bootpay_backend-2.0.6-py3.9.egg-info/SOURCES.txt +13 -0
  9. Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site-packages/bootpay_backend-2.0.6-py3.9.egg-info/dependency_links.txt +1 -0
  10. Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site-packages/bootpay_backend-2.0.6-py3.9.egg-info/not-zip-safe +1 -0
  11. Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site-packages/bootpay_backend-2.0.6-py3.9.egg-info/requires.txt +6 -0
  12. Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site-packages/bootpay_backend-2.0.6-py3.9.egg-info/top_level.txt +1 -0
@@ -0,0 +1,18 @@
1
+ dictionary = {
2
+ '한국은행': '001',
3
+ '기업은행': '003',
4
+ '외환은행': '005',
5
+ '수협은행': '007',
6
+ '농협은행': '011',
7
+ '우리은행': '020',
8
+ 'SC은행': '023',
9
+ '대구은행': '031',
10
+ '부산은행': '032',
11
+ '광주은행': '034',
12
+ '경남은행': '039',
13
+ '우체국': '071',
14
+ 'KEB하나은행': '081',
15
+ '신한은행': '088',
16
+ '케이뱅크': '089',
17
+ '카카오뱅크': '090',
18
+ }
@@ -0,0 +1,305 @@
1
+ import requests
2
+ import uuid
3
+ import json
4
+ from bootpay import bankcode
5
+ import time
6
+
7
+
8
+ class Bootpay:
9
+ base_url = {
10
+ 'development': 'https://dev-api.bootpay.co.kr',
11
+ 'production': 'https://api.bootpay.co.kr'
12
+ }
13
+
14
+ def __init__(self, application_id, private_key, mode='production'):
15
+ self.application_id = application_id
16
+ self.pk = private_key
17
+ self.mode = mode
18
+ self.token = None
19
+
20
+ def api_url(self, uri=None):
21
+ if uri is None:
22
+ uri = []
23
+ return '/'.join([self.base_url[self.mode]] + uri)
24
+
25
+ # 1. 토큰 발급
26
+ def get_access_token(self):
27
+ data = {
28
+ 'application_id': self.application_id,
29
+ 'private_key': self.pk
30
+ }
31
+ response = requests.post(self.api_url(['request', 'token']), data=data)
32
+ result = response.json()
33
+ if result['status'] == 200:
34
+ self.token = result['data']['token']
35
+ return result
36
+
37
+ # 2. 결제 검증
38
+ def verify(self, receipt_id):
39
+ return requests.get(self.api_url(['receipt', receipt_id]), headers={
40
+ 'Authorization': self.token
41
+ }).json()
42
+
43
+ # 3. 결제 취소 (전액 취소 / 부분 취소)
44
+ #
45
+ # price - (선택사항) 부분취소 요청시 금액을 지정, 미지정시 전액 취소 (부분취소가 가능한 PG사, 결제수단에 한해 적용됨)
46
+ # cancel_id - (선택사항) 부분취소 요청시 중복 요청을 방지하기 위한 고유값
47
+ # refund - (선택사항) 가상계좌 환불요청시, 전제조건으로 PG사와 CMS 특약이 체결되어 있을 경우에만 환불요청 가능, 기본적으로 가상계좌는 결제취소가 안됨
48
+ # {
49
+ # account: '6756010101234', # 환불받을 계좌번호
50
+ # accountholder: '홍길동', # 환불받을 계좌주
51
+ # bankcode: bankcode.dictionary['국민은행'], # 은행 코드
52
+ # }
53
+ #
54
+ def cancel(self, receipt_id, price=None, name=None, reason=None, cancel_id=str(uuid.uuid4()), tax_free=None,
55
+ refund=None):
56
+ payload = {'receipt_id': receipt_id, # 부트페이로부터 받은 영수증 ID
57
+ 'price': price, # 부분취소시 금액 지정
58
+ 'name': name, # 취소 요청자 이름
59
+ 'reason': reason, # 취소 요청 사유
60
+ 'tax_free': tax_free, # 취소할 비과세 금액
61
+ 'cancel_id': cancel_id, # 부분취소 중복요청 방지
62
+ 'refund': refund}
63
+
64
+ return requests.post(self.api_url(['cancel.json']), data=payload, headers={
65
+ 'Authorization': self.token
66
+ }).json()
67
+
68
+ # 4. 빌링키 발급
69
+ # extra - 빌링키 발급 옵션
70
+ # {
71
+ # subscribe_tst_payment: 0, # 100원 결제 후 결제가 되면 billing key를 발행, 결제가 실패하면 에러
72
+ # raw_data: 0 //PG 오류 코드 및 메세지까지 리턴
73
+ # }
74
+ def get_subscribe_billing_key(self, pg, order_id, item_name, card_no, card_pw, expire_year, expire_month,
75
+ identify_number,
76
+ user_info=None, extra=None):
77
+ if user_info is None:
78
+ user_info = {}
79
+ payload = {
80
+ 'order_id': order_id, # 개발사에서 관리하는 고유 주문 번호
81
+ 'pg': pg, # PG사의 Alias ex) danal, kcp, inicis 등
82
+ 'item_name': item_name, # 상품명
83
+ 'card_no': card_no, # 카드 일련번호
84
+ 'card_pw': card_pw, # 카드 비밀번호 앞 2자리
85
+ 'expire_year': expire_year, # 카드 유효기간 년
86
+ 'expire_month': expire_month, # 카드 유효기간 월
87
+ 'identify_number': identify_number, # 주민등록번호 또는 사업자번호
88
+ 'user_info': user_info, # 구매자 정보
89
+ 'extra': extra # 기타 옵션
90
+ }
91
+ return requests.post(self.api_url(['request', 'card_rebill.json']), data=json.dumps(payload), headers={
92
+ 'Authorization': self.token,
93
+ 'Content-Type': 'application/json'
94
+ }).json()
95
+
96
+ # 4-1. 발급된 빌링키로 결제 승인 요청
97
+ # tax_free - 면세 상품일 경우 해당만큼의 금액을 설정
98
+ # interest - 웰컴페이먼츠 전용, 무이자여부를 보내는 파라미터가 있다
99
+ # quota - 5만원 이상 결제건에 적용하는 할부개월수. 0-일시불, 1은 지정시 에러 발생함, 2-2개월, 3-3개월... 12까지 지정가능
100
+ # feedback_url - webhook 통지시 받으실 url 주소 (localhost 사용 불가)
101
+ # feedback_content_type - webhook 통지시 받으실 데이터 타입 (json 또는 urlencoded, 기본값 urlencoded)
102
+ #####
103
+ def subscribe_billing(self, billing_key, item_name, price, order_id, items=None, user_info=None, extra=None,
104
+ tax_free=None, quota=None, interest=None, feedback_url=None, feedback_content_type=None):
105
+ if items is None:
106
+ items = []
107
+ payload = {
108
+ 'billing_key': billing_key, # 발급받은 빌링키
109
+ 'item_name': item_name, # 결제할 상품명
110
+ 'price': price, # 결제할 상품금액
111
+ 'order_id': order_id, # 개발사에서 지정하는 고유주문번호
112
+ 'items': items, # 구매할 상품정보, 통계용
113
+ 'user_info': user_info, # 구매자 정보, 특정 PG사의 경우 구매자 휴대폰 번호를 필수로 받는다
114
+ 'extra': extra, # 기타 옵션
115
+ 'tax_free': tax_free, # 면세 상품일 경우 해당만큼의 금액을 설정
116
+ 'quota': quota, # int 형태, 5만원 이상 결제건에 적용하는 할부개월수. 0-일시불, 1은 지정시 에러 발생함, 2-2개월, 3-3개월... 12까지 지정가능
117
+ 'interest': interest, # 웰컴페이먼츠 전용, 무이자여부를 보내는 파라미터가 있다
118
+ 'feedback_url': feedback_url, # webhook 통지시 받으실 url 주소 (localhost 사용 불가)
119
+ 'feedback_content_type': feedback_content_type
120
+ # webhook 통지시 받으실 데이터 타입 (json 또는 urlencoded, 기본값 urlencoded)
121
+ }
122
+ return requests.post(self.api_url(['subscribe', 'billing.json']), data=json.dumps(payload), headers={
123
+ 'Authorization': self.token,
124
+ 'Content-Type': 'application/json'
125
+ }).json()
126
+
127
+ # 4-2. 발급된 빌링키로 결제 예약 요청
128
+ # def subscribe_billing_reserve(self, billing_key, item_name, price, order_id, execute_at, feedback_url, items=None):
129
+ def subscribe_billing_reserve(self, billing_key, item_name, price, order_id, execute_at=time.time() + 10,
130
+ items=None, user_info=None, extra=None,
131
+ tax_free=None, quota=None, interest=None, feedback_url=None,
132
+ feedback_content_type=None):
133
+ if items is None:
134
+ items = []
135
+ payload = {
136
+ 'billing_key': billing_key, # 발급받은 빌링키
137
+ 'item_name': item_name, # 결제할 상품명
138
+ 'price': price, # 결제할 상품금액
139
+ 'order_id': order_id, # 개발사에서 지정하는 고유주문번호
140
+ 'execute_at': execute_at, # 결제 수행(예약) 시간, 기본값으로 10초 뒤 결제
141
+ 'items': items, # 구매할 상품정보, 통계용
142
+ 'user_info': user_info, # 구매자 정보, 특정 PG사의 경우 구매자 휴대폰 번호를 필수로 받는다
143
+ 'extra': extra, # 기타 옵션
144
+ 'tax_free': tax_free, # 면세 상품일 경우 해당만큼의 금액을 설정
145
+ 'quota': quota, # int 형태, 5만원 이상 결제건에 적용하는 할부개월수. 0-일시불, 1은 지정시 에러 발생함, 2-2개월, 3-3개월... 12까지 지정가능
146
+ 'interest': interest, # 웰컴페이먼츠 전용, 무이자여부를 보내는 파라미터가 있다
147
+ 'feedback_url': feedback_url, # webhook 통지시 받으실 url 주소 (localhost 사용 불가)
148
+ 'feedback_content_type': feedback_content_type,
149
+ # webhook 통지시 받으실 데이터 타입 (json 또는 urlencoded, 기본값 urlencoded)
150
+ 'scheduler_type': 'oneshot'
151
+ }
152
+ return requests.post(self.api_url(['subscribe', 'billing', 'reserve.json']), data=json.dumps(payload), headers={
153
+ 'Authorization': self.token,
154
+ 'Content-Type': 'application/json'
155
+ }).json()
156
+
157
+ # 4-2-1. 발급된 빌링키로 결제 예약 - 취소 요청
158
+ def subscribe_billing_reserve_cancel(self, reserve_id):
159
+ return requests.delete(self.api_url(['subscribe', 'billing', 'reserve', reserve_id]), headers={
160
+ 'Authorization': self.token,
161
+ 'Content-Type': 'application/json'
162
+ }).json()
163
+
164
+ # 4-3. 빌링키 삭제
165
+ def destroy_subscribe_billing_key(self, billing_key):
166
+ return requests.delete(self.api_url(['subscribe', 'billing', billing_key]), headers={
167
+ 'Authorization': self.token
168
+ }).json()
169
+
170
+ # 5. (부트페이 단독 - 간편결제창, 생체인증 기반의 사용자를 위한) 사용자 토큰 발급
171
+ def get_user_token(self, user_id=None, email=None, name=None, gender=None, birth=None, phone=None):
172
+ payload = {
173
+ 'user_id': user_id, # 개발사에서 관리하는 회원 고유 id
174
+ 'email': email, # 구매자 email
175
+ 'name': name, # 구매자 이름
176
+ 'gender': gender, # 0:여자, 1:남자
177
+ 'birth': birth, # 생일 901004
178
+ 'phone': phone # 01012341234
179
+ }
180
+
181
+ return requests.post(self.api_url(['request', 'user', 'token.json']), data=json.dumps(payload), headers={
182
+ 'Authorization': self.token
183
+ }).json()
184
+
185
+ # 6. 결제링크 생성
186
+ # user_info # 구매자 모델 설명
187
+ # {
188
+ # id: nil, # 개발사에서 관리하는 회원 고유 id
189
+ # username: nil, # 구매자 이름
190
+ # email: nil, # 구매자 email
191
+ # phone: nil, # 01012341234
192
+ # gender: nil, # 0:여자, 1:남자
193
+ # area: nil, # 서울|인천|대구|광주|부산|울산|경기|강원|충청북도|충북|충청남도|충남|전라북도|전북|전라남도|전남|경상북도|경북|경상남도|경남|제주|세종|대전 중 택 1
194
+ # birth: nil # 생일 901004
195
+ # },
196
+ # item 모델 설명
197
+ # {
198
+ # item_name: '', # 상품명
199
+ # qty: 1, # 수량
200
+ # unique: '', # 상품 고유키
201
+ # price: 1000, # 상품단가
202
+ # cat1: '', # 카테고리 상
203
+ # cat2: '', # 카테고리 중
204
+ # cat3: '' # 카테고리 하
205
+ # }
206
+ # extra 모델 설명
207
+ # {
208
+ # escrow: false, # 에스크로 연동 시 true, 기본값 false
209
+ # quota: [0,2,3], #List<int> 형태, 결제금액이 5만원 이상시 할부개월 허용범위를 설정할 수 있음, ex) "0,2,3" 지정시 - [0(일시불), 2개월, 3개월] 허용, 미설정시 PG사별 기본값 적용, 1 지정시 에러가 발생할 수 있음
210
+ # disp_cash_result: nil, # 현금영수증 노출할지 말지 (가상계좌 이용시)
211
+ # offer_period: '월 자동결제', # 통합결제창, PG 정기결제창에서 표시되는 '월 자동결제'에 해당하는 문구를 지정한 값으로 변경, 지원하는 PG사만 적용 가능
212
+ # theme: nil, # 통합결제창 테마, [ red, purple(기본), custom ] 중 택 1
213
+ # custom_background: nil, # 통합결제창 배경색, ex) "#00a086" theme가 custom 일 때 background 색상 지정 가능
214
+ # custom_font_color: nil # 통합결제창 글자색, ex) "#ffffff" theme가 custom 일 때 font color 색상 지정 가능
215
+ # }
216
+ def request_payment(self, pg=None, method=None, methods=None, price=None, order_id=None, params=None, tax_free=None,
217
+ name=None,
218
+ user_info={}, items=None, extra={}):
219
+
220
+ if items is None:
221
+ items = []
222
+
223
+ payload = {
224
+ 'pg': pg, # PG사의 Alias ex) danal, kcp, inicis 등
225
+ 'method': method, # 'card', # 결제수단 Alias ex) card, phone, vbank, bank, easy 중 1개, 미적용시 통합결제창
226
+ 'methods': methods, # ['card', 'phone'], # 결제수단 array, 통합결제창 사용시 활성화된 결제수단 중 사용할 method array 지정
227
+ 'price': price, # 결제할 상품금액
228
+ 'order_id': order_id, # 개발사에서 지정하는 고유주문번호
229
+ 'params': params, # 전달할 string, 결제 후 다시 되돌려 줌, json string 형태로 활용해도 무방
230
+ 'tax_free': tax_free, # 면세 상품일 경우 해당만큼의 금액을 설정
231
+ 'name': name, # 상품명
232
+ 'user_info': user_info, # 구매자 정보, 특정 PG사의 경우 구매자 휴대폰 번호를 필수로 받는다
233
+ 'extra': extra, # 기타 옵션
234
+ 'items': items # 구매할 상품정보, 통계용
235
+ }
236
+
237
+ return requests.post(self.api_url(['request', 'payment.json']), data=payload, headers={
238
+ 'Authorization': self.token
239
+ }).json()
240
+
241
+ # 7. 서버 승인 요청
242
+ def submit(self, receipt_id):
243
+ payload = {
244
+ 'receipt_id': receipt_id
245
+ }
246
+ return requests.post(self.api_url(['submit.json']), data=payload, headers={
247
+ 'Authorization': self.token
248
+ }).json()
249
+
250
+ # 8. 본인 인증 결과 검증
251
+ def certificate(self, receipt_id):
252
+ return requests.get(self.api_url(['certificate', receipt_id]), headers={
253
+ 'Authorization': self.token
254
+ }).json()
255
+
256
+ # deprecated
257
+ def remote_link(self, payload={}, sms_payload=None):
258
+ if sms_payload is None:
259
+ sms_payload = {}
260
+ payload['sms_payload'] = sms_payload
261
+ return requests.post(self.api_url(['app', 'rest', 'remote_link.json']), data=payload).json()
262
+
263
+ # deprecated
264
+ def remote_form(self, remoter_form, sms_payload=None):
265
+ if sms_payload is None:
266
+ sms_payload = {}
267
+ payload = {
268
+ 'application_id': self.application_id,
269
+ 'remote_form': remoter_form,
270
+ 'sms_payload': sms_payload
271
+ }
272
+ return requests.post(self.api_url(['app', 'rest', 'remote_form.json']), data=payload, headers={
273
+ 'Authorization': self.token
274
+ }).json()
275
+
276
+ # deprecated
277
+ def send_sms(self, receive_numbers, message, send_number=None, extra={}):
278
+ payload = {
279
+ 'data': {
280
+ 'sp': send_number,
281
+ 'rps': receive_numbers,
282
+ 'msg': message,
283
+ 'm_id': extra['m_id'],
284
+ 'o_id': extra['o_id']
285
+ }
286
+ }
287
+ return requests.post(self.api_url(['push', 'sms.json']), data=payload, headers={
288
+ 'Authorization': self.token
289
+ }).json()
290
+
291
+ # deprecated
292
+ def send_lms(self, receive_numbers, message, subject, send_number=None, extra={}):
293
+ payload = {
294
+ 'data': {
295
+ 'sp': send_number,
296
+ 'rps': receive_numbers,
297
+ 'msg': message,
298
+ 'sj': subject,
299
+ 'm_id': extra['m_id'],
300
+ 'o_id': extra['o_id']
301
+ }
302
+ }
303
+ return requests.post(self.api_url(['push', 'lms.json']), data=payload, headers={
304
+ 'Authorization': self.token
305
+ }).json()
@@ -0,0 +1,18 @@
1
+ dictionary = {
2
+ '한국은행': '001',
3
+ '기업은행': '003',
4
+ '외환은행': '005',
5
+ '수협은행': '007',
6
+ '농협은행': '011',
7
+ '우리은행': '020',
8
+ 'SC은행': '023',
9
+ '대구은행': '031',
10
+ '부산은행': '032',
11
+ '광주은행': '034',
12
+ '경남은행': '039',
13
+ '우체국': '071',
14
+ 'KEB하나은행': '081',
15
+ '신한은행': '088',
16
+ '케이뱅크': '089',
17
+ '카카오뱅크': '090',
18
+ }
@@ -0,0 +1,305 @@
1
+ import requests
2
+ import urllib.parse
3
+
4
+
5
+ class BootpayBackend:
6
+ BASE_URL = {
7
+ 'development': 'https://dev-api.bootpay.co.kr/v2',
8
+ 'stage': 'https://stage-api.bootpay.co.kr/v2',
9
+ 'production': 'https://api.bootpay.co.kr/v2'
10
+ }
11
+ API_VERSION = '4.2.7'
12
+ SDK_VERSION = '2.0.6'
13
+
14
+ def __init__(self, application_id, private_key, mode='production'):
15
+ self.application_id = application_id
16
+ self.private_key = private_key
17
+ self.mode = mode
18
+ self.token = None
19
+ self.api_version = self.API_VERSION
20
+
21
+ # API entrypoints
22
+ # Comment by GOSOMI
23
+ # @param url:string
24
+ # @returns string
25
+ def __entrypoints(self, url):
26
+ return '/'.join([self.BASE_URL[self.mode], url])
27
+
28
+ def set_api_version(self, version):
29
+ self.api_version = version
30
+
31
+ # Request Rest
32
+ # Comment by GOSOMI
33
+ # @param method: string, url: string, data: object, headers: object
34
+ # @returns ResponseForamt
35
+ def __request(self, method='', url='', data=None, headers={}, params={}):
36
+ if method in ['put', 'post']:
37
+ response = getattr(requests, method)(url, json=data, headers=dict(headers, **{
38
+ 'Accept': 'application/json',
39
+ 'Authorization': (None if self.token is None else f"Bearer {self.token}"),
40
+ 'BOOTPAY-API-VERSION': self.api_version,
41
+ 'BOOTPAY-SDK-VERSION': self.SDK_VERSION,
42
+ 'BOOTPAY-SDK-TYPE': '302'
43
+ }), params=params)
44
+ else:
45
+ response = getattr(requests, method)(url, headers=dict(headers, **{
46
+ 'Accept': 'application/json',
47
+ 'Authorization': (None if self.token is None else f"Bearer {self.token}")
48
+ }), params=params)
49
+ return response.json()
50
+
51
+ # Get AccessToken
52
+ # Comment by GOSOMI
53
+ def get_access_token(self):
54
+ response = self.__request(method='post', url=self.__entrypoints('request/token'), data={
55
+ 'application_id': self.application_id,
56
+ 'private_key': self.private_key
57
+ })
58
+ if 'error_code' not in response:
59
+ self.token = response['access_token']
60
+ return response
61
+
62
+ # Get Receipt Payment Data
63
+ # Comment by GOSOMI
64
+ # @param receipt_id: string
65
+ def receipt_payment(self, receipt_id=''):
66
+ return self.__request(method='get', url=self.__entrypoints(f'receipt/{receipt_id}'))
67
+
68
+ # certificate
69
+ # Comment by GOSOMI
70
+ # @param receipt_id: string
71
+ def certificate(self, receipt_id=''):
72
+ return self.__request(method='get', url=self.__entrypoints(f'certificate/{receipt_id}'))
73
+
74
+ # confirm payment
75
+ # Comment by GOSOMI
76
+ # @param receipt_id: string
77
+ def confirm_payment(self, receipt_id=''):
78
+ return self.__request(method='post', url=self.__entrypoints('confirm'), data={"receipt_id": receipt_id})
79
+
80
+ # lookup subscribe billing key
81
+ # Comment by GOSOMI
82
+ # @param receipt_id:string
83
+ def lookup_subscribe_billing_key(self, receipt_id=''):
84
+ return self.__request(method='get', url=self.__entrypoints(f'subscribe/billing_key/{receipt_id}'))
85
+
86
+ # request subscribe billing key
87
+ # Comment by GOSOMI
88
+ def request_subscribe_billing_key(self, pg='', order_name='', subscription_id='', card_no='', card_pw='',
89
+ card_identity_no='', card_expire_year='', card_expire_month='', price=0,
90
+ tax_free=0, extra=None, user=None, metadata=None):
91
+ return self.__request(method='post', url=self.__entrypoints('request/subscribe'), data={
92
+ "pg": pg,
93
+ "order_name": order_name,
94
+ "subscription_id": subscription_id,
95
+ "card_no": card_no,
96
+ "card_pw": card_pw,
97
+ "card_identity_no": card_identity_no,
98
+ "card_expire_year": card_expire_year,
99
+ "card_expire_month": card_expire_month,
100
+ "price": price,
101
+ "tax_free": tax_free,
102
+ "extra": extra,
103
+ "user": user,
104
+ "metadata": metadata
105
+ })
106
+
107
+ # request subscribe card payment
108
+ # Comment by GOSOMI
109
+ def request_subscribe_card_payment(self, billing_key='', order_name='', price=0, tax_free=0, card_quota='00',
110
+ card_interest=None, order_id='', items=None, user=None, extra=None):
111
+ return self.__request(method='post', url=self.__entrypoints('subscribe/payment'), data={
112
+ "billing_key": billing_key,
113
+ "order_name": order_name,
114
+ "price": price,
115
+ "tax_free": tax_free,
116
+ "card_quota": card_quota,
117
+ "card_interest": card_interest,
118
+ "order_id": order_id,
119
+ "items": items,
120
+ "user": user,
121
+ "extra": extra
122
+ })
123
+
124
+ # destroy billing key
125
+ # Comment by GOSOMI
126
+ def destroy_billing_key(self, billing_key=''):
127
+ return self.__request(method='delete', url=self.__entrypoints(f'subscribe/billing_key/{billing_key}'))
128
+
129
+ # request user token
130
+ # Comment by GOSOMI
131
+ def request_user_token(self, user_id='', email=None, username=None, gender=None, birth=None, phone=None):
132
+ return self.__request(method='post', url=self.__entrypoints('request/user/token'), data={
133
+ "user_id": user_id,
134
+ "email": email,
135
+ "username": username,
136
+ "gender": gender,
137
+ "birth": birth,
138
+ "phone": phone
139
+ })
140
+
141
+ # subscribe payment reserve
142
+ # Comment by GOSOMI
143
+ def subscribe_payment_reserve(self, billing_key='', order_name='', price=0, tax_free=0, order_id='', items=None,
144
+ user=None, reserve_execute_at='', feedback_url='', content_type=''):
145
+ return self.__request(method='post', url=self.__entrypoints('subscribe/payment/reserve'), data={
146
+ "billing_key": billing_key,
147
+ "order_name": order_name,
148
+ "price": price,
149
+ "tax_free": tax_free,
150
+ "order_id": order_id,
151
+ "items": items,
152
+ "user": user,
153
+ "reserve_execute_at": reserve_execute_at,
154
+ "feedback_url": feedback_url,
155
+ "content_type": content_type
156
+ })
157
+
158
+ def cancel_payment(self, receipt_id='', cancel_id='', cancel_username='', cancel_message='', cancel_price=None,
159
+ cancel_tax_free=None, refund=None, items=None):
160
+ return self.__request(method='post', url=self.__entrypoints('cancel'), data={
161
+ "receipt_id": receipt_id,
162
+ "cancel_id": cancel_id,
163
+ "cancel_username": cancel_username,
164
+ "cancel_message": cancel_message,
165
+ "cancel_price": cancel_price,
166
+ "cancel_tax_free": cancel_tax_free,
167
+ "refund": refund,
168
+ "items": items
169
+ })
170
+
171
+ # subscribe payment reserve lookup
172
+ # Comment by GOSOMI
173
+ # @date: 2023-03-08
174
+ def subscribe_payment_reserve_lookup(self, reserve_id=''):
175
+ return self.__request(method='get', url=self.__entrypoints(f'subscribe/payment/reserve/{reserve_id}'))
176
+
177
+ # cancel subscribe reserve
178
+ # Comment by GOSOMI
179
+ def cancel_subscribe_reserve(self, reserve_id=''):
180
+ return self.__request(method='delete', url=self.__entrypoints(f'subscribe/payment/reserve/{reserve_id}'))
181
+
182
+ def shipping_start(self, receipt_id='', tracking_number='', delivery_corp='', shipping_prepayment=None,
183
+ shipping_day=None, user=None, company=None):
184
+ return self.__request(method='put', url=self.__entrypoints(f'escrow/shipping/start/{receipt_id}'), data={
185
+ "tracking_number": tracking_number,
186
+ "delivery_corp": delivery_corp,
187
+ "shipping_prepayment": shipping_prepayment,
188
+ "shipping_day": shipping_day,
189
+ "user": user,
190
+ "company": company
191
+ })
192
+
193
+ # 현금영수증 발행
194
+ # Comment by GOSOMI
195
+ # @date: 2022-07-28
196
+ def cash_receipt_publish_on_receipt(self, receipt_id='', username='', email='', phone='', identity_no='',
197
+ cash_receipt_type='소득공제'):
198
+ return self.__request(method='post', url=self.__entrypoints('request/receipt/cash/publish'), data={
199
+ "receipt_id": receipt_id,
200
+ "username": username,
201
+ "email": email,
202
+ "phone": phone,
203
+ "identity_no": identity_no,
204
+ "cash_receipt_type": cash_receipt_type
205
+ })
206
+
207
+ # 현금영수증 취소
208
+ # Comment by GOSOMI
209
+ # @date: 2022-07-28
210
+ def cash_receipt_cancel_on_receipt(self, receipt_id='', cancel_username='시스템', cancel_message='현금영수증 취소'):
211
+ return self.__request(
212
+ method='delete',
213
+ url=self.__entrypoints(
214
+ f'request/receipt/cash/cancel/{receipt_id}?'
215
+ ),
216
+ params=dict({
217
+ "cancel_username": cancel_username,
218
+ "cancel_message": cancel_message
219
+ })
220
+ )
221
+
222
+ # 현금 영수증 별건 발행
223
+ # Comment by GOSOMI
224
+ # @date: 2022-08-09
225
+ def request_cash_receipt(self, pg='', order_name='', identity_no='', purchased_at='', cash_receipt_type='소득공제',
226
+ price=0, tax_free=0, user=None, metadata=None, extra={}, order_id=''):
227
+ return self.__request(
228
+ method='post',
229
+ url=self.__entrypoints('request/cash/receipt'),
230
+ data={
231
+ "pg": pg,
232
+ "order_id": order_id,
233
+ "order_name": order_name,
234
+ "identity_no": identity_no,
235
+ "purchased_at": purchased_at,
236
+ "cash_receipt_type": cash_receipt_type,
237
+ "price": price,
238
+ "tax_free": tax_free,
239
+ "user": user,
240
+ "metadata": metadata,
241
+ "extra": extra
242
+ }
243
+ )
244
+
245
+ # 현금영수증 별건 발행 취소하기
246
+ # Comment by GOSOMI
247
+ # @date: 2022-08-09
248
+ def cancel_cash_receipt(self, receipt_id='', cancel_username='', cancel_message=''):
249
+ return self.__request(
250
+ method='delete',
251
+ url=self.__entrypoints(f'request/cash/receipt/{receipt_id}'),
252
+ params=dict({
253
+ "cancel_username": cancel_username,
254
+ "cancel_message": cancel_message
255
+ })
256
+ )
257
+
258
+ # 본인인증 REST API 요청
259
+ # Comment by GOSOMI
260
+ # @date: 2022-11-07
261
+ def request_authentication(self, pg='', method='', username='', identity_no='', carrier='', phone='', site_url='',
262
+ order_name='', authentication_id='', authenticate_type='sms', user=None, extra={}):
263
+ return self.__request(
264
+ method='post',
265
+ url=self.__entrypoints('request/authentication'),
266
+ data={
267
+ "pg": pg,
268
+ "method": method,
269
+ "authentication_id": authentication_id,
270
+ "authenticate_type": authenticate_type,
271
+ "username": username,
272
+ "identity_no": identity_no,
273
+ "carrier": carrier,
274
+ "phone": phone,
275
+ "site_url": site_url,
276
+ "order_name": order_name,
277
+ "user": user,
278
+ "extra": extra
279
+ }
280
+ )
281
+
282
+ # 본인인증 승인 REST API
283
+ # Comment by GOSOMI
284
+ # @date: 2022-11-07
285
+ def confirm_authentication(self, receipt_id='', otp=''):
286
+ return self.__request(
287
+ method='post',
288
+ url=self.__entrypoints('authenticate/confirm'),
289
+ data={
290
+ "receipt_id": receipt_id,
291
+ "otp": otp
292
+ }
293
+ )
294
+
295
+ # SMS로 본인인증 요청시 SMS 재발송 로직
296
+ # Comment by GOSOMI
297
+ # @date: 2022-11-07
298
+ def realarm_authentication(self, receipt_id=''):
299
+ return self.__request(
300
+ method='post',
301
+ url=self.__entrypoints('authenticate/realarm'),
302
+ data={
303
+ "receipt_id": receipt_id
304
+ }
305
+ )
@@ -0,0 +1,380 @@
1
+ Metadata-Version: 2.1
2
+ Name: bootpay-backend
3
+ Version: 2.0.6
4
+ Summary: bootpay server side plugin for python
5
+ Home-page: https://github.com/bootpay/backend-python/tree/2-x-development
6
+ Author: bootpay <bootpay.co.kr@gmail.com>
7
+ License: MIT
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Programming Language :: Python :: 2
14
+ Classifier: Programming Language :: Python :: 2.7
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.4
17
+ Classifier: Programming Language :: Python :: 3.5
18
+ Classifier: Programming Language :: Python :: 3.6
19
+ Classifier: Programming Language :: Python :: 3.7
20
+ Classifier: Programming Language :: Python :: 3.8
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+
29
+
30
+ ## Bootpay Python Server Side Library
31
+ 부트페이 공식 파이썬 라이브러리 입니다 (서버사이드 용)
32
+
33
+ Python 언어로 작성된 어플리케이션, 프레임워크 등에서 사용가능합니다.
34
+
35
+ * PG 결제창 연동은 클라이언트 라이브러리에서 수행됩니다. (Javascript, Android, iOS, React Native, Flutter 등)
36
+ * 결제 검증 및 취소, 빌링키 발급, 본인인증 등의 수행은 서버사이드에서 진행됩니다. (Java, PHP, Python, Ruby, Node.js, Go, ASP.NET 등)
37
+
38
+
39
+ ## 기능
40
+ 1. (부트페이 통신을 위한) 토큰 발급
41
+ 2. 결제 단건 조회
42
+ 3. 결제 취소 (전액 취소 / 부분 취소)
43
+ 4. 신용카드 자동결제 (빌링결제)
44
+
45
+ 4-1. 빌링키 발급
46
+
47
+ 4-2. 발급된 빌링키로 결제 승인 요청
48
+
49
+ 4-3. 발급된 빌링키로 결제 예약 요청
50
+
51
+ 4-4. 발급된 빌링키로 결제 예약 - 취소 요청
52
+
53
+ 4-5. 빌링키 삭제
54
+
55
+ 4-6. 빌링키 조회
56
+
57
+ 5. (생체인증, 비밀번호 결제를 위한) 구매자 토큰 발급
58
+ 6. 서버 승인 요청
59
+ 7. 본인 인증 결과 조회
60
+ 8. (에스크로 이용시) PG사로 배송정보 보내기
61
+ 9. 현금영수증 발행
62
+
63
+ 9-1. 현금영수증 발행
64
+
65
+ 9-2. 현금영수증 발행 취소
66
+
67
+ 9-3. (별건) 현금영수증 발행
68
+
69
+ 9-4. (별건) 현금영수증 발행 취소
70
+ ## pypi로 설치하기
71
+
72
+
73
+ ```
74
+ pip install bootpay-backend
75
+ ```
76
+
77
+ # 사용하기
78
+
79
+ ```python
80
+
81
+ from bootpay_backend import BootpayBackend
82
+
83
+ bootpay = BootpayBackend('5b8f6a4d396fa665fdc2b5ea', 'rm6EYECr6aroQVG2ntW0A6LpWnkTgP4uQ3H18sDDUYw=')
84
+
85
+ token = bootpay.get_access_token()
86
+ if 'error_code' not in token:
87
+ # 토큰 발급 성공
88
+ print(token)
89
+ ```
90
+
91
+
92
+ ## 1. (부트페이 통신을 위한) 토큰 발급
93
+
94
+ 부트페이와 서버간 통신을 하기 위해서는 부트페이 서버로부터 토큰을 발급받아야 합니다.
95
+ 발급된 토큰은 30분간 유효하며, 최초 발급일로부터 30분이 지날 경우 토큰 발급 함수를 재호출 해주셔야 합니다.
96
+
97
+ ```python
98
+ bootpay = BootpayBackend('5b8f6a4d396fa665fdc2b5ea', 'rm6EYECr6aroQVG2ntW0A6LpWnkTgP4uQ3H18sDDUYw=')
99
+
100
+ token = bootpay.get_access_token()
101
+ if 'error_code' not in token:
102
+ # 토큰 발급 성공
103
+ print(token)
104
+ ```
105
+
106
+
107
+ ## 2. 결제 단건 조회
108
+ 결제창 및 정기결제에서 승인/취소된 결제건에 대하여 올바른 결제건인지 서버간 통신으로 결제검증을 합니다.
109
+ ```python
110
+ response = bootpay.receipt_payment('62b2c3c2d01c7e001bc20b10')
111
+ if 'error_code' not in response:
112
+ # 요청 성공
113
+ print(response)
114
+ ```
115
+
116
+ ## 3. 결제 취소 (전액 취소 / 부분 취소)
117
+ price를 지정하지 않으면 전액취소 됩니다.
118
+ * 휴대폰 결제의 경우 이월될 경우 이통사 정책상 취소되지 않습니다
119
+ * 정산받으실 금액보다 취소금액이 클 경우 PG사 정책상 취소되지 않을 수 있습니다. 이때 PG사에 문의하시면 되겠습니다.
120
+ * 가상계좌의 경우 CMS 특약이 되어있지 않으면 취소되지 않습니다. 그러므로 결제 테스트시에는 가상계좌로 테스트 하지 않길 추천합니다.
121
+
122
+ 부분취는 카드로 결제된 건만 가능하며, 일부 PG사만 지원합니다. 요청시 price에 금액을 지정하시면 되겠습니다.
123
+ * (지원가능 PG사: 이니시스, kcp, 다날, 페이레터, 나이스페이, 카카오페이, 페이코)
124
+
125
+ 간혹 개발사에서 실수로 여러번 부분취소를 보내서 여러번 취소되는 경우가 있기때문에, 부트페이에서는 부분취소 중복 요청을 막기 위해 cancel_id 라는 필드를 추가했습니다. cancel_id를 지정하시면, 해당 건에 대해 중복 요청방지가 가능합니다.
126
+ ```python
127
+ response = bootpay.cancel_payment(
128
+ receipt_id='62ba5a3cd01c7e001fb45c46',
129
+ cancel_id=str(uuid.uuid4()),
130
+ cancel_username='test',
131
+ cancel_message='test결제 취소'
132
+ )
133
+ if 'error_code' not in response:
134
+ # 요청 성공
135
+ print(response)
136
+ ```
137
+
138
+ ## 4-1. 빌링키 발급
139
+ REST API 방식으로 고객으로부터 카드 정보를 전달하여, PG사에게 빌링키를 발급받을 수 있습니다.
140
+ 발급받은 빌링키를 저장하고 있다가, 원하는 시점, 원하는 금액에 결제 승인 요청하여 좀 더 자유로운 결제시나리오에 적용이 가능합니다.
141
+ * 비인증 정기결제(REST API) 방식을 지원하는 PG사만 사용 가능합니다.
142
+ ```python
143
+ response = bootpay.request_subscribe_billing_key(
144
+ pg='나이스페이',
145
+ order_name='테스트결제',
146
+ subscription_id=str(time.time()),
147
+ card_no="5570********1074", # 카드번호
148
+ card_pw="**", # 카드 비밀번호 2자리
149
+ card_identity_no="******", # 카드 소주 생년월일
150
+ card_expire_year="**", # 카드 유효기간 년 2자리
151
+ card_expire_month="**", # 카드 유효기간 월 2자리
152
+
153
+ )
154
+ if 'error_code' not in response:
155
+ # 요청 성공
156
+ print(response)
157
+ ```
158
+
159
+ ## 4-2. 발급된 빌링키로 결제 승인 요청
160
+ 발급된 빌링키로 원하는 시점에 원하는 금액으로 결제 승인 요청을 할 수 있습니다. 잔액이 부족하거나 도난 카드 등의 특별한 건이 아니면 PG사에서 결제를 바로 승인합니다.
161
+
162
+ ```python
163
+ response = bootpay.request_subscribe_card_payment(
164
+ billing_key='62b2c3cfd01c7e001cc20a84',
165
+ order_name='테스트결제',
166
+ order_id=str(time.time()),
167
+ price=100,
168
+ user={
169
+ "phone": '01000000000',
170
+ "username": '홍길동',
171
+ "email": 'test@bootpay.co.kr'
172
+ }
173
+ )
174
+ if 'error_code' not in response:
175
+ # 요청 성공
176
+ print(response)
177
+ ```
178
+ ## 4-3. 발급된 빌링키로 결제 예약 요청
179
+ 원하는 시점에 4-1로 결제 승인 요청을 보내도 되지만, 빌링키 발급 이후에 바로 결제 예약 할 수 있습니다. (빌링키당 최대 10건)
180
+ ```python
181
+ response = bootpay.subscribe_payment_reserve(
182
+ billing_key='[ 빌링키 ]',
183
+ order_name='테스트결제',
184
+ order_id=str(time.time()),
185
+ price=1000,
186
+ user={
187
+ "phone": '01000000000',
188
+ "username": '홍길동',
189
+ "email": 'test@bootpay.co.kr'
190
+ },
191
+ reserve_execute_at=(datetime.datetime.now() + datetime.timedelta(seconds=5)).astimezone().strftime(
192
+ '%Y-%m-%dT%H:%M:%S%z')
193
+ )
194
+ if 'error_code' not in response:
195
+ # 요청 성공
196
+ print(response)
197
+ ```
198
+
199
+ ## 4-4. 발급된 빌링키로 결제 예약 - 취소 요청
200
+ 빌링키로 예약된 결제건을 취소합니다.
201
+ ```python
202
+ result = bootpay.cancel_subscribe_reserve(
203
+ '612debc70d681b0039e6133d'
204
+ )
205
+ if 'error_code' not in response:
206
+ # 요청 성공
207
+ print(response)
208
+ ```
209
+
210
+ ## 4-5. 빌링키 삭제
211
+ 발급된 빌링키로 더 이상 사용되지 않도록, 삭제 요청합니다.
212
+ ```python
213
+ response = bootpay.destroy_billing_key(
214
+ billing_key='62b2c3cfd01c7e001cc20a85',
215
+ )
216
+ if 'error_code' not in response:
217
+ # 요청 성공
218
+ print(response)
219
+ ```
220
+
221
+ ## 4-6. 빌링키 조회
222
+ (빌링키 발급 완료시 리턴받았던 receipt_id에 한정) 어떤 빌링키였는지 조회합니다.
223
+ ```python
224
+ response = bootpay.lookup_subscribe_billing_key('62b2c3c2d01c7e001bc20b10')
225
+ if 'error_code' not in response:
226
+ # 요청 성공
227
+ print(response)
228
+ ```
229
+
230
+
231
+ ## 5. (생체인증, 비밀번호 결제를 위한) 구매자 토큰 발급
232
+ (부트페이 단독) 부트페이에서 제공하는 간편결제창, 생체인증 기반의 결제 사용을 위해서는 개발사에서 회원 고유번호를 관리해야하며, 해당 회원에 대한 사용자 토큰을 발급합니다.
233
+ 이 토큰값을 기반으로 클라이언트에서 결제요청 하시면 되겠습니다.
234
+ ```python
235
+ result = bootpay.request_user_token({
236
+ 'user_id': '12341-234',
237
+ 'email': 'test@email.com',
238
+ 'name': '홍길동',
239
+ 'gender': '1',
240
+ 'birth': '901014',
241
+ 'phone': '01012341234'
242
+ })
243
+ if 'error_code' not in token:
244
+ # 요청 성공
245
+ print(response)
246
+ ```
247
+
248
+ ## 6. 서버 승인 요청
249
+ 결제승인 방식은 클라이언트 승인 방식과, 서버 승인 방식으로 총 2가지가 있습니다.
250
+
251
+ 클라이언트 승인 방식은 pythonscript나 native 등에서 confirm 함수에서 진행하는 일반적인 방법입니다만, 경우에 따라 서버 승인 방식이 필요할 수 있습니다.
252
+
253
+ 필요한 이유
254
+ 1. 100% 안정적인 결제 후 고객 안내를 위해 - 클라이언트에서 PG결제 진행 후 승인 완료될 때 onDone이 수행되지 않아 (인터넷 환경 등), 결제 이후 고객에게 안내하지 못할 수 있습니다
255
+ 2. 단일 트랜잭션의 개념이 필요할 경우 - 재고파악이 중요한 커머스를 운영할 경우 트랜잭션 개념이 필요할 수 있겠으며, 이를 위해서는 서버 승인을 사용해야 합니다.
256
+
257
+ ```python
258
+ result = bootpay.confirm_payment(
259
+ receipt_id='612df0250d681b001de61de6'
260
+ )
261
+ if 'error_code' not in token:
262
+ # 요청 성공
263
+ print(response)
264
+ ```
265
+
266
+ ## 7. 본인 인증 결과 조회
267
+ 다날 본인인증 후 결과값을 조회합니다.
268
+ 다날 본인인증에서 통신사, 외국인여부, 전화번호 이 3가지 정보는 다날에 추가로 요청하셔야 받으실 수 있습니다.
269
+ ```python
270
+ result = bootpay.certificate(
271
+ receipt_id='612df0250d681b001de61de6'
272
+ )
273
+ if 'error_code' not in token:
274
+ # 요청 성공
275
+ print(response)
276
+ ```
277
+
278
+
279
+ 8. (에스크로 이용시) PG사로 배송정보 보내기
280
+ 현금 거래에 한해 구매자의 안전거래를 보장하는 방법으로, 판매자와 구매자의 온라인 전자상거래가 원활하게 이루어질 수 있도록 중계해주는 매매보호서비스입니다. 국내법에 따라 전자상거래에서 반드시 적용이 되어 있어야합니다. PG에서도 에스크로 결제를 지원하며, 에스크로 결제 사용을 원하시면 PG사 가맹시에 에스크로결제를 미리 얘기하고나서 진행을 하시는 것이 수월합니다.
281
+
282
+ PG사로 배송정보( 이니시스, KCP만 지원 )를 보내서 에스크로 상태를 변경하는 API 입니다.
283
+ ```python
284
+ response = bootpay.shipping_start(
285
+ receipt_id="62a946aad01c7e001b7dc20b",
286
+ tracking_number='3989838',
287
+ delivery_corp='CJ대한통운',
288
+ user={
289
+ "phone": '01000000000',
290
+ "username": '홍길동',
291
+ "address": "서울특별시 종로구",
292
+ "zipcode": "039899"
293
+ }
294
+ )
295
+ if 'error_code' not in token:
296
+ # 요청 성공
297
+ print(response)
298
+ ```
299
+
300
+ ## 9-1. 현금영수증 발행하기
301
+ bootpay api를 통해 결제된 건에 대하여 현금영수증을 발행합니다.
302
+
303
+ ```python
304
+ response = bootpay.cash_receipt_publish_on_receipt(
305
+ receipt_id='62e0f11f1fc192036b1b3c92',
306
+ username='테스트',
307
+ email='test@bootpay.co.kr',
308
+ phone='01000000000',
309
+ identity_no='01000000000',
310
+ cash_receipt_type='소득공제'
311
+ )
312
+ if 'error_code' not in token:
313
+ # 요청 성공
314
+ print(response)
315
+ ```
316
+
317
+
318
+ ## 9-2. 현금영수증 발행 취소
319
+ 9-1을 통해 발행한 현금영수증을 취소합니다.
320
+ ```python
321
+ response = bootpay.cash_receipt_cancel_on_receipt(
322
+ receipt_id='62e0f11f1fc192036b1b3c92',
323
+ )
324
+ if 'error_code' not in token:
325
+ # 요청 성공
326
+ print(response)
327
+ ```
328
+
329
+ ## 9-3. (별건) 현금영수증 발행
330
+ 부트페이 결제와 상관없이 금액, 상품명, 현금영수증 발행정보 등을 보내 현금영수증을 발행하는 API 입니다
331
+ ```python
332
+ response = bootpay.request_cash_receipt(
333
+ pg='토스',
334
+ price=1000,
335
+ order_name='테스트',
336
+ cash_receipt_type='소득공제',
337
+ user={
338
+ "username": '부트페이',
339
+ "phone": '01000000000',
340
+ "email": "bootpay@bootpay.co.kr"
341
+ },
342
+ identity_no='01000000000',
343
+ purchased_at=datetime.datetime.now().astimezone().strftime(
344
+ '%Y-%m-%dT%H:%M:%S%z'),
345
+ order_id=str(time.time())
346
+ )
347
+ if 'error_code' not in token:
348
+ # 요청 성공
349
+ print(response)
350
+ ```
351
+
352
+ ## 9-4. (별건) 현금영수증 발행 취소
353
+ 9-3을 통해 발행한 현금영수증을 취소합니다.
354
+ ```python
355
+ response = bootpay.cancel_cash_receipt(
356
+ receipt_id='62f20fc21fc192036b4f6f89',
357
+ cancel_username='시스템',
358
+ cancel_message='테스트'
359
+ )
360
+ if 'error_code' not in token:
361
+ # 요청 성공
362
+ print(response)
363
+ ```
364
+
365
+ ## Example 프로젝트
366
+
367
+ [적용한 샘플 프로젝트](https://github.com/bootpay/backend-python-example)을 참조해주세요
368
+
369
+ ## Documentation
370
+
371
+ [부트페이 개발매뉴얼](https://docs.bootpay.co.kr/next/)을 참조해주세요
372
+
373
+ ## 기술문의
374
+
375
+ [부트페이 홈페이지](https://www.bootpay.co.kr) 우측 하단 채팅을 통해 기술문의 주세요!
376
+
377
+ ## License
378
+
379
+ [MIT License](https://opensource.org/licenses/MIT).
380
+
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ README.md
3
+ setup.cfg
4
+ setup.py
5
+ bootpay_backend/__init__.py
6
+ bootpay_backend/bankcode.py
7
+ bootpay_backend/rest_client.py
8
+ bootpay_backend.egg-info/PKG-INFO
9
+ bootpay_backend.egg-info/SOURCES.txt
10
+ bootpay_backend.egg-info/dependency_links.txt
11
+ bootpay_backend.egg-info/not-zip-safe
12
+ bootpay_backend.egg-info/requires.txt
13
+ bootpay_backend.egg-info/top_level.txt
@@ -0,0 +1,6 @@
1
+
2
+ [:python_version < "3.0"]
3
+ requests[security]>=2.20
4
+
5
+ [:python_version >= "3.0"]
6
+ requests>=2.20