// 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> { 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() }