kra-etims-sdk 0.1.1__py3-none-any.whl → 0.1.3__py3-none-any.whl
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.
- kra_etims_sdk/base_client.py +99 -17
- kra_etims_sdk/client.py +51 -62
- kra_etims_sdk/schemas.py +236 -140
- kra_etims_sdk/validator.py +11 -37
- {kra_etims_sdk-0.1.1.dist-info → kra_etims_sdk-0.1.3.dist-info}/METADATA +120 -252
- kra_etims_sdk-0.1.3.dist-info/RECORD +12 -0
- kra_etims_sdk-0.1.1.dist-info/RECORD +0 -12
- {kra_etims_sdk-0.1.1.dist-info → kra_etims_sdk-0.1.3.dist-info}/WHEEL +0 -0
- {kra_etims_sdk-0.1.1.dist-info → kra_etims_sdk-0.1.3.dist-info}/licenses/LICENSE +0 -0
- {kra_etims_sdk-0.1.1.dist-info → kra_etims_sdk-0.1.3.dist-info}/top_level.txt +0 -0
kra_etims_sdk/base_client.py
CHANGED
|
@@ -3,26 +3,77 @@ from .exceptions import ApiException, AuthenticationException
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class BaseClient:
|
|
6
|
+
endpoints = {
|
|
7
|
+
# INITIALIZATION
|
|
8
|
+
'selectInitOsdcInfo': '/selectInitOsdcInfo',
|
|
9
|
+
|
|
10
|
+
# CODE LIST
|
|
11
|
+
'selectCodeList': '/selectCodeList',
|
|
12
|
+
|
|
13
|
+
# CUSTOMER
|
|
14
|
+
'selectCustomer': '/selectCustomer',
|
|
15
|
+
|
|
16
|
+
# NOTICE
|
|
17
|
+
'selectNoticeList': '/selectNoticeList',
|
|
18
|
+
|
|
19
|
+
# ITEM
|
|
20
|
+
'selectItemClsList': '/selectItemClsList',
|
|
21
|
+
'selectItemList': '/selectItemList',
|
|
22
|
+
'saveItem': '/saveItem',
|
|
23
|
+
'SaveItemComposition': '/saveItemComposition',
|
|
24
|
+
|
|
25
|
+
# BRANCH / CUSTOMER
|
|
26
|
+
'selectBhfList': '/selectBhfList',
|
|
27
|
+
'saveBhfCustomer': '/saveBhfCustomer',
|
|
28
|
+
'saveBhfUser': '/saveBhfUser',
|
|
29
|
+
'saveBhfInsurance': '/saveBhfInsurance',
|
|
30
|
+
|
|
31
|
+
# IMPORTED ITEMS
|
|
32
|
+
'selectImportItemList': '/selectImportItemList',
|
|
33
|
+
'updateImportItem': '/updateImportItem',
|
|
34
|
+
|
|
35
|
+
# SALES / PURCHASES
|
|
36
|
+
'TrnsSalesSaveWrReq': '/saveTrnsSalesOsdc',
|
|
37
|
+
'selectTrnsPurchaseSalesList': '/selectTrnsPurchaseSalesList',
|
|
38
|
+
'insertTrnsPurchase': '/insertTrnsPurchase',
|
|
39
|
+
|
|
40
|
+
# STOCK
|
|
41
|
+
'selectStockMoveList': '/selectStockMoveList',
|
|
42
|
+
'insertStockIO': '/insertStockIO',
|
|
43
|
+
'saveStockMaster': '/saveStockMaster',
|
|
44
|
+
}
|
|
45
|
+
|
|
6
46
|
def __init__(self, config, auth):
|
|
7
47
|
self.config = config
|
|
8
48
|
self.auth = auth
|
|
9
49
|
|
|
10
50
|
def base_url(self):
|
|
11
|
-
|
|
51
|
+
env = self.config["env"]
|
|
52
|
+
return self.config["api"][env]["base_url"].rstrip("/")
|
|
53
|
+
|
|
54
|
+
def timeout(self):
|
|
55
|
+
return self.config.get("http", {}).get("timeout", 30)
|
|
56
|
+
|
|
57
|
+
def endpoint(self, key: str):
|
|
58
|
+
if key.startswith("/"):
|
|
59
|
+
raise ApiException(f"Endpoint key expected, path given [{key}]. Pass endpoint keys only.", 500)
|
|
12
60
|
|
|
13
|
-
|
|
14
|
-
if key not in self.config["endpoints"]:
|
|
61
|
+
if key not in self.endpoints:
|
|
15
62
|
raise ApiException(f"Endpoint [{key}] not configured", 500)
|
|
16
|
-
return self.config["endpoints"][key]
|
|
17
63
|
|
|
18
|
-
|
|
19
|
-
|
|
64
|
+
return self.endpoints[key]
|
|
65
|
+
|
|
66
|
+
def get(self, endpoint_key, params=None):
|
|
67
|
+
return self._send("GET", endpoint_key, params or {})
|
|
68
|
+
|
|
69
|
+
def post(self, endpoint_key, data=None):
|
|
70
|
+
return self._send("POST", endpoint_key, data or {})
|
|
20
71
|
|
|
21
72
|
def _send(self, method, endpoint_key, data):
|
|
22
73
|
endpoint = self.endpoint(endpoint_key)
|
|
23
74
|
response = self._request(method, endpoint, data)
|
|
24
75
|
|
|
25
|
-
if response
|
|
76
|
+
if self._is_token_expired(response):
|
|
26
77
|
self.auth.forget_token()
|
|
27
78
|
self.auth.token(force=True)
|
|
28
79
|
response = self._request(method, endpoint, data)
|
|
@@ -32,8 +83,19 @@ class BaseClient:
|
|
|
32
83
|
def _request(self, method, endpoint, data):
|
|
33
84
|
url = self.base_url() + endpoint
|
|
34
85
|
headers = self._headers(endpoint)
|
|
35
|
-
|
|
36
|
-
|
|
86
|
+
|
|
87
|
+
if method.upper() == "GET" and data:
|
|
88
|
+
response = requests.get(url, params=data, headers=headers, timeout=self.timeout())
|
|
89
|
+
else:
|
|
90
|
+
response = requests.request(
|
|
91
|
+
method.upper(),
|
|
92
|
+
url,
|
|
93
|
+
json=data,
|
|
94
|
+
headers=headers,
|
|
95
|
+
timeout=self.timeout()
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
return response
|
|
37
99
|
|
|
38
100
|
def _headers(self, endpoint):
|
|
39
101
|
if endpoint.endswith("/selectInitOsdcInfo"):
|
|
@@ -47,21 +109,41 @@ class BaseClient:
|
|
|
47
109
|
"Authorization": f"Bearer {self.auth.token()}",
|
|
48
110
|
"Content-Type": "application/json",
|
|
49
111
|
"Accept": "application/json",
|
|
50
|
-
"tin": self.config
|
|
51
|
-
"bhfId": self.config
|
|
52
|
-
"cmcKey": self.config
|
|
112
|
+
"tin": self.config.get("oscu", {}).get("tin", ""),
|
|
113
|
+
"bhfId": self.config.get("oscu", {}).get("bhf_id", ""),
|
|
114
|
+
"cmcKey": self.config.get("oscu", {}).get("cmc_key", ""),
|
|
53
115
|
}
|
|
54
116
|
|
|
117
|
+
def _is_token_expired(self, response):
|
|
118
|
+
if response.status_code == 401:
|
|
119
|
+
return True
|
|
120
|
+
try:
|
|
121
|
+
fault = response.json().get("fault", {}).get("faultstring", "")
|
|
122
|
+
return "access token expired" in fault.lower() or "invalid token" in fault.lower()
|
|
123
|
+
except Exception:
|
|
124
|
+
return False
|
|
125
|
+
|
|
55
126
|
def _unwrap(self, response):
|
|
56
127
|
try:
|
|
57
|
-
|
|
128
|
+
json_data = response.json()
|
|
58
129
|
except Exception:
|
|
59
130
|
raise ApiException(response.text, response.status_code)
|
|
60
131
|
|
|
61
|
-
|
|
62
|
-
|
|
132
|
+
# KRA business error
|
|
133
|
+
if json_data.get("resultCd") and json_data["resultCd"] != "000":
|
|
134
|
+
raise ApiException(
|
|
135
|
+
json_data.get("resultMsg", "KRA business error"),
|
|
136
|
+
400,
|
|
137
|
+
json_data.get("resultCd"),
|
|
138
|
+
json_data
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# HTTP errors
|
|
142
|
+
if 200 <= response.status_code < 300:
|
|
143
|
+
return json_data
|
|
63
144
|
|
|
64
145
|
if response.status_code == 401:
|
|
65
|
-
raise AuthenticationException("Unauthorized")
|
|
146
|
+
raise AuthenticationException("Unauthorized: Invalid or expired token")
|
|
66
147
|
|
|
67
|
-
|
|
148
|
+
message = json_data.get("fault", {}).get("faultstring", response.text)
|
|
149
|
+
raise ApiException(message, response.status_code)
|
kra_etims_sdk/client.py
CHANGED
|
@@ -3,7 +3,6 @@ from .validator import Validator
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class EtimsClient(BaseClient):
|
|
6
|
-
|
|
7
6
|
def __init__(self, config: dict, auth):
|
|
8
7
|
super().__init__(config, auth)
|
|
9
8
|
self.validator = Validator()
|
|
@@ -11,96 +10,86 @@ class EtimsClient(BaseClient):
|
|
|
11
10
|
def _validate(self, data: dict, schema: str) -> dict:
|
|
12
11
|
return self.validator.validate(data, schema)
|
|
13
12
|
|
|
13
|
+
# -----------------------------
|
|
14
|
+
# INITIALIZATION
|
|
15
|
+
# -----------------------------
|
|
14
16
|
def select_init_osdc_info(self, data: dict) -> dict:
|
|
15
|
-
"""
|
|
16
|
-
Initialize the OSCU device with KRA.
|
|
17
|
-
Returns cmcKey and device information.
|
|
18
|
-
"""
|
|
19
17
|
return self.post("selectInitOsdcInfo", self._validate(data, "initialization"))
|
|
20
18
|
|
|
21
19
|
# -----------------------------
|
|
22
|
-
#
|
|
20
|
+
# CODE LISTS
|
|
23
21
|
# -----------------------------
|
|
24
22
|
def select_code_list(self, data: dict) -> dict:
|
|
25
|
-
return self.post("selectCodeList", self._validate(data, "
|
|
23
|
+
return self.post("selectCodeList", self._validate(data, "lastReqOnly"))
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
# -----------------------------
|
|
26
|
+
# CUSTOMER / BRANCH
|
|
27
|
+
# -----------------------------
|
|
28
|
+
def select_customer(self, data: dict) -> dict:
|
|
29
|
+
return self.post("selectCustomer", self._validate(data, "custSearchReq"))
|
|
29
30
|
|
|
30
|
-
def
|
|
31
|
-
return self.post("selectBhfList", self._validate(data, "
|
|
31
|
+
def select_branches(self, data: dict) -> dict:
|
|
32
|
+
return self.post("selectBhfList", self._validate(data, "lastReqOnly"))
|
|
32
33
|
|
|
33
|
-
def
|
|
34
|
-
return self.post("
|
|
34
|
+
def save_branch_customer(self, data: dict) -> dict:
|
|
35
|
+
return self.post("saveBhfCustomer", self._validate(data, "branchCustomer"))
|
|
35
36
|
|
|
36
|
-
def
|
|
37
|
-
return self.post("
|
|
37
|
+
def save_branch_user(self, data: dict) -> dict:
|
|
38
|
+
return self.post("saveBhfUser", self._validate(data, "branchUser"))
|
|
38
39
|
|
|
39
|
-
def
|
|
40
|
-
return self.post("
|
|
40
|
+
def save_branch_insurance(self, data: dict) -> dict:
|
|
41
|
+
return self.post("saveBhfInsurance", self._validate(data, "branchInsurance"))
|
|
41
42
|
|
|
42
43
|
# -----------------------------
|
|
43
|
-
#
|
|
44
|
+
# ITEM
|
|
44
45
|
# -----------------------------
|
|
45
|
-
def
|
|
46
|
-
return self.post("
|
|
46
|
+
def select_item_classes(self, data: dict) -> dict:
|
|
47
|
+
return self.post("selectItemClsList", self._validate(data, "lastReqOnly"))
|
|
48
|
+
|
|
49
|
+
def select_items(self, data: dict) -> dict:
|
|
50
|
+
return self.post("selectItemList", self._validate(data, "lastReqOnly"))
|
|
51
|
+
|
|
52
|
+
def save_item(self, data: dict) -> dict:
|
|
53
|
+
return self.post("saveItem", self._validate(data, "saveItem"))
|
|
47
54
|
|
|
48
|
-
def
|
|
49
|
-
return self.post(
|
|
50
|
-
"sendPurchaseTransactionInfo",
|
|
51
|
-
self._validate(data, "purchaseTransaction"),
|
|
52
|
-
)
|
|
55
|
+
def save_item_composition(self, data: dict) -> dict:
|
|
56
|
+
return self.post("SaveItemComposition", self._validate(data, "itemComposition"))
|
|
53
57
|
|
|
54
58
|
# -----------------------------
|
|
55
|
-
#
|
|
59
|
+
# IMPORTED ITEMS
|
|
56
60
|
# -----------------------------
|
|
57
|
-
def
|
|
58
|
-
return self.post("
|
|
59
|
-
|
|
60
|
-
def send_sales_transaction(self, data: dict) -> dict:
|
|
61
|
-
return self.post(
|
|
62
|
-
"sendSalesTransaction",
|
|
63
|
-
self._validate(data, "salesTransaction"),
|
|
64
|
-
)
|
|
61
|
+
def select_imported_items(self, data: dict) -> dict:
|
|
62
|
+
return self.post("selectImportItemList", self._validate(data, "lastReqOnly"))
|
|
65
63
|
|
|
66
|
-
def
|
|
67
|
-
return self.post("
|
|
64
|
+
def update_imported_item(self, data: dict) -> dict:
|
|
65
|
+
return self.post("updateImportItem", self._validate(data, "importItemUpdate"))
|
|
68
66
|
|
|
69
67
|
# -----------------------------
|
|
70
|
-
#
|
|
68
|
+
# PURCHASES
|
|
71
69
|
# -----------------------------
|
|
72
|
-
def
|
|
73
|
-
return self.post("
|
|
70
|
+
def select_purchases(self, data: dict) -> dict:
|
|
71
|
+
return self.post("selectTrnsPurchaseSalesList", self._validate(data, "lastReqOnly"))
|
|
74
72
|
|
|
75
|
-
def
|
|
76
|
-
return self.post("
|
|
73
|
+
def save_purchase(self, data: dict) -> dict:
|
|
74
|
+
return self.post("insertTrnsPurchase", self._validate(data, "insertTrnsPurchase"))
|
|
77
75
|
|
|
78
|
-
def
|
|
79
|
-
return self.post("
|
|
76
|
+
def save_sales_transaction(self, data: dict) -> dict:
|
|
77
|
+
return self.post("TrnsSalesSaveWrReq", self._validate(data, "lastReqOnly"))
|
|
80
78
|
|
|
81
79
|
# -----------------------------
|
|
82
|
-
#
|
|
80
|
+
# STOCK
|
|
83
81
|
# -----------------------------
|
|
84
|
-
def
|
|
85
|
-
return self.post(
|
|
86
|
-
"branchInsuranceInfo",
|
|
87
|
-
self._validate(data, "branchInsurance"),
|
|
88
|
-
)
|
|
82
|
+
def select_stock_movement(self, data: dict) -> dict:
|
|
83
|
+
return self.post("selectStockMoveList", self._validate(data, "lastReqOnly"))
|
|
89
84
|
|
|
90
|
-
def
|
|
91
|
-
return self.post(
|
|
92
|
-
"branchUserAccount",
|
|
93
|
-
self._validate(data, "branchUserAccount"),
|
|
94
|
-
)
|
|
85
|
+
def save_stock_io(self, data: dict) -> dict:
|
|
86
|
+
return self.post("insertStockIO", self._validate(data, "saveStockIO"))
|
|
95
87
|
|
|
96
|
-
def
|
|
97
|
-
return self.post(
|
|
98
|
-
"branchSendCustomerInfo",
|
|
99
|
-
self._validate(data, "customerInfo"),
|
|
100
|
-
)
|
|
88
|
+
def save_stock_master(self, data: dict) -> dict:
|
|
89
|
+
return self.post("saveStockMaster", self._validate(data, "stockMaster"))
|
|
101
90
|
|
|
102
91
|
# -----------------------------
|
|
103
|
-
#
|
|
92
|
+
# NOTICES
|
|
104
93
|
# -----------------------------
|
|
105
|
-
def
|
|
106
|
-
return self.post("
|
|
94
|
+
def select_notice_list(self, data: dict) -> dict:
|
|
95
|
+
return self.post("selectNoticeList", self._validate(data, "lastReqOnly"))
|