gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant-terminal-android] 06/19: Create payments directly from t


From: gnunet
Subject: [taler-merchant-terminal-android] 06/19: Create payments directly from the order
Date: Fri, 21 Feb 2020 18:59:59 +0100

This is an automated email from the git hooks/post-receive script.

torsten-grote pushed a commit to branch master
in repository merchant-terminal-android.

commit 98125ea57089b714a1fe44bf1f22520928aa0f3b
Author: Torsten Grote <address@hidden>
AuthorDate: Fri Jan 31 16:37:51 2020 -0300

    Create payments directly from the order
    
    This removes the CreatePayment fragment as it isn't needed anymore.
---
 .../java/net/taler/merchantpos/CreatePayment.kt    | 131 -------------------
 .../java/net/taler/merchantpos/MainActivity.kt     |  30 +----
 .../java/net/taler/merchantpos/MainViewModel.kt    |  15 +--
 .../java/net/taler/merchantpos/ProcessPayment.kt   | 143 ---------------------
 .../net/taler/merchantpos/config/ConfigManager.kt  |   1 -
 .../net/taler/merchantpos/order/Definitions.kt     |   2 +
 .../net/taler/merchantpos/order/OrderFragment.kt   |   6 +
 .../net/taler/merchantpos/order/OrderManager.kt    |  26 ++--
 .../java/net/taler/merchantpos/payment/Payment.kt  |  13 ++
 .../taler/merchantpos/payment/PaymentManager.kt    | 113 ++++++++++++++++
 .../merchantpos/{ => payment}/PaymentSuccess.kt    |   5 +-
 .../merchantpos/payment/ProcessPaymentFragment.kt  |  85 ++++++++++++
 app/src/main/res/layout/activity_main.xml          |   3 +-
 .../main/res/layout/fragment_create_payment.xml    |  59 ---------
 .../main/res/layout/fragment_process_payment.xml   |   2 +-
 app/src/main/res/menu/activity_main_drawer.xml     |   4 -
 app/src/main/res/menu/main.xml                     |   8 --
 app/src/main/res/navigation/nav_graph.xml          |  11 +-
 18 files changed, 248 insertions(+), 409 deletions(-)

diff --git a/app/src/main/java/net/taler/merchantpos/CreatePayment.kt 
b/app/src/main/java/net/taler/merchantpos/CreatePayment.kt
deleted file mode 100644
index 02a2ae7..0000000
--- a/app/src/main/java/net/taler/merchantpos/CreatePayment.kt
+++ /dev/null
@@ -1,131 +0,0 @@
-package net.taler.merchantpos
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.Button
-import android.widget.EditText
-import android.widget.TextView
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.activityViewModels
-import androidx.navigation.fragment.findNavController
-import com.android.volley.Request
-import com.android.volley.RequestQueue
-import com.android.volley.Response
-import com.android.volley.VolleyError
-import com.android.volley.toolbox.Volley
-import com.google.android.material.snackbar.Snackbar
-import net.taler.merchantpos.config.MerchantRequest
-import org.json.JSONObject
-
-
-/**
- * Fragment that allows the merchant to create a payment.
- */
-class CreatePayment : Fragment() {
-    private lateinit var queue: RequestQueue
-    private val model: MainViewModel by activityViewModels()
-
-    private var paused: Boolean = false
-
-
-    override fun onPause() {
-        super.onPause()
-        this.paused = true
-    }
-
-    override fun onResume() {
-        super.onResume()
-        this.paused = false
-
-        val textView = 
view!!.findViewById<TextView>(R.id.text_create_payment_amount_label)
-        textView.text = "Amount (${model.merchantConfig!!.currency})"
-    }
-
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-
-        queue = Volley.newRequestQueue(context)
-    }
-
-    private fun onRequestPayment() {
-        val amountValStr = 
activity!!.findViewById<EditText>(R.id.edit_payment_amount).text
-        val amount = "${model.merchantConfig!!.currency}:${amountValStr}"
-        model.activeAmount = amount
-        model.activeSubject = 
activity!!.findViewById<EditText>(R.id.edit_payment_subject).text
-
-        val order = JSONObject().also {
-            it.put("amount", amount)
-            it.put("summary", model.activeSubject!!)
-            it.put("fulfillment_url", "https://example.com";)
-            it.put("instance", "default")
-        }
-
-        val reqBody = JSONObject().also { it.put("order", order) }
-
-        val req = MerchantRequest(
-            Request.Method.POST,
-            model.merchantConfig!!,
-            "order",
-            null,
-            reqBody,
-            Response.Listener { onOrderCreated(it) },
-            Response.ErrorListener { onNetworkError(it) })
-
-        queue.add(req)
-    }
-
-    private fun onNetworkError(volleyError: VolleyError?) {
-        val mySnackbar = Snackbar.make(view!!, "Network Error", 
Snackbar.LENGTH_SHORT)
-        mySnackbar.show()
-    }
-
-    private fun onOrderCreated(orderResponse: JSONObject) {
-        val merchantConfig = model.merchantConfig!!
-        val orderId = orderResponse.getString("order_id")
-        val params = mapOf("order_id" to orderId, "instance" to 
merchantConfig.instance)
-        model.activeOrderId = orderId
-
-        val req =
-            MerchantRequest(Request.Method.GET,
-                model.merchantConfig!!,
-                "check-payment",
-                params,
-                null,
-                Response.Listener { onCheckPayment(it) },
-                Response.ErrorListener { onNetworkError(it) })
-        queue.add(req)
-    }
-
-    /**
-     * Called when the /check-payment response gave a result.
-     */
-    private fun onCheckPayment(checkPaymentResponse: JSONObject) {
-        if (paused) {
-            return
-        }
-        if (checkPaymentResponse.getBoolean("paid")) {
-            val mySnackbar = Snackbar.make(view!!, "Already paid?!", 
Snackbar.LENGTH_SHORT)
-            mySnackbar.show()
-            return
-        }
-        model.activeTalerPayUri = 
checkPaymentResponse.getString("taler_pay_uri")
-        
findNavController().navigate(R.id.action_createPayment_to_processPayment)
-    }
-
-    override fun onCreateView(
-        inflater: LayoutInflater, container: ViewGroup?,
-        savedInstanceState: Bundle?
-    ): View? {
-        // Inflate the layout for this fragment
-        val view = inflater.inflate(R.layout.fragment_create_payment, 
container, false)
-        val requestPaymentButton = 
view.findViewById<Button>(R.id.button_request_payment)
-        requestPaymentButton.setOnClickListener {
-            onRequestPayment()
-        }
-
-        return view
-    }
-
-}
diff --git a/app/src/main/java/net/taler/merchantpos/MainActivity.kt 
b/app/src/main/java/net/taler/merchantpos/MainActivity.kt
index 6d2e614..57968c3 100644
--- a/app/src/main/java/net/taler/merchantpos/MainActivity.kt
+++ b/app/src/main/java/net/taler/merchantpos/MainActivity.kt
@@ -5,7 +5,6 @@ import android.nfc.Tag
 import android.nfc.tech.IsoDep
 import android.os.Bundle
 import android.util.Log
