gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant-terminal-android] 03/03: Add refund button to history it


From: gnunet
Subject: [taler-merchant-terminal-android] 03/03: Add refund button to history items and allow to refund orders
Date: Tue, 17 Mar 2020 16:30:47 +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 7eebd0754d16eccadeb3d1cb53c1cebffda65d07
Author: Torsten Grote <address@hidden>
AuthorDate: Mon Mar 16 15:53:58 2020 -0300

    Add refund button to history items and allow to refund orders
    
    (still hidden in UI because API incomplete/broken)
---
 .../java/net/taler/merchantpos/MainViewModel.kt    |   2 +
 app/src/main/java/net/taler/merchantpos/Utils.kt   |   4 +
 .../taler/merchantpos/history/HistoryManager.kt    |   6 +-
 .../merchantpos/history/MerchantHistoryFragment.kt |  26 ++++-
 .../taler/merchantpos/history/RefundFragment.kt    |  99 +++++++++++++++++
 .../net/taler/merchantpos/history/RefundManager.kt | 111 +++++++++++++++++++
 .../taler/merchantpos/history/RefundUriFragment.kt |  65 +++++++++++
 app/src/main/res/drawable/ic_cash_refund.xml       |   9 ++
 app/src/main/res/layout/fragment_refund.xml        | 122 +++++++++++++++++++++
 app/src/main/res/layout/fragment_refund_uri.xml    |  93 ++++++++++++++++
 app/src/main/res/layout/list_item_history.xml      |  21 +++-
 app/src/main/res/navigation/nav_graph.xml          |  25 ++++-
 app/src/main/res/values/strings.xml                |  12 ++
 13 files changed, 580 insertions(+), 15 deletions(-)

diff --git a/app/src/main/java/net/taler/merchantpos/MainViewModel.kt 
b/app/src/main/java/net/taler/merchantpos/MainViewModel.kt
index 560ca59..3fe472d 100644
--- a/app/src/main/java/net/taler/merchantpos/MainViewModel.kt
+++ b/app/src/main/java/net/taler/merchantpos/MainViewModel.kt
@@ -25,6 +25,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
 import com.fasterxml.jackson.module.kotlin.KotlinModule
 import net.taler.merchantpos.config.ConfigManager
 import net.taler.merchantpos.history.HistoryManager
+import net.taler.merchantpos.history.RefundManager
 import net.taler.merchantpos.order.OrderManager
 import net.taler.merchantpos.payment.PaymentManager
 
@@ -41,6 +42,7 @@ class MainViewModel(app: Application) : AndroidViewModel(app) 
{
     }
     val paymentManager = PaymentManager(configManager, queue, mapper)
     val historyManager = HistoryManager(configManager, queue, mapper)
