bootpay-backend 2.2.0__tar.gz → 2.3.0__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.
Files changed (49) hide show
  1. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/PKG-INFO +43 -4
  2. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/README.md +31 -2
  3. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/commerce/__init__.py +46 -1
  4. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/commerce/commerce_resource.py +7 -4
  5. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/commerce/modules/__init__.py +13 -1
  6. bootpay_backend-2.3.0/bootpay_backend/commerce/modules/cart.py +29 -0
  7. bootpay_backend-2.3.0/bootpay_backend/commerce/modules/category.py +60 -0
  8. bootpay_backend-2.3.0/bootpay_backend/commerce/modules/coupon.py +51 -0
  9. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/commerce/modules/order_subscription.py +86 -1
  10. bootpay_backend-2.3.0/bootpay_backend/commerce/modules/order_subscription_request.py +92 -0
  11. bootpay_backend-2.3.0/bootpay_backend/commerce/modules/point.py +43 -0
  12. bootpay_backend-2.3.0/bootpay_backend/commerce/modules/store.py +25 -0
  13. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/commerce/modules/user_group.py +2 -2
  14. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/commerce/types/__init__.py +247 -0
  15. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/rest_client.py +103 -29
  16. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend.egg-info/PKG-INFO +44 -5
  17. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend.egg-info/SOURCES.txt +23 -1
  18. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend.egg-info/top_level.txt +1 -0
  19. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/setup.py +1 -1
  20. bootpay_backend-2.3.0/tests/__init__.py +0 -0
  21. bootpay_backend-2.3.0/tests/commerce/__init__.py +0 -0
  22. bootpay_backend-2.3.0/tests/commerce/test_order.py +61 -0
  23. bootpay_backend-2.3.0/tests/commerce/test_product.py +75 -0
  24. bootpay_backend-2.3.0/tests/commerce/test_store.py +20 -0
  25. bootpay_backend-2.3.0/tests/commerce/test_token.py +58 -0
  26. bootpay_backend-2.3.0/tests/commerce/test_user.py +81 -0
  27. bootpay_backend-2.3.0/tests/conftest.py +145 -0
  28. bootpay_backend-2.3.0/tests/pg/__init__.py +0 -0
  29. bootpay_backend-2.3.0/tests/pg/test_auth.py +66 -0
  30. bootpay_backend-2.3.0/tests/pg/test_billing.py +91 -0
  31. bootpay_backend-2.3.0/tests/pg/test_cash_receipt.py +59 -0
  32. bootpay_backend-2.3.0/tests/pg/test_legacy_compatibility.py +90 -0
  33. bootpay_backend-2.3.0/tests/pg/test_payment.py +45 -0
  34. bootpay_backend-2.3.0/tests/pg/test_token.py +55 -0
  35. bootpay_backend-2.3.0/tests/pg/test_wallet.py +33 -0
  36. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/LICENSE +0 -0
  37. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/__init__.py +0 -0
  38. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/bankcode.py +0 -0
  39. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/commerce/modules/invoice.py +0 -0
  40. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/commerce/modules/order.py +0 -0
  41. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/commerce/modules/order_cancel.py +0 -0
  42. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/commerce/modules/order_subscription_adjustment.py +0 -0
  43. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/commerce/modules/order_subscription_bill.py +0 -0
  44. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/commerce/modules/product.py +0 -0
  45. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend/commerce/modules/user.py +0 -0
  46. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend.egg-info/dependency_links.txt +0 -0
  47. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend.egg-info/not-zip-safe +0 -0
  48. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/bootpay_backend.egg-info/requires.txt +0 -0
  49. {bootpay_backend-2.2.0 → bootpay_backend-2.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: bootpay_backend
3
- Version: 2.2.0
3
+ Version: 2.3.0
4
4
  Summary: bootpay server side plugin for python
5
5
  Home-page: https://github.com/bootpay/backend-python/tree/2-x-development
6
6
  Author: bootpay <bootpay.co.kr@gmail.com>
@@ -27,6 +27,16 @@ Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  Requires-Dist: requests>=2.20; python_version >= "3.0"
29
29
  Requires-Dist: requests[security]>=2.20; python_version < "3.0"
30
+ Dynamic: author
31
+ Dynamic: classifier
32
+ Dynamic: description
33
+ Dynamic: description-content-type
34
+ Dynamic: home-page
35
+ Dynamic: license
36
+ Dynamic: license-file
37
+ Dynamic: requires-dist
38
+ Dynamic: requires-python
39
+ Dynamic: summary
30
40
 
31
41
 
32
42
  ## Bootpay Python Server Side Library
@@ -70,13 +80,42 @@ Python 언어로 작성된 어플리케이션, 프레임워크 등에서 사용
70
80
  pip install bootpay-backend
71
81
  ```
72
82
 
83
+
84
+ ## 환경변수 설정
85
+
86
+ 예제와 테스트는 각 SDK 루트의 `.env` 파일을 우선 읽습니다. 먼저 `.env.example`을 복사한 뒤 필요한 키만 변경하세요. `.env`는 gitignore 처리되어 커밋되지 않습니다.
87
+
88
+ ```bash
89
+ cp .env.example .env
90
+ # BOOTPAY_ENV=production 또는 development
91
+ ```
92
+
93
+ 주요 변수:
94
+
95
+ ```env
96
+ BOOTPAY_ENV=production
97
+ BOOTPAY_PG_CLIENT_KEY_PROD=...
98
+ BOOTPAY_PG_SECRET_KEY_PROD=...
99
+ BOOTPAY_PG_CLIENT_KEY_DEV=...
100
+ BOOTPAY_PG_SECRET_KEY_DEV=...
101
+ BOOTPAY_COMMERCE_CLIENT_KEY_PROD=...
102
+ BOOTPAY_COMMERCE_SECRET_KEY_PROD=...
103
+ BOOTPAY_COMMERCE_CLIENT_KEY_DEV=...
104
+ BOOTPAY_COMMERCE_SECRET_KEY_DEV=...
105
+ ```
106
+
107
+ 변수가 없으면 SDK 테스트용 기본값(NodeJS 기준 ck/sk)으로 fallback 합니다.
108
+
73
109
  # 사용하기
74
110
 
111
+ > 권장 인증 방식은 `client_key/secret_key`입니다. 기존 positional `application_id/private_key` 방식도 계속 지원됩니다.
112
+
75
113
  ```python
76
114
 
115
+ import os
77
116
  from bootpay_backend import BootpayBackend
78
117
 
79
- bootpay = BootpayBackend('5b8f6a4d396fa665fdc2b5ea', 'rm6EYECr6aroQVG2ntW0A6LpWnkTgP4uQ3H18sDDUYw=')
118
+ bootpay = BootpayBackend(client_key=os.getenv('BOOTPAY_PG_CLIENT_KEY_PROD'), secret_key=os.getenv('BOOTPAY_PG_SECRET_KEY_PROD'))
80
119
 
81
120
  token = bootpay.get_access_token()
82
121
  if 'error_code' not in token:
@@ -91,7 +130,7 @@ if 'error_code' not in token:
91
130
  발급된 토큰은 30분간 유효하며, 최초 발급일로부터 30분이 지날 경우 토큰 발급 함수를 재호출 해주셔야 합니다.
92
131
 
93
132
  ```python
94
- bootpay = BootpayBackend('5b8f6a4d396fa665fdc2b5ea', 'rm6EYECr6aroQVG2ntW0A6LpWnkTgP4uQ3H18sDDUYw=')
133
+ bootpay = BootpayBackend(client_key=os.getenv('BOOTPAY_PG_CLIENT_KEY_PROD'), secret_key=os.getenv('BOOTPAY_PG_SECRET_KEY_PROD'))
95
134
 
96
135
  token = bootpay.get_access_token()
97
136
  if 'error_code' not in token:
@@ -40,13 +40,42 @@ Python 언어로 작성된 어플리케이션, 프레임워크 등에서 사용
40
40
  pip install bootpay-backend
41
41
  ```
42
42
 
43
+
44
+ ## 환경변수 설정
45
+
46
+ 예제와 테스트는 각 SDK 루트의 `.env` 파일을 우선 읽습니다. 먼저 `.env.example`을 복사한 뒤 필요한 키만 변경하세요. `.env`는 gitignore 처리되어 커밋되지 않습니다.
47
+
48
+ ```bash
49
+ cp .env.example .env
50
+ # BOOTPAY_ENV=production 또는 development
51
+ ```
52
+
53
+ 주요 변수:
54
+
55
+ ```env
56
+ BOOTPAY_ENV=production
57
+ BOOTPAY_PG_CLIENT_KEY_PROD=...
58
+ BOOTPAY_PG_SECRET_KEY_PROD=...
59
+ BOOTPAY_PG_CLIENT_KEY_DEV=...
60
+ BOOTPAY_PG_SECRET_KEY_DEV=...
61
+ BOOTPAY_COMMERCE_CLIENT_KEY_PROD=...
62
+ BOOTPAY_COMMERCE_SECRET_KEY_PROD=...
63
+ BOOTPAY_COMMERCE_CLIENT_KEY_DEV=...
64
+ BOOTPAY_COMMERCE_SECRET_KEY_DEV=...
65
+ ```
66
+
67
+ 변수가 없으면 SDK 테스트용 기본값(NodeJS 기준 ck/sk)으로 fallback 합니다.
68
+
43
69
  # 사용하기
44
70
 
71
+ > 권장 인증 방식은 `client_key/secret_key`입니다. 기존 positional `application_id/private_key` 방식도 계속 지원됩니다.
72
+
45
73
  ```python
46
74
 
75
+ import os
47
76
  from bootpay_backend import BootpayBackend
48
77
 
49
- bootpay = BootpayBackend('5b8f6a4d396fa665fdc2b5ea', 'rm6EYECr6aroQVG2ntW0A6LpWnkTgP4uQ3H18sDDUYw=')
78
+ bootpay = BootpayBackend(client_key=os.getenv('BOOTPAY_PG_CLIENT_KEY_PROD'), secret_key=os.getenv('BOOTPAY_PG_SECRET_KEY_PROD'))
50
79
 
51
80
  token = bootpay.get_access_token()
52
81
  if 'error_code' not in token:
@@ -61,7 +90,7 @@ if 'error_code' not in token:
61
90
  발급된 토큰은 30분간 유효하며, 최초 발급일로부터 30분이 지날 경우 토큰 발급 함수를 재호출 해주셔야 합니다.
62
91
 
63
92
  ```python
64
- bootpay = BootpayBackend('5b8f6a4d396fa665fdc2b5ea', 'rm6EYECr6aroQVG2ntW0A6LpWnkTgP4uQ3H18sDDUYw=')
93
+ bootpay = BootpayBackend(client_key=os.getenv('BOOTPAY_PG_CLIENT_KEY_PROD'), secret_key=os.getenv('BOOTPAY_PG_SECRET_KEY_PROD'))
65
94
 
66
95
  token = bootpay.get_access_token()
67
96
  if 'error_code' not in token:
@@ -9,7 +9,13 @@ from .modules import (
9
9
  OrderCancelModule,
10
10
  OrderSubscriptionModule,
11
11
  OrderSubscriptionBillModule,
12
- OrderSubscriptionAdjustmentModule
12
+ OrderSubscriptionAdjustmentModule,
13
+ StoreModule,
14
+ CategoryModule,
15
+ CouponModule,
16
+ PointModule,
17
+ CartModule,
18
+ OrderSubscriptionRequestModule
13
19
  )
14
20
  from .types import *
15
21
 
@@ -64,6 +70,12 @@ class BootpayCommerce(BootpayCommerceResource):
64
70
  self.order_subscription = OrderSubscriptionModule(self)
65
71
  self.order_subscription_bill = OrderSubscriptionBillModule(self)
66
72
  self.order_subscription_adjustment = OrderSubscriptionAdjustmentModule(self)
73
+ self.store = StoreModule(self)
74
+ self.category = CategoryModule(self)
75
+ self.coupon = CouponModule(self)
76
+ self.point = PointModule(self)
77
+ self.cart = CartModule(self)
78
+ self.order_subscription_request = OrderSubscriptionRequestModule(self)
67
79
 
68
80
  def get_access_token(self):
69
81
  """
@@ -188,6 +200,12 @@ __all__ = [
188
200
  'OrderSubscriptionModule',
189
201
  'OrderSubscriptionBillModule',
190
202
  'OrderSubscriptionAdjustmentModule',
203
+ 'StoreModule',
204
+ 'CategoryModule',
205
+ 'CouponModule',
206
+ 'PointModule',
207
+ 'CartModule',
208
+ 'OrderSubscriptionRequestModule',
191
209
  # Types
192
210
  'ListParams',
193
211
  'CommerceAddress',
@@ -242,4 +260,31 @@ __all__ = [
242
260
  'SUBSCRIPTION_ADJUSTMENT_TYPE_PERIOD_DISCOUNT',
243
261
  'CommerceOrderSubscriptionAdjustment',
244
262
  'OrderSubscriptionAdjustmentUpdateParams',
263
+ 'SupervisorOrderSubscriptionApproveParams',
264
+ 'SupervisorOrderSubscriptionRejectParams',
265
+ 'SupervisorOrderSubscriptionTerminateParams',
266
+ 'SupervisorOrderSubscriptionPauseParams',
267
+ 'SupervisorOrderSubscriptionResumeParams',
268
+ 'CommerceCategory',
269
+ 'CategoryCreateParams',
270
+ 'CategoryUpdateParams',
271
+ 'CommerceCoupon',
272
+ 'CouponListParams',
273
+ 'CouponDownloadParams',
274
+ 'PointBalance',
275
+ 'PointTransaction',
276
+ 'PointTransactionsResponse',
277
+ 'PointTransactionsParams',
278
+ 'CartItemPayload',
279
+ 'ShippingAddressPayload',
280
+ 'OrderPreviewParams',
281
+ 'DeliveryGroupItem',
282
+ 'DeliveryGroup',
283
+ 'AppliedCouponSnapshot',
284
+ 'OrderPreviewSummary',
285
+ 'OrderPreviewUnavailableItem',
286
+ 'OrderPreviewResponse',
287
+ 'OrderSubscriptionRequest',
288
+ 'OrderSubscriptionRequestListParams',
289
+ 'OrderSubscriptionRequestUpdateParams',
245
290
  ]
@@ -74,8 +74,10 @@ class BootpayCommerceResource:
74
74
  'BOOTPAY-SDK-TYPE': '302',
75
75
  'BOOTPAY-ROLE': self._role or 'user'
76
76
  }
77
- if include_auth and self._token:
78
- headers['Authorization'] = f'Bearer {self._token}'
77
+ if include_auth:
78
+ basic_auth = self._get_basic_auth_header()
79
+ if basic_auth:
80
+ headers['Authorization'] = basic_auth
79
81
  return headers
80
82
 
81
83
  def get(self, url: str, params: Optional[Dict] = None):
@@ -125,8 +127,9 @@ class BootpayCommerceResource:
125
127
  'BOOTPAY-SDK-TYPE': '302',
126
128
  'BOOTPAY-ROLE': self._role or 'user'
127
129
  }
128
- if self._token:
129
- headers['Authorization'] = f'Bearer {self._token}'
130
+ basic_auth = self._get_basic_auth_header()
131
+ if basic_auth:
132
+ headers['Authorization'] = basic_auth
130
133
 
131
134
  # 폼 데이터 준비
132
135
  form_data = {}
@@ -8,6 +8,12 @@ from .order_cancel import OrderCancelModule
8
8
  from .order_subscription import OrderSubscriptionModule
9
9
  from .order_subscription_bill import OrderSubscriptionBillModule
10
10
  from .order_subscription_adjustment import OrderSubscriptionAdjustmentModule
11
+ from .store import StoreModule
12
+ from .category import CategoryModule
13
+ from .coupon import CouponModule
14
+ from .point import PointModule
15
+ from .cart import CartModule
16
+ from .order_subscription_request import OrderSubscriptionRequestModule
11
17
 
12
18
  __all__ = [
13
19
  'UserModule',
@@ -18,5 +24,11 @@ __all__ = [
18
24
  'OrderCancelModule',
19
25
  'OrderSubscriptionModule',
20
26
  'OrderSubscriptionBillModule',
21
- 'OrderSubscriptionAdjustmentModule'
27
+ 'OrderSubscriptionAdjustmentModule',
28
+ 'StoreModule',
29
+ 'CategoryModule',
30
+ 'CouponModule',
31
+ 'PointModule',
32
+ 'CartModule',
33
+ 'OrderSubscriptionRequestModule'
22
34
  ]
@@ -0,0 +1,29 @@
1
+ from typing import TYPE_CHECKING, Optional
2
+
3
+ if TYPE_CHECKING:
4
+ from ..commerce_resource import BootpayCommerceResource
5
+
6
+ from ..types import (
7
+ OrderPreviewParams,
8
+ OrderPreviewResponse
9
+ )
10
+
11
+
12
+ class CartModule:
13
+ """장바구니 모듈"""
14
+
15
+ def __init__(self, bootpay: 'BootpayCommerceResource'):
16
+ self._bootpay = bootpay
17
+
18
+ def order_preview(self, params: Optional[OrderPreviewParams] = None):
19
+ """
20
+ 주문 미리보기 (배송비/할인 권위적 계산)
21
+ POST /v1/cart/order-preview
22
+
23
+ member_mode='guest' (기본): cart_items 필수
24
+ member_mode='member': 서버 장바구니 사용 (user 토큰 필요)
25
+
26
+ :param params: 주문 미리보기 파라미터
27
+ :return: OrderPreviewResponse
28
+ """
29
+ return self._bootpay.post('cart/order-preview', params if params is not None else {})
@@ -0,0 +1,60 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from ..commerce_resource import BootpayCommerceResource
5
+
6
+ from ..types import (
7
+ CommerceCategory,
8
+ CategoryCreateParams,
9
+ CategoryUpdateParams
10
+ )
11
+
12
+
13
+ class CategoryModule:
14
+ """카테고리 모듈"""
15
+
16
+ def __init__(self, bootpay: 'BootpayCommerceResource'):
17
+ self._bootpay = bootpay
18
+
19
+ def list(self):
20
+ """
21
+ 카테고리 트리 조회
22
+ :return: List[CommerceCategory]
23
+ """
24
+ return self._bootpay.get('categories')
25
+
26
+ def detail(self, category_id: str):
27
+ """
28
+ 카테고리 단건 조회
29
+ :param category_id: 카테고리 ID
30
+ :return: CommerceCategory
31
+ """
32
+ return self._bootpay.get(f'categories/{category_id}')
33
+
34
+ def create(self, params: CategoryCreateParams):
35
+ """
36
+ 카테고리 생성
37
+ :param params: 카테고리 생성 파라미터
38
+ :return: CommerceCategory
39
+ """
40
+ return self._bootpay.post('categories', params)
41
+
42
+ def update(self, params: CategoryUpdateParams):
43
+ """
44
+ 카테고리 수정
45
+ :param params: 카테고리 수정 파라미터 (category_id 필수)
46
+ :return: CommerceCategory
47
+ """
48
+ if not params.get('category_id'):
49
+ raise ValueError('category_id is required')
50
+ category_id = params['category_id']
51
+ rest = {k: v for k, v in params.items() if k != 'category_id'}
52
+ return self._bootpay.put(f'categories/{category_id}', rest)
53
+
54
+ def destroy(self, category_id: str):
55
+ """
56
+ 카테고리 삭제
57
+ :param category_id: 카테고리 ID
58
+ :return: None
59
+ """
60
+ return self._bootpay.delete(f'categories/{category_id}')
@@ -0,0 +1,51 @@
1
+ from typing import TYPE_CHECKING, Optional
2
+ from urllib.parse import urlencode
3
+
4
+ if TYPE_CHECKING:
5
+ from ..commerce_resource import BootpayCommerceResource
6
+
7
+ from ..types import (
8
+ CommerceCoupon,
9
+ CouponListParams,
10
+ CouponDownloadParams
11
+ )
12
+
13
+
14
+ class CouponModule:
15
+ """쿠폰 모듈"""
16
+
17
+ def __init__(self, bootpay: 'BootpayCommerceResource'):
18
+ self._bootpay = bootpay
19
+
20
+ def list(self, params: Optional[CouponListParams] = None):
21
+ """
22
+ 사용자 보유 쿠폰 목록 조회
23
+ :param params: 조회 파라미터
24
+ :return: List[CommerceCoupon]
25
+ """
26
+ query_params = {}
27
+ if params:
28
+ if params.get('status'):
29
+ query_params['status'] = params['status']
30
+ if params.get('page') is not None:
31
+ query_params['page'] = params['page']
32
+ if params.get('limit') is not None:
33
+ query_params['limit'] = params['limit']
34
+
35
+ query = urlencode(query_params) if query_params else ''
36
+ return self._bootpay.get(f'coupon{"?" + query if query else ""}')
37
+
38
+ def available(self):
39
+ """
40
+ 다운로드 가능한 쿠폰 목록
41
+ :return: List[CommerceCoupon]
42
+ """
43
+ return self._bootpay.get('coupon/available')
44
+
45
+ def download(self, params: CouponDownloadParams):
46
+ """
47
+ 쿠폰 다운로드 (issue_from_template)
48
+ :param params: {'coupon_template_id': str}
49
+ :return: CommerceCoupon
50
+ """
51
+ return self._bootpay.post('coupon/download', params)
@@ -11,7 +11,12 @@ from ..types import (
11
11
  OrderSubscriptionPauseParams,
12
12
  OrderSubscriptionResumeParams,
13
13
  OrderSubscriptionTerminationParams,
14
- CalcTerminateFeeResponse
14
+ CalcTerminateFeeResponse,
15
+ SupervisorOrderSubscriptionApproveParams,
16
+ SupervisorOrderSubscriptionRejectParams,
17
+ SupervisorOrderSubscriptionTerminateParams,
18
+ SupervisorOrderSubscriptionPauseParams,
19
+ SupervisorOrderSubscriptionResumeParams
15
20
  )
16
21
 
17
22
 
@@ -130,3 +135,83 @@ class OrderSubscriptionModule:
130
135
  if not params.get('order_subscription_id'):
131
136
  raise ValueError('order_subscription_id is required')
132
137
  return self._bootpay.put(f'order_subscriptions/{params["order_subscription_id"]}', params)
138
+
139
+ def supervisor_approve(
140
+ self,
141
+ order_subscription_id: str,
142
+ params: Optional[SupervisorOrderSubscriptionApproveParams] = None
143
+ ):
144
+ """
145
+ 관리자 정기구독 승인
146
+ :param order_subscription_id: 정기구독 ID
147
+ :param params: 승인 파라미터
148
+ :return: CommerceOrderSubscription
149
+ """
150
+ return self._bootpay.put(
151
+ f'order_subscriptions/{order_subscription_id}/approve',
152
+ params or {}
153
+ )
154
+
155
+ def supervisor_reject(
156
+ self,
157
+ order_subscription_id: str,
158
+ params: Optional[SupervisorOrderSubscriptionRejectParams] = None
159
+ ):
160
+ """
161
+ 관리자 정기구독 거절
162
+ :param order_subscription_id: 정기구독 ID
163
+ :param params: 거절 파라미터
164
+ :return: CommerceOrderSubscription
165
+ """
166
+ return self._bootpay.put(
167
+ f'order_subscriptions/{order_subscription_id}/reject',
168
+ params or {}
169
+ )
170
+
171
+ def supervisor_terminate(
172
+ self,
173
+ order_subscription_id: str,
174
+ params: Optional[SupervisorOrderSubscriptionTerminateParams] = None
175
+ ):
176
+ """
177
+ 관리자 정기구독 해지
178
+ :param order_subscription_id: 정기구독 ID
179
+ :param params: 해지 파라미터
180
+ :return: CommerceOrderSubscription
181
+ """
182
+ return self._bootpay.put(
183
+ f'order_subscriptions/{order_subscription_id}/terminate',
184
+ params or {}
185
+ )
186
+
187
+ def supervisor_pause(
188
+ self,
189
+ order_subscription_id: str,
190
+ params: SupervisorOrderSubscriptionPauseParams
191
+ ):
192
+ """
193
+ 관리자 정기구독 일시정지
194
+ :param order_subscription_id: 정기구독 ID
195
+ :param params: 일시정지 파라미터
196
+ :return: CommerceOrderSubscription
197
+ """
198
+ return self._bootpay.put(
199
+ f'order_subscriptions/{order_subscription_id}/pause',
200
+ params
201
+ )
202
+
203
+ def supervisor_resume(
204
+ self,
205
+ order_subscription_id: str,
206
+ params: Optional[SupervisorOrderSubscriptionResumeParams] = None
207
+ ):
208
+ """
209
+ 관리자 정기구독 재개
210
+ :param order_subscription_id: 정기구독 ID
211
+ :param params: 재개 파라미터
212
+ :return: CommerceOrderSubscription
213
+ """
214
+ return self._bootpay.put(
215
+ f'order_subscriptions/{order_subscription_id}/resume',
216
+ params or {}
217
+ )
@@ -0,0 +1,92 @@
1
+ from typing import TYPE_CHECKING, Optional
2
+ from urllib.parse import urlencode
3
+
4
+ if TYPE_CHECKING:
5
+ from ..commerce_resource import BootpayCommerceResource
6
+
7
+ from ..types import (
8
+ OrderSubscriptionRequest,
9
+ OrderSubscriptionRequestListParams,
10
+ OrderSubscriptionRequestUpdateParams
11
+ )
12
+
13
+
14
+ class OrderSubscriptionRequestModule:
15
+ """
16
+ V1 OrderSubscription Request 조회/승인 모듈
17
+
18
+ 본인 모드 (user role): project_id 없이 호출 → 본인 요청 목록/단건
19
+ 슈퍼바이저 모드 (supervisor role): project_id 포함 → 프로젝트 전체 + update (승인/거절)
20
+
21
+ 구매자측 요청 생성 (pause/resume/termination 등) 은
22
+ `commerce.order_subscription.request_ing.*` 모듈을 사용한다.
23
+ """
24
+
25
+ def __init__(self, bootpay: 'BootpayCommerceResource'):
26
+ self._bootpay = bootpay
27
+
28
+ def list(self, params: Optional[OrderSubscriptionRequestListParams] = None):
29
+ """
30
+ 요청 목록 조회 (user / supervisor 공용)
31
+ :param params: 조회 파라미터
32
+ :return: {'items': List[OrderSubscriptionRequest], 'total': int}
33
+ """
34
+ query_params = {}
35
+ if params:
36
+ if params.get('project_id'):
37
+ query_params['project_id'] = params['project_id']
38
+ if params.get('page') is not None:
39
+ query_params['page'] = params['page']
40
+ if params.get('limit') is not None:
41
+ query_params['limit'] = params['limit']
42
+ if params.get('request_type') is not None:
43
+ query_params['request_type'] = params['request_type']
44
+ if params.get('status') is not None:
45
+ query_params['status'] = params['status']
46
+ if params.get('s_at'):
47
+ query_params['s_at'] = params['s_at']
48
+ if params.get('e_at'):
49
+ query_params['e_at'] = params['e_at']
50
+ if params.get('keyword'):
51
+ query_params['keyword'] = params['keyword']
52
+
53
+ query = urlencode(query_params) if query_params else ''
54
+ return self._bootpay.get(
55
+ f'order-subscription-requests{"?" + query if query else ""}'
56
+ )
57
+
58
+ def detail(
59
+ self,
60
+ order_subscription_request_history_id: str,
61
+ project_id: Optional[str] = None
62
+ ):
63
+ """
64
+ 요청 단건 조회 (user / supervisor 공용)
65
+ :param order_subscription_request_history_id: 요청 이력 ID
66
+ :param project_id: 프로젝트 ID (supervisor 모드에서 사용)
67
+ :return: OrderSubscriptionRequest
68
+ """
69
+ query_params = {}
70
+ if project_id:
71
+ query_params['project_id'] = project_id
72
+
73
+ query = urlencode(query_params) if query_params else ''
74
+ return self._bootpay.get(
75
+ f'order-subscription-requests/{order_subscription_request_history_id}'
76
+ f'{"?" + query if query else ""}'
77
+ )
78
+
79
+ def update(self, params: OrderSubscriptionRequestUpdateParams):
80
+ """
81
+ 요청 승인/거절 (supervisor 전용)
82
+ :param params: 승인/거절 파라미터 (order_subscription_request_history_id 필수)
83
+ :return: OrderSubscriptionRequest
84
+ """
85
+ if not params.get('order_subscription_request_history_id'):
86
+ raise ValueError('order_subscription_request_history_id is required')
87
+ history_id = params['order_subscription_request_history_id']
88
+ rest = {k: v for k, v in params.items() if k != 'order_subscription_request_history_id'}
89
+ return self._bootpay.put(
90
+ f'order-subscription-requests/{history_id}',
91
+ rest
92
+ )
@@ -0,0 +1,43 @@
1
+ from typing import TYPE_CHECKING, Optional
2
+ from urllib.parse import urlencode
3
+
4
+ if TYPE_CHECKING:
5
+ from ..commerce_resource import BootpayCommerceResource
6
+
7
+ from ..types import (
8
+ PointBalance,
9
+ PointTransactionsParams,
10
+ PointTransactionsResponse
11
+ )
12
+
13
+
14
+ class PointModule:
15
+ """적립금 모듈"""
16
+
17
+ def __init__(self, bootpay: 'BootpayCommerceResource'):
18
+ self._bootpay = bootpay
19
+
20
+ def balance(self):
21
+ """
22
+ 적립금 잔액 조회
23
+ :return: PointBalance
24
+ """
25
+ return self._bootpay.get('point/balance')
26
+
27
+ def transactions(self, params: Optional[PointTransactionsParams] = None):
28
+ """
29
+ 적립금 내역 조회
30
+ :param params: 조회 파라미터
31
+ :return: PointTransactionsResponse
32
+ """
33
+ query_params = {}
34
+ if params:
35
+ if params.get('page') is not None:
36
+ query_params['page'] = params['page']
37
+ if params.get('limit') is not None:
38
+ query_params['limit'] = params['limit']
39
+ if params.get('transaction_type') is not None:
40
+ query_params['transaction_type'] = params['transaction_type']
41
+
42
+ query = urlencode(query_params) if query_params else ''
43
+ return self._bootpay.get(f'point/transactions{"?" + query if query else ""}')
@@ -0,0 +1,25 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from ..commerce_resource import BootpayCommerceResource
5
+
6
+
7
+ class StoreModule:
8
+ """가맹점 모듈"""
9
+
10
+ def __init__(self, bootpay: 'BootpayCommerceResource'):
11
+ self._bootpay = bootpay
12
+
13
+ def info(self):
14
+ """
15
+ 가맹점 기본 정보 조회
16
+ :return: 가맹점 정보
17
+ """
18
+ return self._bootpay.get('store')
19
+
20
+ def detail(self):
21
+ """
22
+ 가맹점 상세 정보 조회
23
+ :return: 가맹점 상세 정보
24
+ """
25
+ return self._bootpay.get('store/detail')
@@ -71,7 +71,7 @@ class UserGroupModule:
71
71
  :param user_id: 사용자 ID
72
72
  :return: None
73
73
  """
74
- return self._bootpay.post(f'user-groups/{user_group_id}/add_user', {'user_id': user_id})
74
+ return self._bootpay.post(f'user-groups/{user_group_id}/user', {'user_id': user_id})
75
75
 
76
76
  def user_delete(self, user_group_id: str, user_id: str):
77
77
  """
@@ -80,7 +80,7 @@ class UserGroupModule:
80
80
  :param user_id: 사용자 ID
81
81
  :return: None
82
82
  """
83
- return self._bootpay.delete(f'user-groups/{user_group_id}/remove_user?user_id={user_id}')
83
+ return self._bootpay.delete(f'user-groups/{user_group_id}/user/{user_id}')
84
84
 
85
85
  def limit(self, params: UserGroupLimitParams):
86
86
  """