kra-etims-sdk 0.1.0__tar.gz → 0.1.2__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.
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/PKG-INFO +19 -19
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/README.md +18 -18
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/kra_etims_sdk/base_client.py +2 -1
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/kra_etims_sdk/client.py +6 -6
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/kra_etims_sdk/schemas.py +1 -1
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/kra_etims_sdk.egg-info/PKG-INFO +19 -19
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/pyproject.toml +1 -1
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/tests/test_etims.py +20 -21
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/LICENSE +0 -0
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/kra_etims_sdk/__init__.py +0 -0
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/kra_etims_sdk/auth.py +0 -0
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/kra_etims_sdk/exceptions.py +0 -0
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/kra_etims_sdk/validator.py +0 -0
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/kra_etims_sdk.egg-info/SOURCES.txt +0 -0
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/kra_etims_sdk.egg-info/dependency_links.txt +0 -0
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/kra_etims_sdk.egg-info/requires.txt +0 -0
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/kra_etims_sdk.egg-info/top_level.txt +0 -0
- {kra_etims_sdk-0.1.0 → kra_etims_sdk-0.1.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kra-etims-sdk
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Python SDK for KRA eTIMS OSCU API
|
|
5
5
|
Author: Emmanuel Bartile
|
|
6
6
|
License: MIT
|
|
@@ -41,7 +41,7 @@ Dynamic: license-file
|
|
|
41
41
|
|
|
42
42
|
A production-ready **Python SDK** for integrating with the Kenya Revenue Authority (KRA) **eTIMS OSCU** (Online Sales Control Unit) API. Built to match the official Postman collection specifications with strict header compliance, token management, and comprehensive Pydantic validation.
|
|
43
43
|
|
|
44
|
-
> ⚠️ **Critical Note**: This SDK implements the **new OSCU specification** (KRA-hosted), *not* the
|
|
44
|
+
> ⚠️ **Critical Note**: This SDK implements the **new OSCU specification** (KRA-hosted), *not* the VSCU eTIMS API. OSCU requires device registration, headers, and `cmcKey` lifecycle management.
|
|
45
45
|
|
|
46
46
|
## Author
|
|
47
47
|
**Bartile Emmanuel**
|
|
@@ -73,15 +73,15 @@ A production-ready **Python SDK** for integrating with the Kenya Revenue Authori
|
|
|
73
73
|
|
|
74
74
|
## Introduction to eTIMS OSCU
|
|
75
75
|
|
|
76
|
-
KRA's **Electronic Tax Invoice Management System (eTIMS)** uses **OSCU** (Online Sales Control Unit) – a KRA-hosted software module that validates and signs tax invoices in real-time before issuance. Unlike
|
|
76
|
+
KRA's **Electronic Tax Invoice Management System (eTIMS)** uses **OSCU** (Online Sales Control Unit) – a KRA-hosted software module that validates and signs tax invoices in real-time before issuance. Unlike VSCU, OSCU requires:
|
|
77
77
|
|
|
78
78
|
- Pre-registered device serial numbers (`dvcSrlNo`)
|
|
79
79
|
- Communication key (`cmcKey`) lifecycle management
|
|
80
80
|
- Strict payload schema compliance per KRA specifications
|
|
81
81
|
|
|
82
|
-
### OSCU vs
|
|
82
|
+
### OSCU vs VSCU eTIMS
|
|
83
83
|
|
|
84
|
-
| Feature | OSCU (This SDK) |
|
|
84
|
+
| Feature | OSCU (This SDK) | VSCU eTIMS |
|
|
85
85
|
|---------|-----------------|--------------|
|
|
86
86
|
| **Hosting** | KRA-hosted (cloud) | Self-hosted (on-premise) |
|
|
87
87
|
| **Device Registration** | Mandatory pre-registration | Not required |
|
|
@@ -191,17 +191,18 @@ flowchart TD
|
|
|
191
191
|
Before integration, you **MUST** complete these prerequisites:
|
|
192
192
|
|
|
193
193
|
### 1. Device Registration (MANDATORY)
|
|
194
|
-
- Register OSCU device via [eTIMS Taxpayer
|
|
194
|
+
- Register OSCU device via [eTIMS Taxpayer Production Portal](https://etims.kra.go.ke)
|
|
195
|
+
- Register OSCU device via [eTIMS Taxpayer Sandbox Portal](https://etims-sbx.kra.go.ke)
|
|
195
196
|
- Obtain **approved device serial number** (`dvcSrlNo`)
|
|
196
197
|
- ⚠️ **Dynamic/unregistered device serials fail with `resultCd: 901`** ("It is not valid device")
|
|
197
198
|
|
|
198
199
|
### 2. Communication Key Lifecycle
|
|
199
200
|
```python
|
|
200
201
|
# 1. Initialize FIRST (returns cmcKey)
|
|
201
|
-
response = etims.
|
|
202
|
+
response = etims.select_init_osdc_info({
|
|
202
203
|
"tin": config.oscu["tin"],
|
|
203
204
|
"bhfId": config.oscu["bhf_id"],
|
|
204
|
-
"dvcSrlNo": "
|
|
205
|
+
"dvcSrlNo": config.oscu["device_serial"], # KRA-approved serial
|
|
205
206
|
})
|
|
206
207
|
|
|
207
208
|
# 2. Extract cmcKey (sandbox returns at root level)
|
|
@@ -304,19 +305,19 @@ config = KraEtimsConfig(
|
|
|
304
305
|
},
|
|
305
306
|
|
|
306
307
|
api={
|
|
307
|
-
"sandbox": {"base_url": "https://sbx.kra.go.ke/etims-
|
|
308
|
-
"production": {"base_url": "https://api.
|
|
308
|
+
"sandbox": {"base_url": "https://etims-api-sbx.kra.go.ke/etims-api".strip()},
|
|
309
|
+
"production": {"base_url": "https://etims-api.kra.go.ke/etims-api".strip()}
|
|
309
310
|
},
|
|
310
311
|
|
|
311
312
|
oscu={
|
|
312
313
|
"tin": os.environ["KRA_TIN"],
|
|
313
|
-
"bhf_id": os.environ["KRA_BHF_ID"],
|
|
314
|
-
"cmc_key": ""
|
|
314
|
+
"bhf_id": os.environ["KRA_BHF_ID"],
|
|
315
|
+
"cmc_key": os.environ["CMC_KEY"] # Set AFTER initialization
|
|
315
316
|
},
|
|
316
317
|
|
|
317
318
|
endpoints={
|
|
318
319
|
# INITIALIZATION (ONLY endpoint without tin/bhfId/cmcKey headers)
|
|
319
|
-
"
|
|
320
|
+
"selectInitOsdcInfo": "/selectInitOsdcInfo",
|
|
320
321
|
|
|
321
322
|
# DATA MANAGEMENT
|
|
322
323
|
"selectCodeList": "/selectCodeList",
|
|
@@ -355,7 +356,7 @@ config = KraEtimsConfig(
|
|
|
355
356
|
```
|
|
356
357
|
|
|
357
358
|
> 💡 **Production URL Note**:
|
|
358
|
-
> Production base URL is `https://api.
|
|
359
|
+
> Production base URL is `https://etims-api.kra.go.ke/etims-api` (NOT `https://etims-api-sbx.kra.go.ke/etims-api`)
|
|
359
360
|
|
|
360
361
|
---
|
|
361
362
|
|
|
@@ -386,12 +387,11 @@ except AuthenticationException as e:
|
|
|
386
387
|
try:
|
|
387
388
|
# ⚠️ MUST use KRA-approved device serial (NOT dynamic!)
|
|
388
389
|
# Common sandbox test value (if pre-provisioned by KRA):
|
|
389
|
-
device_serial = "dvcv1130" # REPLACE with your approved serial
|
|
390
390
|
|
|
391
|
-
response = etims.
|
|
391
|
+
response = etims.select_init_info({
|
|
392
392
|
"tin": config.oscu["tin"],
|
|
393
393
|
"bhfId": config.oscu["bhf_id"],
|
|
394
|
-
"dvcSrlNo": device_serial
|
|
394
|
+
"dvcSrlNo": config.oscu["device_serial"],
|
|
395
395
|
})
|
|
396
396
|
|
|
397
397
|
# Extract cmcKey (sandbox returns at root level)
|
|
@@ -506,7 +506,7 @@ except ApiException as e:
|
|
|
506
506
|
|
|
507
507
|
| Category | Purpose | Endpoints |
|
|
508
508
|
|----------|---------|-----------|
|
|
509
|
-
| **Initialization** | Device registration & cmcKey acquisition | `
|
|
509
|
+
| **Initialization** | Device registration & cmcKey acquisition | `select_init_info` |
|
|
510
510
|
| **Data Management** | Retrieve standard codes & master data | `select_code_list`, `select_item_cls_list`, `select_bhf_list`, `select_taxpayer_info`, `select_customer_list`, `select_notice_list` |
|
|
511
511
|
| **Branch Management** | Manage branch offices & users | `branch_insurance_info`, `branch_user_account`, `branch_send_customer_info` |
|
|
512
512
|
| **Item Management** | Item master data | `save_item`, `item_info` |
|
|
@@ -720,7 +720,7 @@ KRA mandates successful completion of automated tests before verification:
|
|
|
720
720
|
3. Deploy directly to production environment
|
|
721
721
|
4. No SLA execution required
|
|
722
722
|
|
|
723
|
-
> 💡 **Production URL**: `https://api.
|
|
723
|
+
> 💡 **Production URL**: `https://etims-api.kra.go.ke/etims-api`
|
|
724
724
|
> ⚠️ **Never use sandbox credentials in production** – KRA monitors environment separation strictly
|
|
725
725
|
|
|
726
726
|
---
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
A production-ready **Python SDK** for integrating with the Kenya Revenue Authority (KRA) **eTIMS OSCU** (Online Sales Control Unit) API. Built to match the official Postman collection specifications with strict header compliance, token management, and comprehensive Pydantic validation.
|
|
20
20
|
|
|
21
|
-
> ⚠️ **Critical Note**: This SDK implements the **new OSCU specification** (KRA-hosted), *not* the
|
|
21
|
+
> ⚠️ **Critical Note**: This SDK implements the **new OSCU specification** (KRA-hosted), *not* the VSCU eTIMS API. OSCU requires device registration, headers, and `cmcKey` lifecycle management.
|
|
22
22
|
|
|
23
23
|
## Author
|
|
24
24
|
**Bartile Emmanuel**
|
|
@@ -50,15 +50,15 @@ A production-ready **Python SDK** for integrating with the Kenya Revenue Authori
|
|
|
50
50
|
|
|
51
51
|
## Introduction to eTIMS OSCU
|
|
52
52
|
|
|
53
|
-
KRA's **Electronic Tax Invoice Management System (eTIMS)** uses **OSCU** (Online Sales Control Unit) – a KRA-hosted software module that validates and signs tax invoices in real-time before issuance. Unlike
|
|
53
|
+
KRA's **Electronic Tax Invoice Management System (eTIMS)** uses **OSCU** (Online Sales Control Unit) – a KRA-hosted software module that validates and signs tax invoices in real-time before issuance. Unlike VSCU, OSCU requires:
|
|
54
54
|
|
|
55
55
|
- Pre-registered device serial numbers (`dvcSrlNo`)
|
|
56
56
|
- Communication key (`cmcKey`) lifecycle management
|
|
57
57
|
- Strict payload schema compliance per KRA specifications
|
|
58
58
|
|
|
59
|
-
### OSCU vs
|
|
59
|
+
### OSCU vs VSCU eTIMS
|
|
60
60
|
|
|
61
|
-
| Feature | OSCU (This SDK) |
|
|
61
|
+
| Feature | OSCU (This SDK) | VSCU eTIMS |
|
|
62
62
|
|---------|-----------------|--------------|
|
|
63
63
|
| **Hosting** | KRA-hosted (cloud) | Self-hosted (on-premise) |
|
|
64
64
|
| **Device Registration** | Mandatory pre-registration | Not required |
|
|
@@ -168,17 +168,18 @@ flowchart TD
|
|
|
168
168
|
Before integration, you **MUST** complete these prerequisites:
|
|
169
169
|
|
|
170
170
|
### 1. Device Registration (MANDATORY)
|
|
171
|
-
- Register OSCU device via [eTIMS Taxpayer
|
|
171
|
+
- Register OSCU device via [eTIMS Taxpayer Production Portal](https://etims.kra.go.ke)
|
|
172
|
+
- Register OSCU device via [eTIMS Taxpayer Sandbox Portal](https://etims-sbx.kra.go.ke)
|
|
172
173
|
- Obtain **approved device serial number** (`dvcSrlNo`)
|
|
173
174
|
- ⚠️ **Dynamic/unregistered device serials fail with `resultCd: 901`** ("It is not valid device")
|
|
174
175
|
|
|
175
176
|
### 2. Communication Key Lifecycle
|
|
176
177
|
```python
|
|
177
178
|
# 1. Initialize FIRST (returns cmcKey)
|
|
178
|
-
response = etims.
|
|
179
|
+
response = etims.select_init_osdc_info({
|
|
179
180
|
"tin": config.oscu["tin"],
|
|
180
181
|
"bhfId": config.oscu["bhf_id"],
|
|
181
|
-
"dvcSrlNo": "
|
|
182
|
+
"dvcSrlNo": config.oscu["device_serial"], # KRA-approved serial
|
|
182
183
|
})
|
|
183
184
|
|
|
184
185
|
# 2. Extract cmcKey (sandbox returns at root level)
|
|
@@ -281,19 +282,19 @@ config = KraEtimsConfig(
|
|
|
281
282
|
},
|
|
282
283
|
|
|
283
284
|
api={
|
|
284
|
-
"sandbox": {"base_url": "https://sbx.kra.go.ke/etims-
|
|
285
|
-
"production": {"base_url": "https://api.
|
|
285
|
+
"sandbox": {"base_url": "https://etims-api-sbx.kra.go.ke/etims-api".strip()},
|
|
286
|
+
"production": {"base_url": "https://etims-api.kra.go.ke/etims-api".strip()}
|
|
286
287
|
},
|
|
287
288
|
|
|
288
289
|
oscu={
|
|
289
290
|
"tin": os.environ["KRA_TIN"],
|
|
290
|
-
"bhf_id": os.environ["KRA_BHF_ID"],
|
|
291
|
-
"cmc_key": ""
|
|
291
|
+
"bhf_id": os.environ["KRA_BHF_ID"],
|
|
292
|
+
"cmc_key": os.environ["CMC_KEY"] # Set AFTER initialization
|
|
292
293
|
},
|
|
293
294
|
|
|
294
295
|
endpoints={
|
|
295
296
|
# INITIALIZATION (ONLY endpoint without tin/bhfId/cmcKey headers)
|
|
296
|
-
"
|
|
297
|
+
"selectInitOsdcInfo": "/selectInitOsdcInfo",
|
|
297
298
|
|
|
298
299
|
# DATA MANAGEMENT
|
|
299
300
|
"selectCodeList": "/selectCodeList",
|
|
@@ -332,7 +333,7 @@ config = KraEtimsConfig(
|
|
|
332
333
|
```
|
|
333
334
|
|
|
334
335
|
> 💡 **Production URL Note**:
|
|
335
|
-
> Production base URL is `https://api.
|
|
336
|
+
> Production base URL is `https://etims-api.kra.go.ke/etims-api` (NOT `https://etims-api-sbx.kra.go.ke/etims-api`)
|
|
336
337
|
|
|
337
338
|
---
|
|
338
339
|
|
|
@@ -363,12 +364,11 @@ except AuthenticationException as e:
|
|
|
363
364
|
try:
|
|
364
365
|
# ⚠️ MUST use KRA-approved device serial (NOT dynamic!)
|
|
365
366
|
# Common sandbox test value (if pre-provisioned by KRA):
|
|
366
|
-
device_serial = "dvcv1130" # REPLACE with your approved serial
|
|
367
367
|
|
|
368
|
-
response = etims.
|
|
368
|
+
response = etims.select_init_info({
|
|
369
369
|
"tin": config.oscu["tin"],
|
|
370
370
|
"bhfId": config.oscu["bhf_id"],
|
|
371
|
-
"dvcSrlNo": device_serial
|
|
371
|
+
"dvcSrlNo": config.oscu["device_serial"],
|
|
372
372
|
})
|
|
373
373
|
|
|
374
374
|
# Extract cmcKey (sandbox returns at root level)
|
|
@@ -483,7 +483,7 @@ except ApiException as e:
|
|
|
483
483
|
|
|
484
484
|
| Category | Purpose | Endpoints |
|
|
485
485
|
|----------|---------|-----------|
|
|
486
|
-
| **Initialization** | Device registration & cmcKey acquisition | `
|
|
486
|
+
| **Initialization** | Device registration & cmcKey acquisition | `select_init_info` |
|
|
487
487
|
| **Data Management** | Retrieve standard codes & master data | `select_code_list`, `select_item_cls_list`, `select_bhf_list`, `select_taxpayer_info`, `select_customer_list`, `select_notice_list` |
|
|
488
488
|
| **Branch Management** | Manage branch offices & users | `branch_insurance_info`, `branch_user_account`, `branch_send_customer_info` |
|
|
489
489
|
| **Item Management** | Item master data | `save_item`, `item_info` |
|
|
@@ -697,7 +697,7 @@ KRA mandates successful completion of automated tests before verification:
|
|
|
697
697
|
3. Deploy directly to production environment
|
|
698
698
|
4. No SLA execution required
|
|
699
699
|
|
|
700
|
-
> 💡 **Production URL**: `https://api.
|
|
700
|
+
> 💡 **Production URL**: `https://etims-api.kra.go.ke/etims-api`
|
|
701
701
|
> ⚠️ **Never use sandbox credentials in production** – KRA monitors environment separation strictly
|
|
702
702
|
|
|
703
703
|
---
|
|
@@ -32,10 +32,11 @@ class BaseClient:
|
|
|
32
32
|
def _request(self, method, endpoint, data):
|
|
33
33
|
url = self.base_url() + endpoint
|
|
34
34
|
headers = self._headers(endpoint)
|
|
35
|
+
print(url, headers, data)
|
|
35
36
|
return requests.request(method, url, json=data, headers=headers, timeout=30)
|
|
36
37
|
|
|
37
38
|
def _headers(self, endpoint):
|
|
38
|
-
if endpoint.endswith("/
|
|
39
|
+
if endpoint.endswith("/selectInitOsdcInfo"):
|
|
39
40
|
return {
|
|
40
41
|
"Authorization": f"Bearer {self.auth.token()}",
|
|
41
42
|
"Content-Type": "application/json",
|
|
@@ -11,12 +11,12 @@ class EtimsClient(BaseClient):
|
|
|
11
11
|
def _validate(self, data: dict, schema: str) -> dict:
|
|
12
12
|
return self.validator.validate(data, schema)
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return self.post("
|
|
14
|
+
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
|
+
return self.post("selectInitOsdcInfo", self._validate(data, "initialization"))
|
|
20
20
|
|
|
21
21
|
# -----------------------------
|
|
22
22
|
# BASIC DATA ENDPOINTS
|
|
@@ -14,7 +14,7 @@ from pydantic import (
|
|
|
14
14
|
# =========================================================
|
|
15
15
|
|
|
16
16
|
TIN = Annotated[str, StringConstraints(min_length=1, max_length=20)]
|
|
17
|
-
BHF = Annotated[str, StringConstraints(min_length=1, max_length=
|
|
17
|
+
BHF = Annotated[str, StringConstraints(min_length=1, max_length=20)]
|
|
18
18
|
|
|
19
19
|
YN = Annotated[str, StringConstraints(pattern="^[YN]$")]
|
|
20
20
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kra-etims-sdk
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Python SDK for KRA eTIMS OSCU API
|
|
5
5
|
Author: Emmanuel Bartile
|
|
6
6
|
License: MIT
|
|
@@ -41,7 +41,7 @@ Dynamic: license-file
|
|
|
41
41
|
|
|
42
42
|
A production-ready **Python SDK** for integrating with the Kenya Revenue Authority (KRA) **eTIMS OSCU** (Online Sales Control Unit) API. Built to match the official Postman collection specifications with strict header compliance, token management, and comprehensive Pydantic validation.
|
|
43
43
|
|
|
44
|
-
> ⚠️ **Critical Note**: This SDK implements the **new OSCU specification** (KRA-hosted), *not* the
|
|
44
|
+
> ⚠️ **Critical Note**: This SDK implements the **new OSCU specification** (KRA-hosted), *not* the VSCU eTIMS API. OSCU requires device registration, headers, and `cmcKey` lifecycle management.
|
|
45
45
|
|
|
46
46
|
## Author
|
|
47
47
|
**Bartile Emmanuel**
|
|
@@ -73,15 +73,15 @@ A production-ready **Python SDK** for integrating with the Kenya Revenue Authori
|
|
|
73
73
|
|
|
74
74
|
## Introduction to eTIMS OSCU
|
|
75
75
|
|
|
76
|
-
KRA's **Electronic Tax Invoice Management System (eTIMS)** uses **OSCU** (Online Sales Control Unit) – a KRA-hosted software module that validates and signs tax invoices in real-time before issuance. Unlike
|
|
76
|
+
KRA's **Electronic Tax Invoice Management System (eTIMS)** uses **OSCU** (Online Sales Control Unit) – a KRA-hosted software module that validates and signs tax invoices in real-time before issuance. Unlike VSCU, OSCU requires:
|
|
77
77
|
|
|
78
78
|
- Pre-registered device serial numbers (`dvcSrlNo`)
|
|
79
79
|
- Communication key (`cmcKey`) lifecycle management
|
|
80
80
|
- Strict payload schema compliance per KRA specifications
|
|
81
81
|
|
|
82
|
-
### OSCU vs
|
|
82
|
+
### OSCU vs VSCU eTIMS
|
|
83
83
|
|
|
84
|
-
| Feature | OSCU (This SDK) |
|
|
84
|
+
| Feature | OSCU (This SDK) | VSCU eTIMS |
|
|
85
85
|
|---------|-----------------|--------------|
|
|
86
86
|
| **Hosting** | KRA-hosted (cloud) | Self-hosted (on-premise) |
|
|
87
87
|
| **Device Registration** | Mandatory pre-registration | Not required |
|
|
@@ -191,17 +191,18 @@ flowchart TD
|
|
|
191
191
|
Before integration, you **MUST** complete these prerequisites:
|
|
192
192
|
|
|
193
193
|
### 1. Device Registration (MANDATORY)
|
|
194
|
-
- Register OSCU device via [eTIMS Taxpayer
|
|
194
|
+
- Register OSCU device via [eTIMS Taxpayer Production Portal](https://etims.kra.go.ke)
|
|
195
|
+
- Register OSCU device via [eTIMS Taxpayer Sandbox Portal](https://etims-sbx.kra.go.ke)
|
|
195
196
|
- Obtain **approved device serial number** (`dvcSrlNo`)
|
|
196
197
|
- ⚠️ **Dynamic/unregistered device serials fail with `resultCd: 901`** ("It is not valid device")
|
|
197
198
|
|
|
198
199
|
### 2. Communication Key Lifecycle
|
|
199
200
|
```python
|
|
200
201
|
# 1. Initialize FIRST (returns cmcKey)
|
|
201
|
-
response = etims.
|
|
202
|
+
response = etims.select_init_osdc_info({
|
|
202
203
|
"tin": config.oscu["tin"],
|
|
203
204
|
"bhfId": config.oscu["bhf_id"],
|
|
204
|
-
"dvcSrlNo": "
|
|
205
|
+
"dvcSrlNo": config.oscu["device_serial"], # KRA-approved serial
|
|
205
206
|
})
|
|
206
207
|
|
|
207
208
|
# 2. Extract cmcKey (sandbox returns at root level)
|
|
@@ -304,19 +305,19 @@ config = KraEtimsConfig(
|
|
|
304
305
|
},
|
|
305
306
|
|
|
306
307
|
api={
|
|
307
|
-
"sandbox": {"base_url": "https://sbx.kra.go.ke/etims-
|
|
308
|
-
"production": {"base_url": "https://api.
|
|
308
|
+
"sandbox": {"base_url": "https://etims-api-sbx.kra.go.ke/etims-api".strip()},
|
|
309
|
+
"production": {"base_url": "https://etims-api.kra.go.ke/etims-api".strip()}
|
|
309
310
|
},
|
|
310
311
|
|
|
311
312
|
oscu={
|
|
312
313
|
"tin": os.environ["KRA_TIN"],
|
|
313
|
-
"bhf_id": os.environ["KRA_BHF_ID"],
|
|
314
|
-
"cmc_key": ""
|
|
314
|
+
"bhf_id": os.environ["KRA_BHF_ID"],
|
|
315
|
+
"cmc_key": os.environ["CMC_KEY"] # Set AFTER initialization
|
|
315
316
|
},
|
|
316
317
|
|
|
317
318
|
endpoints={
|
|
318
319
|
# INITIALIZATION (ONLY endpoint without tin/bhfId/cmcKey headers)
|
|
319
|
-
"
|
|
320
|
+
"selectInitOsdcInfo": "/selectInitOsdcInfo",
|
|
320
321
|
|
|
321
322
|
# DATA MANAGEMENT
|
|
322
323
|
"selectCodeList": "/selectCodeList",
|
|
@@ -355,7 +356,7 @@ config = KraEtimsConfig(
|
|
|
355
356
|
```
|
|
356
357
|
|
|
357
358
|
> 💡 **Production URL Note**:
|
|
358
|
-
> Production base URL is `https://api.
|
|
359
|
+
> Production base URL is `https://etims-api.kra.go.ke/etims-api` (NOT `https://etims-api-sbx.kra.go.ke/etims-api`)
|
|
359
360
|
|
|
360
361
|
---
|
|
361
362
|
|
|
@@ -386,12 +387,11 @@ except AuthenticationException as e:
|
|
|
386
387
|
try:
|
|
387
388
|
# ⚠️ MUST use KRA-approved device serial (NOT dynamic!)
|
|
388
389
|
# Common sandbox test value (if pre-provisioned by KRA):
|
|
389
|
-
device_serial = "dvcv1130" # REPLACE with your approved serial
|
|
390
390
|
|
|
391
|
-
response = etims.
|
|
391
|
+
response = etims.select_init_info({
|
|
392
392
|
"tin": config.oscu["tin"],
|
|
393
393
|
"bhfId": config.oscu["bhf_id"],
|
|
394
|
-
"dvcSrlNo": device_serial
|
|
394
|
+
"dvcSrlNo": config.oscu["device_serial"],
|
|
395
395
|
})
|
|
396
396
|
|
|
397
397
|
# Extract cmcKey (sandbox returns at root level)
|
|
@@ -506,7 +506,7 @@ except ApiException as e:
|
|
|
506
506
|
|
|
507
507
|
| Category | Purpose | Endpoints |
|
|
508
508
|
|----------|---------|-----------|
|
|
509
|
-
| **Initialization** | Device registration & cmcKey acquisition | `
|
|
509
|
+
| **Initialization** | Device registration & cmcKey acquisition | `select_init_info` |
|
|
510
510
|
| **Data Management** | Retrieve standard codes & master data | `select_code_list`, `select_item_cls_list`, `select_bhf_list`, `select_taxpayer_info`, `select_customer_list`, `select_notice_list` |
|
|
511
511
|
| **Branch Management** | Manage branch offices & users | `branch_insurance_info`, `branch_user_account`, `branch_send_customer_info` |
|
|
512
512
|
| **Item Management** | Item master data | `save_item`, `item_info` |
|
|
@@ -720,7 +720,7 @@ KRA mandates successful completion of automated tests before verification:
|
|
|
720
720
|
3. Deploy directly to production environment
|
|
721
721
|
4. No SLA execution required
|
|
722
722
|
|
|
723
|
-
> 💡 **Production URL**: `https://api.
|
|
723
|
+
> 💡 **Production URL**: `https://etims-api.kra.go.ke/etims-api`
|
|
724
724
|
> ⚠️ **Never use sandbox credentials in production** – KRA monitors environment separation strictly
|
|
725
725
|
|
|
726
726
|
---
|
|
@@ -60,10 +60,10 @@ CONFIG = {
|
|
|
60
60
|
|
|
61
61
|
"api": {
|
|
62
62
|
"sbx": {
|
|
63
|
-
"base_url": "https://sbx.kra.go.ke/etims-
|
|
63
|
+
"base_url": "https://etims-api-sbx.kra.go.ke/etims-api",
|
|
64
64
|
},
|
|
65
65
|
"prod": {
|
|
66
|
-
"base_url": "https://kra.go.ke/etims-
|
|
66
|
+
"base_url": "https://etims-api.kra.go.ke/etims-api",
|
|
67
67
|
},
|
|
68
68
|
},
|
|
69
69
|
|
|
@@ -72,13 +72,14 @@ CONFIG = {
|
|
|
72
72
|
},
|
|
73
73
|
|
|
74
74
|
"oscu": {
|
|
75
|
-
"tin": os.getenv("KRA_TIN", "
|
|
76
|
-
"bhf_id": os.getenv("KRA_BHF_ID", "
|
|
77
|
-
"cmc_key": "",
|
|
75
|
+
"tin": os.getenv("KRA_TIN", ""),
|
|
76
|
+
"bhf_id": os.getenv("KRA_BHF_ID", ""),
|
|
77
|
+
"cmc_key": os.getenv("CMC_KEY", ""),
|
|
78
|
+
"device_serial": os.getenv("DEVICE_SERIAL", ""),
|
|
78
79
|
},
|
|
79
80
|
|
|
80
81
|
"endpoints": {
|
|
81
|
-
"
|
|
82
|
+
"selectInitOsdcInfo": "/selectInitOsdcInfo",
|
|
82
83
|
"selectCodeList": "/selectCodeList",
|
|
83
84
|
"selectTaxpayerInfo": "/selectTaxpayerInfo",
|
|
84
85
|
"selectNoticeList": "/selectNoticeList",
|
|
@@ -124,28 +125,26 @@ except AuthenticationException as e:
|
|
|
124
125
|
header("STEP 2: OSCU INITIALIZATION")
|
|
125
126
|
warning("Device serial MUST be pre-registered with KRA")
|
|
126
127
|
|
|
127
|
-
DEVICE_SERIAL = "dvcv1130" # 🔴 REPLACE WITH APPROVED SERIAL
|
|
128
|
-
|
|
129
128
|
try:
|
|
130
129
|
etims = EtimsClient(CONFIG, auth)
|
|
131
130
|
|
|
132
|
-
response = etims.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
})
|
|
131
|
+
# response = etims.select_init_info({
|
|
132
|
+
# "tin": CONFIG["oscu"]["tin"],
|
|
133
|
+
# "bhfId": CONFIG["oscu"]["bhf_id"],
|
|
134
|
+
# "dvcSrlNo": CONFIG["oscu"]["device_serial"],
|
|
135
|
+
# })
|
|
137
136
|
|
|
138
|
-
pprint(response)
|
|
137
|
+
# pprint(response)
|
|
138
|
+
|
|
139
|
+
# cmc_key = response.get("cmcKey") or response.get("data", {}).get("info", {}).get("cmcKey")
|
|
140
|
+
# if not cmc_key:
|
|
141
|
+
# raise RuntimeError("cmcKey missing from initialization response")
|
|
139
142
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
raise RuntimeError("cmcKey missing from initialization response")
|
|
143
|
+
# success("Initialization successful")
|
|
144
|
+
# print("cmcKey:", cmc_key[:15], "...")
|
|
143
145
|
|
|
144
|
-
CONFIG["oscu"]["cmc_key"] = cmc_key
|
|
145
146
|
etims = EtimsClient(CONFIG, auth)
|
|
146
147
|
|
|
147
|
-
success("Initialization successful")
|
|
148
|
-
print("cmcKey:", cmc_key[:15], "...")
|
|
149
148
|
except ApiException as e:
|
|
150
149
|
error(f"Initialization failed: {e}")
|
|
151
150
|
pprint(e.details)
|
|
@@ -160,10 +159,10 @@ try:
|
|
|
160
159
|
"bhfId": CONFIG["oscu"]["bhf_id"],
|
|
161
160
|
"lastReqDt": format_date(),
|
|
162
161
|
})
|
|
163
|
-
|
|
164
162
|
count = len(response.get("itemList", []))
|
|
165
163
|
success(f"Retrieved {count} code list items")
|
|
166
164
|
except ApiException as e:
|
|
165
|
+
print("emm")
|
|
167
166
|
error(str(e))
|
|
168
167
|
sys.exit(1)
|
|
169
168
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|