+    val refundManager = RefundManager(configManager, queue)
 
     override fun onCleared() {
         queue.cancelAll { !it.isCanceled }
diff --git a/app/src/main/java/net/taler/merchantpos/Utils.kt 
b/app/src/main/java/net/taler/merchantpos/Utils.kt
index 507d142..a0c30d6 100644
--- a/app/src/main/java/net/taler/merchantpos/Utils.kt
+++ b/app/src/main/java/net/taler/merchantpos/Utils.kt
@@ -30,11 +30,13 @@ import android.view.View
 import android.view.View.INVISIBLE
 import android.view.View.VISIBLE
 import androidx.annotation.StringRes
+import androidx.fragment.app.Fragment
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MediatorLiveData
 import androidx.lifecycle.Observer
 import androidx.navigation.NavController
 import androidx.navigation.NavDirections
+import androidx.navigation.fragment.findNavController
 import 
com.google.android.material.snackbar.BaseTransientBottomBar.ANIMATION_MODE_FADE
 import com.google.android.material.snackbar.BaseTransientBottomBar.Duration
 import com.google.android.material.snackbar.Snackbar.make
@@ -107,6 +109,8 @@ fun topSnackbar(view: View, @StringRes resId: Int, 
@Duration duration: Int) {
 
 fun NavDirections.navigate(nav: NavController) = nav.navigate(this)
 
+fun Fragment.navigate(directions: NavDirections) = 
findNavController().navigate(directions)
+
 fun Long.toRelativeTime(context: Context): CharSequence {
     val now = System.currentTimeMillis()
     return if (now - this > DAY_IN_MILLIS * 2) {
diff --git a/app/src/main/java/net/taler/merchantpos/history/HistoryManager.kt 
b/app/src/main/java/net/taler/merchantpos/history/HistoryManager.kt
index 1459876..594e7cc 100644
--- a/app/src/main/java/net/taler/merchantpos/history/HistoryManager.kt
+++ b/app/src/main/java/net/taler/merchantpos/history/HistoryManager.kt
@@ -16,10 +16,12 @@
 
 package net.taler.merchantpos.history
 
+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
@@ -79,7 +81,7 @@ class HistoryManager(
         val params = mapOf("instance" to merchantConfig.instance)
         val req = MerchantRequest(GET, merchantConfig, "history", params, null,
             Listener { onHistoryResponse(it) },
-            ErrorListener { onNetworkError() })
+            ErrorListener { onHistoryError() })
         queue.add(req)
     }
 
@@ -96,7 +98,7 @@ class HistoryManager(
     }
 
     @UiThread
-    private fun onNetworkError() {
+    private fun onHistoryError() {
         mIsLoading.value = false
         mItems.value = HistoryResult.Error
     }
diff --git 
a/app/src/main/java/net/taler/merchantpos/history/MerchantHistoryFragment.kt 
b/app/src/main/java/net/taler/merchantpos/history/MerchantHistoryFragment.kt
index 5299f28..0c53f71 100644
--- a/app/src/main/java/net/taler/merchantpos/history/MerchantHistoryFragment.kt
+++ b/app/src/main/java/net/taler/merchantpos/history/MerchantHistoryFragment.kt
@@ -22,11 +22,11 @@ import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.widget.ImageButton
 import android.widget.TextView
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
 import androidx.lifecycle.Observer
-import androidx.navigation.fragment.findNavController
 import androidx.recyclerview.widget.DividerItemDecoration
 import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL
 import androidx.recyclerview.widget.LinearLayoutManager
@@ -40,14 +40,19 @@ import net.taler.merchantpos.R
 import net.taler.merchantpos.exhaustive
 import net.taler.merchantpos.history.HistoryItemAdapter.HistoryItemViewHolder
 import 
net.taler.merchantpos.history.MerchantHistoryFragmentDirections.Companion.actionGlobalMerchantSettings
+import 
net.taler.merchantpos.history.MerchantHistoryFragmentDirections.Companion.actionNavHistoryToRefundFragment
 import net.taler.merchantpos.navigate
 import net.taler.merchantpos.toRelativeTime
 import java.util.*
 
+private interface RefundClickListener {
+    fun onRefundClicked(item: HistoryItem)
+}
+
 /**
  * Fragment to display the merchant's payment history, received from the 
backend.
  */
-class MerchantHistoryFragment : Fragment() {
+class MerchantHistoryFragment : Fragment(), RefundClickListener {
 
     companion object {
         const val TAG = "taler-merchant"
@@ -55,8 +60,9 @@ class MerchantHistoryFragment : Fragment() {
 
     private val model: MainViewModel by activityViewModels()
     private val historyManager by lazy { model.historyManager }
+    private val refundManager by lazy { model.refundManager }
 
-    private val historyListAdapter = HistoryItemAdapter()
+    private val historyListAdapter = HistoryItemAdapter(this)
 
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
@@ -91,7 +97,7 @@ class MerchantHistoryFragment : Fragment() {
     override fun onStart() {
         super.onStart()
         if (model.configManager.merchantConfig?.instance == null) {
-            actionGlobalMerchantSettings().navigate(findNavController())
+            navigate(actionGlobalMerchantSettings())
         } else {
             historyManager.fetchHistory()
         }
@@ -101,9 +107,15 @@ class MerchantHistoryFragment : Fragment() {
         Snackbar.make(view!!, R.string.error_network, LENGTH_SHORT).show()
     }
 
+    override fun onRefundClicked(item: HistoryItem) {
+        refundManager.startRefund(item)
+        navigate(actionNavHistoryToRefundFragment())
+    }
+
 }
 
-internal class HistoryItemAdapter : Adapter<HistoryItemViewHolder>() {
+private class HistoryItemAdapter(private val listener: RefundClickListener) :
+    Adapter<HistoryItemViewHolder>() {
 
     private val items = ArrayList<HistoryItem>()
 
@@ -125,12 +137,13 @@ internal class HistoryItemAdapter : 
Adapter<HistoryItemViewHolder>() {
         this.notifyDataSetChanged()
     }
 
-    internal class HistoryItemViewHolder(private val v: View) : ViewHolder(v) {
+    private inner class HistoryItemViewHolder(private val v: View) : 
ViewHolder(v) {
 
         private val orderSummaryView: TextView = 
v.findViewById(R.id.orderSummaryView)
         private val orderAmountView: TextView = 
v.findViewById(R.id.orderAmountView)
         private val orderTimeView: TextView = 
v.findViewById(R.id.orderTimeView)
         private val orderIdView: TextView = v.findViewById(R.id.orderIdView)
+        private val refundButton: ImageButton = 
v.findViewById(R.id.refundButton)
 
         fun bind(item: HistoryItem) {
             orderSummaryView.text = item.summary
@@ -139,6 +152,7 @@ internal class HistoryItemAdapter : 
Adapter<HistoryItemViewHolder>() {
             orderAmountView.text = "${amount.amount} ${amount.currency}"
             orderIdView.text = v.context.getString(R.string.history_ref_no, 
item.orderId)
             orderTimeView.text = item.time.toRelativeTime(v.context)
+            refundButton.setOnClickListener { listener.onRefundClicked(item) }
         }
 
     }
diff --git a/app/src/main/java/net/taler/merchantpos/history/RefundFragment.kt 
b/app/src/main/java/net/taler/merchantpos/history/RefundFragment.kt
new file mode 100644
index 0000000..1797cea
--- /dev/null
+++ b/app/src/main/java/net/taler/merchantpos/history/RefundFragment.kt
@@ -0,0 +1,99 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+ * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.merchantpos.history
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.StringRes
+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.BaseTransientBottomBar.LENGTH_LONG
+import com.google.android.material.snackbar.Snackbar
+import kotlinx.android.synthetic.main.fragment_refund.*
+import net.taler.merchantpos.MainViewModel
+import net.taler.merchantpos.R
+import net.taler.merchantpos.fadeIn
+import net.taler.merchantpos.fadeOut
+import 
net.taler.merchantpos.history.RefundFragmentDirections.Companion.actionRefundFragmentToRefundUriFragment
+import net.taler.merchantpos.history.RefundResult.Error
+import net.taler.merchantpos.history.RefundResult.PastDeadline
+import net.taler.merchantpos.history.RefundResult.Success
+import net.taler.merchantpos.navigate
+
+class RefundFragment : Fragment() {
+
+    private val model: MainViewModel by activityViewModels()
+    private val refundManager by lazy { model.refundManager }
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.fragment_refund, container, false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        val item = refundManager.toBeRefunded ?: throw IllegalStateException()
+        amountInputView.setText(item.amount.amount)
+        currencyView.text = item.amount.currency
+        abortButton.setOnClickListener { findNavController().navigateUp() }
+        refundButton.setOnClickListener { onRefundButtonClicked(item) }
+
+        refundManager.refundResult.observe(viewLifecycleOwner, Observer { 
result ->
+            onRefundResultChanged(result)
+        })
+    }
+
+    private fun onRefundButtonClicked(item: HistoryItem) {
+        val inputAmount = amountInputView.text.toString().toDouble()
+        if (inputAmount > item.amount.amount.toDouble()) {
+            amountView.error = getString(R.string.refund_error_max_amount, 
item.amount.amount)
+            return
+        }
+        if (inputAmount <= 0.0) {
+            amountView.error = getString(R.string.refund_error_zero)
+            return
+        }
+        amountView.error = null
+        refundButton.fadeOut()
+        progressBar.fadeIn()
+        refundManager.refund(item, inputAmount, 
reasonInputView.text.toString())
+    }
+
+    private fun onRefundResultChanged(result: RefundResult?): Any = when 
(result) {
+        Error -> onError(R.string.refund_error_backend)
+        PastDeadline -> onError(R.string.refund_error_deadline)
+        is Success -> {
+            progressBar.fadeOut()
+            refundButton.fadeIn()
+            navigate(actionRefundFragmentToRefundUriFragment())
+        }
+        null -> { // no-op
+        }
+    }
+
+    private fun onError(@StringRes res: Int) {
+        Snackbar.make(view!!, res, LENGTH_LONG).show()
+        progressBar.fadeOut()
+        refundButton.fadeIn()
+    }
+
+}
diff --git a/app/src/main/java/net/taler/merchantpos/history/RefundManager.kt 
b/app/src/main/java/net/taler/merchantpos/history/RefundManager.kt
new file mode 100644
index 0000000..270b3b8
--- /dev/null
+++ b/app/src/main/java/net/taler/merchantpos/history/RefundManager.kt
@@ -0,0 +1,111 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+ * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.merchantpos.history
+
+import android.util.Log
+import androidx.annotation.UiThread
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+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 net.taler.merchantpos.config.ConfigManager
+import net.taler.merchantpos.config.MerchantRequest
+import org.json.JSONObject
+
+sealed class RefundResult {
+    object Error : RefundResult()
+    object PastDeadline : RefundResult()
+    class Success(
+        val refundUri: String,
+        val item: HistoryItem,
+        val amount: Double,
+        val reason: String
+    ) : RefundResult()
+}
+
+class RefundManager(
+    private val configManager: ConfigManager,
+    private val queue: RequestQueue
+) {
+
+    var toBeRefunded: HistoryItem? = null
+        private set
+
+    private val mRefundResult = MutableLiveData<RefundResult>()
+    internal val refundResult: LiveData<RefundResult> = mRefundResult
+
+    @UiThread
+    internal fun startRefund(item: HistoryItem) {
+        toBeRefunded = item
+        mRefundResult.value = null
+    }
+
+    @UiThread
+    internal fun refund(item: HistoryItem, amount: Double, reason: String) {
+        val merchantConfig = configManager.merchantConfig!!
+        val refundRequest = mapOf(
+            "order_id" to item.orderId,
+            "refund" to "${item.amount.currency}:$amount",
+            "reason" to reason
+        )
+        val body = JSONObject(refundRequest)
+        val req = MerchantRequest(POST, merchantConfig, "refund", null, body,
+            Listener { onRefundResponse(it, item, amount, reason) },
+            ErrorListener { onRefundError() }
+        )
+        queue.add(req)
+    }
+
+    @UiThread
+    private fun onRefundResponse(
+        json: JSONObject,
+        item: HistoryItem,
+        amount: Double,
+        reason: String
+    ) {
+        if (!json.has("contract_terms")) {
+            Log.e("TEST", "json: $json")
+            onRefundError()
+            return
+        }
+
+        val contractTerms = json.getJSONObject("contract_terms")
+        val refundDeadline = if (contractTerms.has("refund_deadline")) {
+            contractTerms.getJSONObject("refund_deadline").getLong("t_ms")
+        } else null
+        val autoRefund = contractTerms.has("auto_refund")
+        val refundUri = json.getString("taler_refund_uri")
+
+        Log.e("TEST", "refundDeadline: $refundDeadline")
+        if (refundDeadline != null) Log.e(
+            "TEST",
+            "refundDeadline passed: ${System.currentTimeMillis() > 
refundDeadline}"
+        )
+        Log.e("TEST", "autoRefund: $autoRefund")
+        Log.e("TEST", "refundUri: $refundUri")
+
+        mRefundResult.value = RefundResult.Success(refundUri, item, amount, 
reason)
+    }
+
+    @UiThread
+    private fun onRefundError() {
+        mRefundResult.value = RefundResult.Error
+    }
+
+}
diff --git 
a/app/src/main/java/net/taler/merchantpos/history/RefundUriFragment.kt 
b/app/src/main/java/net/taler/merchantpos/history/RefundUriFragment.kt
new file mode 100644
index 0000000..f2bd569
--- /dev/null
+++ b/app/src/main/java/net/taler/merchantpos/history/RefundUriFragment.kt
@@ -0,0 +1,65 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+ * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.merchantpos.history
+
+import android.annotation.SuppressLint
+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.navigation.fragment.findNavController
+import kotlinx.android.synthetic.main.fragment_refund_uri.*
+import net.taler.merchantpos.MainViewModel
+import net.taler.merchantpos.NfcManager.Companion.hasNfc
+import net.taler.merchantpos.QrCodeManager.makeQrCode
+import net.taler.merchantpos.R
+
+class RefundUriFragment : Fragment() {
+
+    private val model: MainViewModel by activityViewModels()
+    private val refundManager by lazy { model.refundManager }
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.fragment_refund_uri, container, false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        val result = refundManager.refundResult.value
+        if (result !is RefundResult.Success) throw IllegalStateException()
+
+        refundQrcodeView.setImageBitmap(makeQrCode(result.refundUri))
+
+        val introRes =
+            if (hasNfc(requireContext())) R.string.refund_intro_nfc else 
R.string.refund_intro
+        refundIntroView.setText(introRes)
+
+        @SuppressLint("SetTextI18n")
+        refundAmountView.text = "${result.amount} 
${result.item.amount.currency}"
+
+        refundRefView.text =
+            getString(R.string.refund_order_ref, result.item.orderId, 
result.reason)
+
+        cancelRefundButton.setOnClickListener { 
findNavController().navigateUp() }
+    }
+
+}
diff --git a/app/src/main/res/drawable/ic_cash_refund.xml 
b/app/src/main/res/drawable/ic_cash_refund.xml
new file mode 100644
index 0000000..7359ca3
--- /dev/null
+++ b/app/src/main/res/drawable/ic_cash_refund.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android";
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+            android:fillColor="#000000"
+            android:pathData="M3,11H21V23H3V11M12,15A2,2 0 0,1 14,17A2,2 0 0,1 
12,19A2,2 0 0,1 10,17A2,2 0 0,1 12,15M7,13A2,2 0 0,1 5,15V19A2,2 0 0,1 
7,21H17A2,2 0 0,1 19,19V15A2,2 0 0,1 
17,13H7M17,5V10H15.5V6.5H9.88L12.3,8.93L11.24,10L7,5.75L11.24,1.5L12.3,2.57L9.88,5H17Z"
 />
+</vector>
diff --git a/app/src/main/res/layout/fragment_refund.xml 
b/app/src/main/res/layout/fragment_refund.xml
new file mode 100644
index 0000000..5a78cdd
--- /dev/null
+++ b/app/src/main/res/layout/fragment_refund.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ This file is part of GNU Taler
+  ~ (C) 2020 Taler Systems S.A.
+  ~
+  ~ GNU Taler is free software; you can redistribute it and/or modify it under 
the
+  ~ terms of the GNU General Public License as published by the Free Software
+  ~ Foundation; either version 3, or (at your option) any later version.
+  ~
+  ~ GNU Taler is distributed in the hope that it will be useful, but WITHOUT 
ANY
+  ~ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+  ~ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU General Public License along 
with
+  ~ GNU Taler; see the file COPYING.  If not, see 
<http://www.gnu.org/licenses/>
+  -->
+
+<androidx.constraintlayout.widget.ConstraintLayout 
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=".history.RefundFragment">
+
+    <com.google.android.material.textfield.TextInputLayout
+            android:id="@+id/amountView"
+            
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="16dp"
+            android:hint="@string/refund_amount"
+            app:boxBackgroundMode="outline"
+            app:endIconMode="clear_text"
+            app:endIconTint="?attr/colorControlNormal"
+            app:layout_constraintBottom_toTopOf="@+id/reasonView"
+            app:layout_constraintEnd_toStartOf="@+id/currencyView"
+            app:layout_constraintHorizontal_chainStyle="packed"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintVertical_chainStyle="spread">
+
+        <com.google.android.material.textfield.TextInputEditText
+                android:id="@+id/amountInputView"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:ems="6"
+                android:inputType="numberDecimal"
+                tools:text="23.42" />
+
+    </com.google.android.material.textfield.TextInputLayout>
+
+    <TextView
+            android:id="@+id/currencyView"
+            android:layout_width="wrap_content"
+            android:layout_height="0dp"
+            android:layout_marginStart="8dp"
+            android:gravity="start|center_vertical"
+            app:layout_constraintBottom_toBottomOf="@+id/amountView"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toEndOf="@+id/amountView"
+            app:layout_constraintTop_toTopOf="@+id/amountView"
+            tools:text="TESTKUDOS" />
+
+    <com.google.android.material.textfield.TextInputLayout
+            android:id="@+id/reasonView"
+            
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_margin="16dp"
+            android:hint="@string/refund_reason"
+            app:endIconMode="clear_text"
+            app:layout_constraintBottom_toTopOf="@+id/abortButton"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.5"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/amountView">
+
+        <com.google.android.material.textfield.TextInputEditText
+                android:id="@+id/reasonInputView"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                
android:inputType="textAutoComplete|textAutoCorrect|textMultiLine" />
+
+    </com.google.android.material.textfield.TextInputLayout>
+
+    <Button
+            android:id="@+id/abortButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="16dp"
+            android:backgroundTint="@color/red"
+            android:text="@string/refund_abort"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/refundButton"
+            app:layout_constraintHorizontal_bias="0.76"
+            app:layout_constraintHorizontal_chainStyle="spread_inside"
+            app:layout_constraintStart_toStartOf="parent" />
+
+    <Button
+            android:id="@+id/refundButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="16dp"
+            android:backgroundTint="@color/green"
+            android:text="@string/refund_confirm"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.5"
+            app:layout_constraintStart_toEndOf="@+id/abortButton" />
+
+    <ProgressBar
+            android:id="@+id/progressBar"
+            style="?android:attr/progressBarStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:visibility="invisible"
+            app:layout_constraintBottom_toBottomOf="@+id/refundButton"
+            app:layout_constraintEnd_toEndOf="@+id/refundButton"
+            app:layout_constraintStart_toStartOf="@+id/refundButton"
+            app:layout_constraintTop_toTopOf="@+id/refundButton"
+            tools:visibility="visible" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/fragment_refund_uri.xml 
b/app/src/main/res/layout/fragment_refund_uri.xml
new file mode 100644
index 0000000..8447d28
--- /dev/null
+++ b/app/src/main/res/layout/fragment_refund_uri.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ This file is part of GNU Taler
+  ~ (C) 2020 Taler Systems S.A.
+  ~
+  ~ GNU Taler is free software; you can redistribute it and/or modify it under 
the
+  ~ terms of the GNU General Public License as published by the Free Software
+  ~ Foundation; either version 3, or (at your option) any later version.
+  ~
+  ~ GNU Taler is distributed in the hope that it will be useful, but WITHOUT 
ANY
+  ~ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+  ~ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU General Public License along 
with
+  ~ GNU Taler; see the file COPYING.  If not, see 
<http://www.gnu.org/licenses/>
+  -->
+
+<androidx.constraintlayout.widget.ConstraintLayout 
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=".payment.ProcessPaymentFragment">
+
+    <ImageView
+            android:id="@+id/refundQrcodeView"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_margin="32dp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/guideline"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:ignore="ContentDescription"
+            tools:src="@tools:sample/avatars" />
+
+    <androidx.constraintlayout.widget.Guideline
+            android:id="@+id/guideline"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            app:layout_constraintGuide_percent="0.54" />
+
+    <TextView
+            android:id="@+id/refundIntroView"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_margin="16dp"
+            android:text="@string/refund_intro_nfc"
+            android:textAlignment="center"
+            android:textSize="24sp"
+            app:layout_constraintBottom_toTopOf="@+id/refundAmountView"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="@+id/guideline"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintVertical_chainStyle="spread" />
+
+    <TextView
+            android:id="@+id/refundAmountView"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="16dp"
+            android:textAppearance="@style/TextAppearance.AppCompat.Headline"
+            app:layout_constraintBottom_toTopOf="@+id/refundRefView"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="@+id/guideline"
+            app:layout_constraintTop_toBottomOf="@+id/refundIntroView"
+            tools:text="10.49 TESTKUDOS" />
+
+    <TextView
+            android:id="@+id/refundRefView"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_margin="16dp"
+            android:textAlignment="center"
+            app:layout_constraintBottom_toTopOf="@id/cancelRefundButton"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="@+id/guideline"
+            app:layout_constraintTop_toBottomOf="@+id/refundAmountView"
+            tools:text="@string/refund_order_ref" />
+
+    <Button
+            android:id="@+id/cancelRefundButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="16dp"
+            android:backgroundTint="@color/red"
+            android:text="@string/refund_abort"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.0"
+            app:layout_constraintStart_toStartOf="@+id/guideline" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/list_item_history.xml 
b/app/src/main/res/layout/list_item_history.xml
index 06ffff2..fe485ba 100644
--- a/app/src/main/res/layout/list_item_history.xml
+++ b/app/src/main/res/layout/list_item_history.xml
@@ -40,12 +40,12 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginStart="8dp"
+            android:layout_marginEnd="16dp"
             android:textColor="?android:attr/textColorPrimary"
             android:textSize="20sp"
             android:textStyle="bold"
             app:layout_constraintBottom_toBottomOf="@+id/orderSummaryView"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintHorizontal_bias="0.0"
+            app:layout_constraintEnd_toStartOf="@+id/refundButton"
             app:layout_constraintStart_toEndOf="@+id/orderSummaryView"
             app:layout_constraintTop_toTopOf="parent"
             app:layout_constraintVertical_bias="0.0"
@@ -72,13 +72,26 @@
             android:layout_height="wrap_content"
             android:layout_marginStart="8dp"
             android:layout_marginTop="8dp"
+            android:layout_marginEnd="16dp"
             android:textSize="20sp"
             app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintHorizontal_bias="0.5"
+            app:layout_constraintEnd_toStartOf="@+id/refundButton"
             app:layout_constraintStart_toEndOf="@+id/orderIdView"
             app:layout_constraintTop_toBottomOf="@+id/orderAmountView"
             app:layout_constraintVertical_bias="1.0"
             tools:text="3 hrs. ago" />
 
+    <ImageButton
+            android:id="@+id/refundButton"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:backgroundTint="?colorPrimary"
+            android:contentDescription="@string/history_refund"
+            android:tint="?attr/colorOnPrimary"
+            android:visibility="gone"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:srcCompat="@drawable/ic_cash_refund" />
+
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/navigation/nav_graph.xml 
b/app/src/main/res/navigation/nav_graph.xml
index 0d7d870..2e337f2 100644
--- a/app/src/main/res/navigation/nav_graph.xml
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
   ~ This file is part of GNU Taler
   ~ (C) 2020 Taler Systems S.A.
   ~
@@ -57,7 +56,27 @@
             android:id="@+id/nav_history"
             
android:name="net.taler.merchantpos.history.MerchantHistoryFragment"
             android:label="@string/history_label"
-            tools:layout="@layout/fragment_merchant_history" />
+            tools:layout="@layout/fragment_merchant_history">
+        <action
+                android:id="@+id/action_nav_history_to_refundFragment"
+                app:destination="@id/refundFragment" />
+    </fragment>
+
+    <fragment
+            android:id="@+id/refundFragment"
+            android:name="net.taler.merchantpos.history.RefundFragment"
+            android:label="@string/history_refund"
+            tools:layout="@layout/fragment_refund">
+        <action
+                android:id="@+id/action_refundFragment_to_refundUriFragment"
+                app:destination="@id/refundUriFragment" />
+    </fragment>
+
+    <fragment
+            android:id="@+id/refundUriFragment"
+            android:name="net.taler.merchantpos.history.RefundUriFragment"
+            android:label="@string/history_refund"
+            tools:layout="@layout/fragment_refund_uri" />
 
     <fragment
             android:id="@+id/nav_settings"
diff --git a/app/src/main/res/values/strings.xml 
b/app/src/main/res/values/strings.xml
index ac84c5d..77c7e03 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -48,6 +48,18 @@
     <string name="history_label">Payment History</string>
     <string name="history_received_at">Received at</string>
     <string name="history_ref_no">Ref. No: %s</string>
+    <string name="history_refund">Refund Order</string>
+    <string name="refund_amount">Amount</string>
+    <string name="refund_reason">Refund reason</string>
+    <string name="refund_abort">Abort</string>
+    <string name="refund_confirm">Give Refund</string>
+    <string name="refund_error_max_amount">Greater than order amount of 
%s</string>
+    <string name="refund_error_zero">Needs to be positive amount</string>
+    <string name="refund_error_backend">Error processing refund</string>
+    <string name="refund_error_deadline">Refund deadline has passed</string>
+    <string name="refund_intro_nfc">Please scan QR Code or use NFC to give 
refund</string>
+    <string name="refund_intro">Please scan QR Code to give refund</string>
+    <string name="refund_order_ref">Order Reference: %1$s\n\n%2$s</string>
 
     <string name="error_network">Network Error</string>
 

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



reply via email to

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