-import android.view.Menu
 import android.view.MenuItem
 import androidx.activity.viewModels
 import androidx.appcompat.app.AppCompatActivity
@@ -158,7 +157,7 @@ class MainActivity : AppCompatActivity(), 
NavigationView.OnNavigationItemSelecte
 
         isoDep.transceive(apduSelectFile())
 
-        val contractUri: String? = model.activeTalerPayUri
+        val contractUri: String? = 
model.paymentManager.payment.value?.talerPayUri
 
         if (contractUri != null) {
             isoDep.transceive(apduPutTalerData(1, contractUri.toByteArray()))
@@ -267,7 +266,6 @@ class MainActivity : AppCompatActivity(), 
NavigationView.OnNavigationItemSelecte
         val appBarConfiguration = AppBarConfiguration(
                 setOf(
                     R.id.order,
-                    R.id.createPayment,
                     R.id.merchantSettings,
                     R.id.merchantHistory
                 ), drawerLayout
@@ -284,39 +282,17 @@ class MainActivity : AppCompatActivity(), 
NavigationView.OnNavigationItemSelecte
         }
     }
 
-    override fun onCreateOptionsMenu(menu: Menu): Boolean {
-        // Inflate the menu; this adds items to the action bar if it is 
present.
-        menuInflater.inflate(R.menu.main, menu)
-        return true
-    }
-
-    override fun onOptionsItemSelected(item: MenuItem): Boolean {
-        // Handle action bar item clicks here. The action bar will
-        // automatically handle clicks on the Home/Up button, so long
-        // as you specify a parent activity in AndroidManifest.xml.
-        return when (item.itemId) {
-            R.id.action_settings -> true
-            else -> super.onOptionsItemSelected(item)
-        }
-    }
-
     override fun onNavigationItemSelected(item: MenuItem): Boolean {
         // Handle navigation view item clicks here.
         val nav: NavController = findNavController(R.id.nav_host_fragment)
         when (item.itemId) {
-            R.id.nav_home -> nav.navigate(R.id.action_global_createPayment)
             R.id.nav_order -> nav.navigate(R.id.action_global_order)
-            R.id.nav_history -> {
-                nav.navigate(R.id.action_global_merchantHistory)
-            }
-            R.id.nav_settings -> {
-                nav.navigate(R.id.action_global_merchantSettings)
-            }
+            R.id.nav_history -> 
nav.navigate(R.id.action_global_merchantHistory)
+            R.id.nav_settings -> 
nav.navigate(R.id.action_global_merchantSettings)
         }
         val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
         drawerLayout.closeDrawer(GravityCompat.START)
         return true
     }
 
