[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.
- [taler-merchant-terminal-android] branch master updated (f463d1b -> 39af919), gnunet, 2020/02/21
- [taler-merchant-terminal-android] 03/19: Fix crash when loading history, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 01/19: Upgrade libraries to latest stable versions, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 05/19: Allow user to undo restarting the order, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 07/19: Add ordered products to order's contract terms, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 08/19: Use actual taler icon for the app, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 09/19: Factor out NFC code from MainActivity, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 06/19: Create payments directly from the order,
gnunet <=
- [taler-merchant-terminal-android] 04/19: Fetch merchant config from central configuration JSON, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 02/19: Add screen to process an order, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 18/19: Don't talk about NFC if it is not supported, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 14/19: Use product categories for order summary, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 11/19: Allow user to decide if they want to save password, add FORGET option, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 13/19: Make NFC and QR code re-useable in another app, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 15/19: Introduce different product classes for re-use in other taler apps, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 17/19: Make order sorting deterministic, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 12/19: Fix invalid product configuration, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 19/19: Check for duplicate product IDs, gnunet, 2020/02/21