nigig-org/nimanyatta/crates/kra-etims-sdk/examples/mock_server.rs
andodeki fd8b0632ca
Some checks failed
repo hygiene / hygiene (push) Has been cancelled
Include nimanyatta as normal tree (not embedded git)
2026-09-26 09:29:36 +03:00

466 lines
No EOL
15 KiB
Rust

// File: examples/mock_server.rs
//! Comprehensive Mock KRA eTims server for local development
//!
//! Run with: cargo run --example mock_server
//! Then set DEV_API_BASE_URL=http://127.0.0.1:8888 in your .env
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpListener;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("╔════════════════════════════════════════════════════════════════╗");
println!("║ Mock KRA eTIMS Server (Development Only) ║");
println!("╠════════════════════════════════════════════════════════════════╣");
println!("║ Company: ITERATE IOT LIMITED (P052038091H) ║");
println!("║ Listening on: http://127.0.0.1:8888 ║");
println!("║ ║");
println!("║ Set in .env: ║");
println!("║ DEV_API_BASE_URL=http://127.0.0.1:8888 ║");
println!("║ API_USERNAME=test_user ║");
println!("║ API_PASSWORD=test_pass ║");
println!("╚════════════════════════════════════════════════════════════════╝");
println!();
let listener = TcpListener::bind("127.0.0.1:8888").await?;
println!("🚀 Mock server started. Waiting for requests...\n");
loop {
let (mut socket, addr) = listener.accept().await?;
tokio::spawn(async move {
let mut buf = vec![0u8; 8192];
match socket.read(&mut buf).await {
Ok(n) if n > 0 => {
let request = String::from_utf8_lossy(&buf[..n]);
let first_line = request.lines().next().unwrap_or("");
println!("📥 [{}] {}", addr, first_line);
let (status, body) = route_request(&request);
let response = format!(
"HTTP/1.1 {}\r\n\
Content-Type: application/json\r\n\
Content-Length: {}\r\n\
Access-Control-Allow-Origin: *\r\n\
Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n\
Access-Control-Allow-Headers: Content-Type, Authorization\r\n\
Connection: close\r\n\
\r\n\
{}",
status,
body.len(),
body
);
let _ = socket.write_all(response.as_bytes()).await;
let preview = if body.len() > 80 {
format!("{}...", &body[..80])
} else {
body.clone()
};
println!("📤 [{}] {} - {}", addr, status, preview);
}
_ => {}
}
});
}
}
fn route_request(request: &str) -> (&'static str, String) {
let path = request
.lines()
.next()
.and_then(|line| line.split_whitespace().nth(1))
.unwrap_or("");
// Handle OPTIONS preflight
if request.starts_with("OPTIONS") {
return ("204 No Content", String::new());
}
match path {
p if p.contains("/oauth2/v1/generate") => {
("200 OK", mock_token_response())
}
p if p.contains("/selectInitOsdcInfo") => {
("200 OK", mock_init_osdc_response())
}
p if p.contains("/selectCodeList") => {
("200 OK", mock_code_list_response())
}
p if p.contains("/selectItemClsList") => {
("200 OK", mock_item_cls_response())
}
p if p.contains("/selectBhfList") => {
("200 OK", mock_bhf_list_response())
}
p if p.contains("/sendSalesTrns") => {
("200 OK", mock_send_sales_response())
}
p if p.contains("/selectSalesTrns") => {
("200 OK", mock_select_sales_response())
}
p if p.contains("/selectNoticeList") => {
("200 OK", mock_notice_response())
}
p if p.contains("/selectTaxpayerInfo") => {
("200 OK", mock_taxpayer_response())
}
p if p.contains("/selectCustomerList") => {
("200 OK", mock_customer_response())
}
p if p.contains("/selectMoveList") => {
("200 OK", mock_move_list_response())
}
p if p.contains("/saveStockMaster") => {
("200 OK", mock_save_stock_response())
}
p if p.contains("/selectPurchaseTrns") => {
("200 OK", mock_purchase_response())
}
p if p.contains("/saveItem") => {
("200 OK", mock_save_item_response())
}
p if p.contains("/selectImportItemList") => {
("200 OK", mock_import_items_response())
}
_ => {
println!("⚠️ Unknown endpoint: {}", path);
("404 Not Found", format!(
r#"{{"resultCd": "9999", "resultMsg": "Endpoint not found: {}"}}"#,
path
))
}
}
}
fn mock_token_response() -> String {
r#"{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.mock_token_for_iterate_iot",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read write"
}"#.to_string()
}
fn mock_init_osdc_response() -> String {
r#"{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {
"tin": "P052038091H",
"bhfId": "00",
"dvcSrlNo": "ITERATE-DEV-001",
"sdcId": "SDC-ITERATE-001",
"mrcNo": "MRC-001",
"lastSaleInvcNo": 0,
"lastPchsInvcNo": 0,
"lastSaleRcptNo": 0,
"lastInvcNo": 0,
"lastTrainInvcNo": 0,
"lastProfrmInvcNo": 0,
"lastCopyInvcNo": 0
}
}"#.to_string()
}
fn mock_code_list_response() -> String {
r#"{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {
"clsList": [
{"cdCls": "01", "cdClsNm": "Tax Type", "cdClsDesc": "Tax Type Codes"},
{"cdCls": "02", "cdClsNm": "Country", "cdClsDesc": "Country Codes"},
{"cdCls": "03", "cdClsNm": "Quantity Unit", "cdClsDesc": "Quantity Unit Codes"},
{"cdCls": "04", "cdClsNm": "Package Unit", "cdClsDesc": "Package Unit Codes"},
{"cdCls": "05", "cdClsNm": "Payment Type", "cdClsDesc": "Payment Type Codes"}
],
"dtlList": [
{"cdCls": "01", "cd": "A", "cdNm": "A-EX", "cdDesc": "Exempt"},
{"cdCls": "01", "cd": "B", "cdNm": "B-16.00%", "cdDesc": "Standard Rate 16%"},
{"cdCls": "01", "cd": "C", "cdNm": "C-0%", "cdDesc": "Zero Rated"},
{"cdCls": "01", "cd": "D", "cdNm": "D-Non-VAT", "cdDesc": "Non-VAT"},
{"cdCls": "01", "cd": "E", "cdNm": "E-8%", "cdDesc": "8% VAT"},
{"cdCls": "02", "cd": "KE", "cdNm": "Kenya", "cdDesc": "Republic of Kenya"},
{"cdCls": "03", "cd": "EA", "cdNm": "Each", "cdDesc": "Each/Piece"},
{"cdCls": "03", "cd": "KG", "cdNm": "Kilogram", "cdDesc": "Kilogram"},
{"cdCls": "03", "cd": "LT", "cdNm": "Litre", "cdDesc": "Litre"},
{"cdCls": "04", "cd": "BX", "cdNm": "Box", "cdDesc": "Box"},
{"cdCls": "04", "cd": "CT", "cdNm": "Carton", "cdDesc": "Carton"},
{"cdCls": "05", "cd": "01", "cdNm": "Cash", "cdDesc": "Cash Payment"},
{"cdCls": "05", "cd": "02", "cdNm": "Credit", "cdDesc": "Credit Payment"},
{"cdCls": "05", "cd": "03", "cdNm": "Mobile", "cdDesc": "Mobile Money"}
]
}
}"#.to_string()
}
fn mock_item_cls_response() -> String {
r#"{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {
"itemClsList": [
{"itemClsCd": "KE1NTXU000", "itemClsNm": "General Goods", "itemClsLvl": 1, "taxTyCd": "B", "mjrTgYn": "N", "useYn": "Y"},
{"itemClsCd": "KE2NTXU001", "itemClsNm": "Electronics", "itemClsLvl": 2, "taxTyCd": "B", "mjrTgYn": "N", "useYn": "Y"},
{"itemClsCd": "KE2NTXU002", "itemClsNm": "Food & Beverages", "itemClsLvl": 2, "taxTyCd": "A", "mjrTgYn": "N", "useYn": "Y"},
{"itemClsCd": "KE2NTXU003", "itemClsNm": "IoT Devices", "itemClsLvl": 2, "taxTyCd": "B", "mjrTgYn": "N", "useYn": "Y"},
{"itemClsCd": "KE2NTXU004", "itemClsNm": "Software & Services", "itemClsLvl": 2, "taxTyCd": "B", "mjrTgYn": "N", "useYn": "Y"}
]
}
}"#.to_string()
}
fn mock_bhf_list_response() -> String {
r#"{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {
"bhfList": [
{
"tin": "P052038091H",
"bhfId": "00",
"bhfNm": "ITERATE IOT LIMITED - Head Office",
"bhfSttsCd": "A",
"prvncNm": "Nairobi",
"dstrtNm": "Westlands",
"sctrNm": "Parklands",
"locDesc": "Innovation Hub, 4th Floor",
"mgrNm": "Manager",
"mgrTelNo": "+254700000000",
"mgrEmail": "info@iterateiot.com"
}
]
}
}"#.to_string()
}
fn mock_send_sales_response() -> String {
use std::time::{SystemTime, UNIX_EPOCH};
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
format!(r#"{{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {{
"rcptNo": {},
"intrlData": "MOCK-INTERNAL-DATA-{}",
"rcptSign": "MOCK-SIGNATURE-{}",
"sdcDateTime": "20240207120000",
"sdcId": "SDC-ITERATE-001",
"mrcNo": "MRC-001",
"qrCodeUrl": "https://etims.kra.go.ke/verify?code=MOCK{}",
"totTaxAmt": 160.00,
"totAmt": 1160.00
}}
}}"#, timestamp % 10000, timestamp, timestamp, timestamp)
}
fn mock_select_sales_response() -> String {
r#"{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {
"salesList": [
{
"invcNo": "INV-2024-0001",
"salesDt": "20240207",
"custTin": "A012345678X",
"custNm": "Test Customer",
"totItemCnt": 2,
"totTaxblAmt": 1000.00,
"totTaxAmt": 160.00,
"totAmt": 1160.00,
"rcptTyCd": "S",
"salesSttsCd": "02"
},
{
"invcNo": "INV-2024-0002",
"salesDt": "20240207",
"custTin": "P987654321Y",
"custNm": "Another Customer",
"totItemCnt": 1,
"totTaxblAmt": 500.00,
"totTaxAmt": 80.00,
"totAmt": 580.00,
"rcptTyCd": "S",
"salesSttsCd": "02"
}
]
}
}"#.to_string()
}
fn mock_notice_response() -> String {
r#"{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {
"noticeList": [
{
"noticeNo": "N-2024-001",
"title": "eTIMS System Update",
"cont": "The eTIMS system will undergo scheduled maintenance on Sunday.",
"regDt": "20240201",
"dtlUrl": "https://etims.kra.go.ke/notices/001"
},
{
"noticeNo": "N-2024-002",
"title": "New VAT Rates Effective",
"cont": "Please note the updated VAT rates effective from the new fiscal year.",
"regDt": "20240115",
"dtlUrl": "https://etims.kra.go.ke/notices/002"
}
]
}
}"#.to_string()
}
fn mock_taxpayer_response() -> String {
r#"{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {
"tin": "P052038091H",
"taxprNm": "ITERATE IOT LIMITED",
"taxprSttsCd": "A",
"taxprSttsNm": "Active",
"prvncNm": "Nairobi",
"dstrtNm": "Westlands",
"sctrNm": "Parklands",
"locDesc": "Innovation Hub, 4th Floor",
"isVatReg": "Y",
"vatRegDt": "20230101"
}
}"#.to_string()
}
fn mock_customer_response() -> String {
r#"{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {
"custList": [
{
"custNo": "CUST-001",
"custTin": "A012345678X",
"custNm": "John Doe",
"adrs": "123 Main Street, Nairobi",
"telNo": "+254700111222",
"email": "john.doe@example.com",
"useYn": "Y"
},
{
"custNo": "CUST-002",
"custTin": "P987654321Y",
"custNm": "ABC Company Ltd",
"adrs": "456 Business Park, Mombasa",
"telNo": "+254700333444",
"email": "info@abccompany.co.ke",
"useYn": "Y"
}
]
}
}"#.to_string()
}
fn mock_move_list_response() -> String {
r#"{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {
"stockList": [
{
"itemCd": "ITEM-001",
"itemNm": "IoT Sensor Module",
"rsdQty": 150.0,
"pkgUnitCd": "EA",
"lastMvDt": "20240206"
},
{
"itemCd": "ITEM-002",
"itemNm": "WiFi Gateway",
"rsdQty": 50.0,
"pkgUnitCd": "EA",
"lastMvDt": "20240205"
}
]
}
}"#.to_string()
}
fn mock_save_stock_response() -> String {
r#"{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {
"itemCd": "ITEM-NEW-001",
"regrId": "SYSTEM",
"regrNm": "System"
}
}"#.to_string()
}
fn mock_purchase_response() -> String {
r#"{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {
"purchaseList": [
{
"invcNo": "PUR-2024-001",
"spplrTin": "P111222333Z",
"spplrNm": "Supplier Company",
"pchsDt": "20240201",
"totItemCnt": 5,
"totTaxblAmt": 50000.00,
"totTaxAmt": 8000.00,
"totAmt": 58000.00
}
]
}
}"#.to_string()
}
fn mock_save_item_response() -> String {
r#"{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {
"itemCd": "ITEM-NEW-001"
}
}"#.to_string()
}
fn mock_import_items_response() -> String {
r#"{
"resultCd": "0000",
"resultMsg": "Successful",
"resultDt": "20240207120000",
"data": {
"itemList": []
}
}"#.to_string()
}