-
 }
diff --git a/app/src/main/java/net/taler/merchantpos/MainViewModel.kt 
b/app/src/main/java/net/taler/merchantpos/MainViewModel.kt
index c202f5f..716c1e7 100644
--- a/app/src/main/java/net/taler/merchantpos/MainViewModel.kt
+++ b/app/src/main/java/net/taler/merchantpos/MainViewModel.kt
@@ -1,7 +1,6 @@
 package net.taler.merchantpos
 
 import android.app.Application
-import android.text.Editable
 import androidx.lifecycle.AndroidViewModel
 import androidx.lifecycle.viewModelScope
 import com.android.volley.toolbox.Volley
@@ -10,6 +9,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
 import com.fasterxml.jackson.module.kotlin.KotlinModule
 import net.taler.merchantpos.config.ConfigManager
 import net.taler.merchantpos.order.OrderManager
+import net.taler.merchantpos.payment.PaymentManager
 
 class MainViewModel(app: Application) : AndroidViewModel(app) {
 
@@ -22,15 +22,12 @@ class MainViewModel(app: Application) : 
AndroidViewModel(app) {
     val configManager = ConfigManager(app, viewModelScope, mapper, 
queue).apply {
         addConfigurationReceiver(orderManager)
     }
+    val paymentManager = PaymentManager(configManager, queue)
 
+    @Deprecated("Use ConfigManager instead!", 
ReplaceWith("configManager.merchantConfig"))
     val merchantConfig
         get() = configManager.merchantConfig
 
-    var activeSubject: Editable? = null
-    var activeOrderId: String? = null
-    var activeAmount: String? = null
-    var activeTalerPayUri: String? = null
-
     init {
         if (configManager.merchantConfig == null) {
             configManager.fetchConfig(configManager.config, false)
@@ -41,10 +38,4 @@ class MainViewModel(app: Application) : 
AndroidViewModel(app) {
         queue.cancelAll { !it.isCanceled }
     }
 
-    fun activeAmountPretty(): String? {
-        val amount = activeAmount ?: return null
-        val components = amount.split(":")
-        return "${components[1]} ${components[0]}"
-    }
-
 }
diff --git a/app/src/main/java/net/taler/merchantpos/ProcessPayment.kt 
b/app/src/main/java/net/taler/merchantpos/ProcessPayment.kt
deleted file mode 100644
index d556b6f..0000000
--- a/app/src/main/java/net/taler/merchantpos/ProcessPayment.kt
+++ /dev/null
@@ -1,143 +0,0 @@
-package net.taler.merchantpos
-
-import android.graphics.Bitmap
-import android.graphics.Color
-import android.os.Bundle
-import android.os.Handler
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.Button
-import android.widget.ImageView
-import android.widget.TextView
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.activityViewModels
-import androidx.navigation.fragment.findNavController
-import com.android.volley.Request
-import com.android.volley.RequestQueue
-import com.android.volley.Response
-import com.android.volley.VolleyError
-import com.android.volley.toolbox.Volley
-import com.google.android.material.snackbar.Snackbar
-import com.google.zxing.BarcodeFormat
-import com.google.zxing.common.BitMatrix
-import com.google.zxing.qrcode.QRCodeWriter
-import net.taler.merchantpos.config.MerchantRequest
-import org.json.JSONObject
-
-
-// TODO: Rename parameter arguments, choose names that match
-// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
-private const val ARG_PARAM1 = "param1"
-private const val ARG_PARAM2 = "param2"
-
-/**
- * A simple [Fragment] subclass.
- *
- */
-class ProcessPayment : Fragment() {
-
-    private var paused: Boolean = true
-    private lateinit var queue: RequestQueue
-    private val model: MainViewModel by activityViewModels()
-
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-
-        queue = Volley.newRequestQueue(context)
-    }
-
-    private fun onCheckPayment(checkPaymentResponse: JSONObject) {
-        if (paused) {
-            return
-        }
-        //Log.v("taler-merchant", "got check payment result 
${checkPaymentResponse}")
-        if (checkPaymentResponse.getBoolean("paid")) {
-            queue.cancelAll { true }
-            
findNavController().navigate(R.id.action_processPayment_to_paymentSuccess)
-            return
-        }
-    }
-
-    private fun onNetworkError(volleyError: VolleyError?) {
-        val mySnackbar = Snackbar.make(view!!, "Network Error", 
Snackbar.LENGTH_SHORT)
-        mySnackbar.show()
-    }
-
-    private fun checkPaid() {
-        if (paused) {
-            return
-        }
-        //Log.v("taler-merchant", "checkig if payment happened")
-        val params = mapOf("order_id" to model.activeOrderId!!, "instance" to 
model.merchantConfig!!.instance)
-        var req =
-            MerchantRequest(Request.Method.GET,
-                model.merchantConfig!!,
-                "check-payment",
-                params,
-                null,
-                Response.Listener { onCheckPayment(it) },
-                Response.ErrorListener { onNetworkError(it) })
-        queue.add(req)
-        val handler = Handler()
-        handler.postDelayed({
-            checkPaid()
-        }, 500)
-
-    }
-
-    override fun onResume() {
-        this.paused = false
-        checkPaid()
-        super.onResume()
-    }
-
-    override fun onPause() {
-        this.paused = true
-        super.onPause()
-        queue.cancelAll { true }
-    }
-
-    override fun onCreateView(
-        inflater: LayoutInflater, container: ViewGroup?,
-        savedInstanceState: Bundle?
-    ): View? {
-        // Inflate the layout for this fragment
-        val view = inflater.inflate(R.layout.fragment_process_payment, 
container, false)
-        val img = view.findViewById<ImageView>(R.id.qrcode)
-        val talerPayUrl = model.activeTalerPayUri!!;
-        val myBitmap = makeQrCode(talerPayUrl)
-        img.setImageBitmap(myBitmap)
-        val cancelPaymentButton = 
view.findViewById<Button>(R.id.button_cancel_payment)
-        cancelPaymentButton.setOnClickListener {
-            onPaymentCancel()
-        }
-        val textViewAmount = view.findViewById<TextView>(R.id.text_view_amount)
-        textViewAmount.text = model.activeAmountPretty()
-        val textViewOrderId = 
view.findViewById<TextView>(R.id.text_view_order_reference)
-        textViewOrderId.text = "Order Reference: " + model.activeOrderId
-        return view
-    }
-
-    private fun onPaymentCancel() {
-        val navController = findNavController()
-        navController.popBackStack()
-
-        val mySnackbar = Snackbar.make(view!!, "Payment Canceled", 
Snackbar.LENGTH_SHORT)
-        mySnackbar.show()
-    }
-
-    fun makeQrCode(text: String): Bitmap {
-        val qrCodeWriter: QRCodeWriter = QRCodeWriter()
-        val bitMatrix: BitMatrix = qrCodeWriter.encode(text, 
BarcodeFormat.QR_CODE, 256, 256)
-        val height = bitMatrix.height
-        val width = bitMatrix.width
-        val bmp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
-        for (x in 0 until width) {
-            for (y in 0 until height) {
-                bmp.setPixel(x, y, if (bitMatrix.get(x, y)) Color.BLACK else 
Color.WHITE)
-            }
-        }
-        return bmp
-    }
-}
diff --git a/app/src/main/java/net/taler/merchantpos/config/ConfigManager.kt 
b/app/src/main/java/net/taler/merchantpos/config/ConfigManager.kt
index f6d1d30..563394f 100644
--- a/app/src/main/java/net/taler/merchantpos/config/ConfigManager.kt
+++ b/app/src/main/java/net/taler/merchantpos/config/ConfigManager.kt
@@ -113,7 +113,6 @@ class ConfigManager(
                 config = it
                 saveConfig(it)
             }
-            Log.e("TEST", "set currency to $currency")
             merchantConfig = merchantConfig!!.copy(currency = currency)
             mConfigUpdateResult.value = ConfigUpdateResult(currency)
         } else {
diff --git a/app/src/main/java/net/taler/merchantpos/order/Definitions.kt 
b/app/src/main/java/net/taler/merchantpos/order/Definitions.kt
index ec7f77e..d45e175 100644
--- a/app/src/main/java/net/taler/merchantpos/order/Definitions.kt
+++ b/app/src/main/java/net/taler/merchantpos/order/Definitions.kt
@@ -22,4 +22,6 @@ data class Product(
     val priceAsDouble by lazy { Amount.fromString(price).amount.toDouble() }
 }
 
+typealias Order = HashMap<Product, Int>
+
 typealias OrderLine = Pair<Product, Int>
diff --git a/app/src/main/java/net/taler/merchantpos/order/OrderFragment.kt 
b/app/src/main/java/net/taler/merchantpos/order/OrderFragment.kt
index 936caa9..f4c5a15 100644
--- a/app/src/main/java/net/taler/merchantpos/order/OrderFragment.kt
+++ b/app/src/main/java/net/taler/merchantpos/order/OrderFragment.kt
@@ -19,6 +19,7 @@ class OrderFragment : Fragment() {
 
     private val viewModel: MainViewModel by activityViewModels()
     private val orderManager by lazy { viewModel.orderManager }
+    private val paymentManager by lazy { viewModel.paymentManager }
 
     override fun onCreateView(
         inflater: LayoutInflater,
@@ -47,6 +48,11 @@ class OrderFragment : Fragment() {
         reconfigureButton.setOnClickListener { 
nav.navigate(R.id.action_global_merchantSettings) }
         historyButton.setOnClickListener { 
nav.navigate(R.id.action_global_merchantHistory) }
         logoutButton.setOnClickListener { 
nav.navigate(R.id.action_global_merchantSettings) }
+        completeButton.setOnClickListener {
+            val order = orderManager.order.value ?: return@setOnClickListener
+            paymentManager.createPayment(order)
+            nav.navigate(R.id.action_createPayment_to_processPayment)
+        }
     }
 
 }
diff --git a/app/src/main/java/net/taler/merchantpos/order/OrderManager.kt 
b/app/src/main/java/net/taler/merchantpos/order/OrderManager.kt
index 56dd95e..5d781a1 100644
--- a/app/src/main/java/net/taler/merchantpos/order/OrderManager.kt
+++ b/app/src/main/java/net/taler/merchantpos/order/OrderManager.kt
@@ -21,9 +21,9 @@ class OrderManager(private val mapper: ObjectMapper) : 
ConfigurationReceiver {
 
     private val productsByCategory = HashMap<Category, ArrayList<Product>>()
 
-    private val mOrder = MutableLiveData<HashMap<Product, Int>>()
-    internal val order: LiveData<HashMap<Product, Int>> = mOrder
-    internal val orderTotal: LiveData<Double> = map(mOrder) { map -> 
getTotal(map) }
+    private val mOrder = MutableLiveData<Order>()
+    internal val order: LiveData<Order> = mOrder
+    internal val orderTotal: LiveData<Double> = map(mOrder) { it.getTotal() }
 
     private val mProducts = MutableLiveData<List<Product>>()
     internal val products: LiveData<List<Product>> = mProducts
@@ -31,7 +31,7 @@ class OrderManager(private val mapper: ObjectMapper) : 
ConfigurationReceiver {
     private val mCategories = MutableLiveData<List<Category>>()
     internal val categories: LiveData<List<Category>> = mCategories
 
-    private var undoOrder: HashMap<Product, Int>? = null
+    private var undoOrder: Order? = null
     private val mRestartState = MutableLiveData<RestartState>().apply { value 
= DISABLED }
     internal val restartState: LiveData<RestartState> = mRestartState
 
@@ -114,13 +114,17 @@ class OrderManager(private val mapper: ObjectMapper) : 
ConfigurationReceiver {
         }
     }
 
-    private fun getTotal(map: HashMap<Product, Int>): Double {
-        var total = 0.0
-        map.forEach {
-            val price = it.key.priceAsDouble
-            total += price * it.value
-        }
-        return total
+}
+
+fun Order.getTotal(): Double {
+    var total = 0.0
+    forEach {
+        val price = it.key.priceAsDouble
+        total += price * it.value
     }
+    return total
+}
 
+fun Order.getTotalAsString(): String {
+    return String.format("%.2f", getTotal())
 }
diff --git a/app/src/main/java/net/taler/merchantpos/payment/Payment.kt 
b/app/src/main/java/net/taler/merchantpos/payment/Payment.kt
new file mode 100644
index 0000000..b82c8c0
--- /dev/null
+++ b/app/src/main/java/net/taler/merchantpos/payment/Payment.kt
@@ -0,0 +1,13 @@
+package net.taler.merchantpos.payment
+
+import net.taler.merchantpos.order.Order
+
+data class Payment(
+    val order: Order,
+    val summary: String,
+    val currency: String,
+    val orderId: String? = null,
+    val talerPayUri: String? = null,
+    val paid: Boolean = false,
+    val error: Boolean = false
+)
diff --git a/app/src/main/java/net/taler/merchantpos/payment/PaymentManager.kt 
b/app/src/main/java/net/taler/merchantpos/payment/PaymentManager.kt
new file mode 100644
index 0000000..5f8935e
--- /dev/null
+++ b/app/src/main/java/net/taler/merchantpos/payment/PaymentManager.kt
@@ -0,0 +1,113 @@
+package net.taler.merchantpos.payment
+
+import android.os.CountDownTimer
+import android.util.Log
+import androidx.annotation.UiThread
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.android.volley.Request.Method.GET
+import com.android.volley.Request.Method.POST
+import com.android.volley.RequestQueue
+import com.android.volley.Response.ErrorListener
+import com.android.volley.Response.Listener
+import com.android.volley.VolleyError
+import net.taler.merchantpos.config.ConfigManager
+import net.taler.merchantpos.config.MerchantRequest
+import net.taler.merchantpos.order.Order
+import net.taler.merchantpos.order.getTotalAsString
+import org.json.JSONObject
+import java.util.concurrent.TimeUnit.MINUTES
+import java.util.concurrent.TimeUnit.SECONDS
+
+private val TIMEOUT = MINUTES.toMillis(2)
+private val CHECK_INTERVAL = SECONDS.toMillis(1)
+
+class PaymentManager(
+    private val configManager: ConfigManager,
+    private val queue: RequestQueue
+) {
+
+    private val mPayment = MutableLiveData<Payment>()
+    var payment: LiveData<Payment> = mPayment
+
+    private val checkTimer = object : CountDownTimer(TIMEOUT, CHECK_INTERVAL) {
+        override fun onTick(millisUntilFinished: Long) {
+            val orderId = payment.value?.orderId
+            if (orderId == null) cancel()
+            else checkPayment(orderId)
+        }
+
+        override fun onFinish() {
+            payment.value?.copy(error = true)?.let { mPayment.value = it }
+        }
+    }
+
+    @UiThread
+    fun createPayment(order: Order) {
+        val merchantConfig = configManager.merchantConfig!!
+
+        val currency = merchantConfig.currency!!
+        val orderTotal = order.getTotalAsString()
+        val amount = "$currency:$orderTotal"
+        val summary = order.map {
+            "${it.value} x ${it.key.description}"
+        }.joinToString()
+
+        mPayment.value = Payment(order, summary, currency)
+
+        val body = JSONObject().apply {
+            put("order", JSONObject().apply {
+                put("amount", amount)
+                put("summary", summary)
+                // fulfillment_url needs to be unique per order
+                put("fulfillment_url", 
"https://example.com/${order.hashCode()}")
+                put("instance", "default")
+            })
+        }
+
+        val req = MerchantRequest(POST, merchantConfig, "order", null, body,
+            Listener { onOrderCreated(it) },
+            ErrorListener { onNetworkError(it) }
+        )
+        queue.add(req)
+    }
+
+    private fun onOrderCreated(orderResponse: JSONObject) {
+        val orderId = orderResponse.getString("order_id")
+        mPayment.value = mPayment.value!!.copy(orderId = orderId)
+        checkTimer.start()
+    }
+
+    private fun checkPayment(orderId: String) {
+        val merchantConfig = configManager.merchantConfig!!
+        val params = mapOf(
+            "order_id" to orderId,
+            "instance" to merchantConfig.instance
+        )
+
+        val req = MerchantRequest(GET, merchantConfig, "check-payment", 
params, null,
+            Listener { onPaymentChecked(it) },
+            ErrorListener { onNetworkError(it) })
+        queue.add(req)
+    }
+
+    /**
+     * Called when the /check-payment response gave a result.
+     */
+    private fun onPaymentChecked(checkPaymentResponse: JSONObject) {
+        if (checkPaymentResponse.getBoolean("paid")) {
+            mPayment.value = mPayment.value!!.copy(paid = true)
+            checkTimer.cancel()
+        } else {
+            val talerPayUri = checkPaymentResponse.getString("taler_pay_uri")
+            mPayment.value = mPayment.value!!.copy(talerPayUri = talerPayUri)
+        }
+    }
+
+    private fun onNetworkError(volleyError: VolleyError) {
+        Log.e(PaymentManager::class.java.simpleName, volleyError.toString())
+        mPayment.value = mPayment.value!!.copy(error = true)
+        checkTimer.cancel()
+    }
+
+}
diff --git a/app/src/main/java/net/taler/merchantpos/PaymentSuccess.kt 
b/app/src/main/java/net/taler/merchantpos/payment/PaymentSuccess.kt
similarity index 91%
rename from app/src/main/java/net/taler/merchantpos/PaymentSuccess.kt
rename to app/src/main/java/net/taler/merchantpos/payment/PaymentSuccess.kt
index 20b6ed1..c62abbc 100644
--- a/app/src/main/java/net/taler/merchantpos/PaymentSuccess.kt
+++ b/app/src/main/java/net/taler/merchantpos/payment/PaymentSuccess.kt
@@ -1,13 +1,14 @@
-package net.taler.merchantpos
+package net.taler.merchantpos.payment
 
 
 import android.os.Bundle
-import androidx.fragment.app.Fragment
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import android.widget.Button
+import androidx.fragment.app.Fragment
 import androidx.navigation.findNavController
+import net.taler.merchantpos.R
 
 /**
  * A simple [Fragment] subclass.
diff --git 
a/app/src/main/java/net/taler/merchantpos/payment/ProcessPaymentFragment.kt 
b/app/src/main/java/net/taler/merchantpos/payment/ProcessPaymentFragment.kt
new file mode 100644
index 0000000..67a913f
--- /dev/null
+++ b/app/src/main/java/net/taler/merchantpos/payment/ProcessPaymentFragment.kt
@@ -0,0 +1,85 @@
+package net.taler.merchantpos.payment
+
+import android.graphics.Bitmap
+import android.graphics.Bitmap.Config.RGB_565
+import android.graphics.Color.BLACK
+import android.graphics.Color.WHITE
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.Observer
+import androidx.navigation.fragment.findNavController
+import com.google.android.material.snackbar.Snackbar
+import com.google.android.material.snackbar.Snackbar.LENGTH_SHORT
+import com.google.zxing.BarcodeFormat.QR_CODE
+import com.google.zxing.common.BitMatrix
+import com.google.zxing.qrcode.QRCodeWriter
+import kotlinx.android.synthetic.main.fragment_process_payment.*
+import net.taler.merchantpos.MainViewModel
+import net.taler.merchantpos.R
+import net.taler.merchantpos.order.getTotalAsString
+
+class ProcessPaymentFragment : Fragment() {
+
+    private val model: MainViewModel by activityViewModels()
+    private val paymentManager by lazy { model.paymentManager }
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.fragment_process_payment, container, 
false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        paymentManager.payment.observe(viewLifecycleOwner, Observer { payment 
->
+            onPaymentStateChanged(payment)
+        })
+        button_cancel_payment.setOnClickListener {
+            onPaymentCancel()
+        }
+    }
+
+    private fun onPaymentStateChanged(payment: Payment) {
+        if (payment.error) {
+            Snackbar.make(view!!, "Network Error", LENGTH_SHORT).show()
+            return
+        }
+        if (payment.paid) {
+            
findNavController().navigate(R.id.action_processPayment_to_paymentSuccess)
+            return
+        }
+        text_view_amount.text = "${payment.order.getTotalAsString()} 
${payment.currency}"
+        text_view_order_reference.text = "Order Reference: ${payment.orderId}"
+        payment.talerPayUri?.let {
+            val myBitmap = makeQrCode(it)
+            qrcode.setImageBitmap(myBitmap)
+        }
+    }
+
+    private fun onPaymentCancel() {
+        val navController = findNavController()
+        navController.popBackStack()
+
+        val mySnackbar = Snackbar.make(view!!, "Payment Canceled", 
LENGTH_SHORT)
+        mySnackbar.show()
+    }
+
+    private fun makeQrCode(text: String): Bitmap {
+        val qrCodeWriter = QRCodeWriter()
+        val bitMatrix: BitMatrix = qrCodeWriter.encode(text, QR_CODE, 256, 256)
+        val height = bitMatrix.height
+        val width = bitMatrix.width
+        val bmp = Bitmap.createBitmap(width, height, RGB_565)
+        for (x in 0 until width) {
+            for (y in 0 until height) {
+                bmp.setPixel(x, y, if (bitMatrix.get(x, y)) BLACK else WHITE)
+            }
+        }
+        return bmp
+    }
+
+}
diff --git a/app/src/main/res/layout/activity_main.xml 
b/app/src/main/res/layout/activity_main.xml
index ac9a123..f67c32c 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -20,7 +20,6 @@
             android:layout_height="match_parent"
             android:layout_gravity="start"
             android:fitsSystemWindows="true"
-            app:headerLayout="@layout/nav_header_main"
-            app:menu="@menu/activity_main_drawer"/>
+            app:headerLayout="@layout/nav_header_main" />
 
 </androidx.drawerlayout.widget.DrawerLayout>
diff --git a/app/src/main/res/layout/fragment_create_payment.xml 
b/app/src/main/res/layout/fragment_create_payment.xml
deleted file mode 100644
index c3f2e5f..0000000
--- a/app/src/main/res/layout/fragment_create_payment.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android";
-             xmlns:app="http://schemas.android.com/apk/res-auto"; 
xmlns:tools="http://schemas.android.com/tools";
-             android:layout_width="match_parent"
-             android:layout_height="match_parent"
-             tools:context=".CreatePayment">
-
-    <LinearLayout
-            android:orientation="vertical"
-            android:paddingLeft="16dp"
-            android:paddingRight="16dp"
-            android:paddingBottom="16dp"
-            android:paddingTop="16dp"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent">
-
-        <Space
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_weight="0.5"/>
-
-        <TextView
-                android:text="Payment Subject"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content" 
android:id="@+id/textView5"/>
-
-        <EditText
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:inputType="textPersonName"
-                android:text="Demo Payment"
-                android:ems="10"
-                android:layout_gravity="top"
-                android:id="@+id/edit_payment_subject"/>
-        <TextView
-                android:text="Amount (TESTKUDOS)"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:id="@+id/text_create_payment_amount_label"/>
-        <EditText
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:inputType="numberDecimal"
-                android:ems="10"
-                android:id="@+id/edit_payment_amount" android:layout_weight="0"
-                android:text="1"/>
-        <Space
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"/>
-
-        <Button
-                android:text="Request Payment"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:id="@+id/button_request_payment"
-                android:layout_gravity="right"/>
-    </LinearLayout>
-</FrameLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_process_payment.xml 
b/app/src/main/res/layout/fragment_process_payment.xml
index 3f1764e..53c3bc3 100644
--- a/app/src/main/res/layout/fragment_process_payment.xml
+++ b/app/src/main/res/layout/fragment_process_payment.xml
@@ -4,7 +4,7 @@
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:layout_margin="15dp"
-             tools:context=".ProcessPayment" android:id="@+id/frameLayout2">
+             tools:context=".payment.ProcessPaymentFragment" 
android:id="@+id/frameLayout2">
 
     <androidx.constraintlayout.widget.ConstraintLayout
             android:layout_width="match_parent"
diff --git a/app/src/main/res/menu/activity_main_drawer.xml 
b/app/src/main/res/menu/activity_main_drawer.xml
index 7a70824..06f9e5c 100644
--- a/app/src/main/res/menu/activity_main_drawer.xml
+++ b/app/src/main/res/menu/activity_main_drawer.xml
@@ -4,10 +4,6 @@
         tools:showIn="navigation_view">
 
     <group android:checkableBehavior="single">
-        <item
-                android:id="@+id/nav_home"
-                android:icon="@drawable/ic_move_money_24dp"
-                android:title="@string/menu_home" />
         <item
                 android:id="@+id/nav_order"
                 android:icon="@drawable/ic_move_money_24dp"
diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml
deleted file mode 100644
index d579f6f..0000000
--- a/app/src/main/res/menu/main.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android";
-      xmlns:app="http://schemas.android.com/apk/res-auto";>
-    <item android:id="@+id/action_settings"
-          android:title="@string/action_settings"
-          android:orderInCategory="100"
-          app:showAsAction="never"/>
-</menu>
diff --git a/app/src/main/res/navigation/nav_graph.xml 
b/app/src/main/res/navigation/nav_graph.xml
index 4eaadda..a1c0d8d 100644
--- a/app/src/main/res/navigation/nav_graph.xml
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -15,28 +15,23 @@
                 app:destination="@id/processPayment" />
     </fragment>
 
-    <fragment android:id="@+id/createPayment" 
android:name="net.taler.merchantpos.CreatePayment"
-              android:label="Request Payment" 
tools:layout="@layout/fragment_create_payment">
-        <action android:id="@+id/action_createPayment_to_processPayment" 
app:destination="@id/processPayment"/>
-    </fragment>
-    <fragment android:id="@+id/processPayment" 
android:name="net.taler.merchantpos.ProcessPayment"
+    <fragment android:id="@+id/processPayment" 
android:name="net.taler.merchantpos.payment.ProcessPaymentFragment"
               android:label="Payment Prompt" 
tools:layout="@layout/fragment_process_payment">
         <action
                 android:id="@+id/action_processPayment_to_paymentSuccess"
                 app:destination="@id/paymentSuccess"
-                app:popUpTo="@id/createPayment"/>
+                app:popUpTo="@id/order"/>
     </fragment>
     <fragment android:id="@+id/merchantHistory" 
android:name="net.taler.merchantpos.MerchantHistory"
               android:label="Payment History" 
tools:layout="@layout/fragment_merchant_history"/>
     <action android:id="@+id/action_global_merchantHistory" 
app:destination="@id/merchantHistory"/>
-    <action android:id="@+id/action_global_createPayment" 
app:destination="@id/createPayment"/>
     <action android:id="@+id/action_global_order" app:destination="@id/order"/>
     <fragment android:id="@+id/merchantSettings" 
android:name="net.taler.merchantpos.config.MerchantConfigFragment"
               android:label="Merchant Settings" 
tools:layout="@layout/fragment_merchant_settings"/>
     <action android:id="@+id/action_global_merchantSettings" 
app:destination="@id/merchantSettings"/>
     <fragment
             android:id="@+id/paymentSuccess"
-            android:name="net.taler.merchantpos.PaymentSuccess"
+            android:name="net.taler.merchantpos.payment.PaymentSuccess"
             android:label="Payment Received"
             tools:layout="@layout/fragment_payment_success" />
 </navigation>
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]