/** * PayUs Integrator Demo — Android (Kotlin) * * Single-file demo showing the full third-party integration flow using raw HTTP. * No SDK dependency — uses java.net.HttpURLConnection for clarity. * * Run as Kotlin script: kotlin IntegratorDemo.kt * Or compile: kotlinc IntegratorDemo.kt -include-runtime -d demo.jar && java -jar demo.jar * * ⚠️ Replace APP_ID, APP_SECRET, and BRANCH_ID with your real values. */ import java.io.OutputStreamWriter import java.net.HttpURLConnection import java.net.URL import java.util.Base64 const val BASE = "https://payus.co.nz" const val SYSTEM = "pos" const val APP_ID = "YOUR_APP_ID" const val APP_SECRET = "YOUR_APP_SECRET" const val BRANCH_ID = 123L fun main() { println("═══════════════════════════════════════════════════") println(" PayUs Integrator Demo — Android (Kotlin)") println("═══════════════════════════════════════════════════") // Step 1: Authenticate println("\n🔐 Step 1: Authenticating...") val credentials = Base64.getEncoder().encodeToString("$APP_ID:$APP_SECRET".toByteArray()) val authResponse = post("$BASE/api/v1/oauth/token", null, mapOf("Authorization" to "Basic $credentials")) println(" ✅ Token acquired") // Parse token from JSON response (simple string extraction) val token = authResponse.substringAfter("\"token\":\"").substringBefore("\"") // Step 2: List terminals println("\n📱 Step 2: Listing terminals...") val terminalsResponse = get("$BASE/api/v1/$SYSTEM/listTerminals?branchId=$BRANCH_ID", token) println(" ✅ Response: ${terminalsResponse.take(200)}...") // Step 3: Send PRINT trigger (requires terminals:trigger scope) println("\n🖨️ Step 3: Sending PRINT trigger...") val triggerBody = """ {"terminalId":"TERM001","accessId":"ACCESS001","requestType":"PRINT", "body":"Hello from Kotlin integrator!","branchId":$BRANCH_ID,"configId":1} """.trimIndent() try { val triggerResp = post("$BASE/api/v1/$SYSTEM/requestTerminal", triggerBody, bearerHeader(token)) println(" ✅ Trigger sent: ${triggerResp.take(100)}") } catch (e: Exception) { println(" ⚠️ Trigger failed: ${e.message}") } // Step 4: Process payment (requires payments:direct scope) println("\n💳 Step 4: Processing test payment...") val payBody = """ {"grandTotal":"0.01","referenceId":"kt_demo_${System.currentTimeMillis()}", "branchId":$BRANCH_ID,"configId":1,"terminalId":"TERM001","accessId":"ACCESS001", "channel":"WECHAT","qrMode":true} """.trimIndent() try { val payResp = post("$BASE/api/v1/$SYSTEM/payNow", payBody, bearerHeader(token)) println(" ✅ Payment response: ${payResp.take(200)}") } catch (e: Exception) { println(" ⚠️ Payment failed: ${e.message} (expected without payments:direct scope)") } // Step 5: Query transactions (requires transactions:read scope) println("\n📊 Step 5: Querying transactions...") val today = java.time.LocalDate.now().toString() val queryBody = """{"branchId":$BRANCH_ID,"startDate":"$today","endDate":"$today"}""" try { val queryResp = post("$BASE/api/v1/$SYSTEM/getRecentTransactions", queryBody, bearerHeader(token)) println(" ✅ Transactions: ${queryResp.take(200)}...") } catch (e: Exception) { println(" ⚠️ Query failed: ${e.message}") } println("\n✅ Demo complete!") } fun bearerHeader(token: String) = mapOf("Authorization" to "Bearer $token") fun get(url: String, token: String): String { val conn = URL(url).openConnection() as HttpURLConnection conn.requestMethod = "GET" conn.setRequestProperty("Authorization", "Bearer $token") conn.setRequestProperty("Accept", "application/json") if (conn.responseCode != 200) throw Exception("${conn.responseCode}: ${conn.errorStream?.bufferedReader()?.readText()}") return conn.inputStream.bufferedReader().readText() } fun post(url: String, body: String?, headers: Map): String { val conn = URL(url).openConnection() as HttpURLConnection conn.requestMethod = "POST" conn.setRequestProperty("Accept", "application/json") headers.forEach { (k, v) -> conn.setRequestProperty(k, v) } if (body != null) { conn.doOutput = true conn.setRequestProperty("Content-Type", "application/json") OutputStreamWriter(conn.outputStream).use { it.write(body) } } if (conn.responseCode !in 200..299) { val err = conn.errorStream?.bufferedReader()?.readText() ?: "No body" throw Exception("${conn.responseCode}: $err") } return conn.inputStream.bufferedReader().readText() }