qr_refundable_from_list

This commit is contained in:
MooN 2025-11-12 21:16:22 +06:30
parent 2358782f3d
commit 644df8211d
11 changed files with 831 additions and 25 deletions

13
.idea/deviceManager.xml Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DeviceTable">
<option name="columnSorters">
<list>
<ColumnSorterState>
<option name="column" value="Name" />
<option name="order" value="ASCENDING" />
</ColumnSorterState>
</list>
</option>
</component>
</project>

View File

@ -142,6 +142,9 @@ public class InputPasswordFragment extends DataBindingFragment implements DataBi
private void checkRoute() {
switch (Objects.requireNonNull(sharedViewModel.transactionsType.getValue())) {
case MMQR_REFUND:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SYSTEM);
break;
case PRE_AUTH_COMPLETE_VOID:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SYSTEM);
sharedViewModel.transactionName.postValue(getResourceString(R.string.title_pre_auth_complete));
@ -242,6 +245,11 @@ public class InputPasswordFragment extends DataBindingFragment implements DataBi
if(inputPasswordViewModel.onClickEnter()) {
clearLiveData();
if(sharedViewModel.transactionsType.getValue() == TransactionsType.MMQR_REFUND){
safePopBackStack();
return;
}
if(sharedViewModel.transactionsType.getValue() == TransactionsType.SETTING) {
mListener.onSuccess();
}

View File

@ -80,6 +80,12 @@ public class QRPayFragment extends DataBindingFragment {
return config;
}
public class ClickEvent {
public void onGenerateQRClick() { onClickQRPay(); }
public void onRefundClick() { onClickRefund(); }
public void onHistoryClick() { onClickHistory(); }
}
@Override
protected int currentId() {
return currentId;

View File

@ -1,6 +1,7 @@
package com.utsmm.kbz.ui.qr_pay;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.utsmyanmar.baselib.repo.Repository;
@ -18,6 +19,10 @@ public class QRPayViewModel extends ViewModel {
private final Repository repository;
private final LiveData<List<PayDetail>> refundableHistory;
private final MutableLiveData<PayDetail> _payDetail = new MutableLiveData<>();
public LiveData<PayDetail> payDetail = _payDetail;
@Inject
public QRPayViewModel(Repository repository){
this.repository = repository;
@ -27,4 +32,11 @@ public class QRPayViewModel extends ViewModel {
public LiveData<List<PayDetail>> getRefundableQrHistory(){
return refundableHistory;
}
public void setPayDetail(PayDetail payDetail){
_payDetail.setValue(payDetail);
}
public Runnable onCancel;
public Runnable onConfirm;
}

View File

@ -0,0 +1,357 @@
package com.utsmm.kbz.ui.qr_pay;
import android.os.Bundle;
import android.text.InputFilter;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmm.kbz.ui.kpay.KPayViewModel;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.KPayRefund;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.system.SystemDateTime;
import com.utsmyanmar.paylibs.utils.POSUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.util.DecimalDigitsInputFilter;
import com.utsmm.kbz.util.TransactionUtil;
import com.utsmm.kbz.util.ecr.CoreUtils;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class QRRefundDetailFragment extends DataBindingFragment {
private SharedViewModel sharedViewModel;
private KPayViewModel KPayViewModel;
private int routeId;
private TradeData tradeData;
private PayDetail payDetail;
// UI Elements
private RadioGroup radioGroupRefundType;
private RadioButton radioOriginal, radioPartial;
private EditText etReferenceNo, etOriginalAmount, etRefundAmount, etRefundReason;
private LinearLayout originalAmountLayout, refundAmountLayout;
private boolean isPartialRefund = false;
CompositeDisposable refundDisposable = new CompositeDisposable();
CompositeDisposable retrieveUpdateDisposable = new CompositeDisposable();
private static final String TAG = com.utsmm.kbz.ui.kpay.QRRefundFragment.class.getSimpleName();
private static final int hostId = Constants.NAV_HOST_ID;
private static final int currentId = R.id.qrRefundDetail;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
KPayViewModel = getFragmentScopeViewModel(KPayViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_qr_refund_detail, BR.sharedViewModel, sharedViewModel)
.addBindingParam(BR.kPayViewModel, KPayViewModel)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
protected int currentId() {
return currentId;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if(getArguments() != null){
payDetail = (PayDetail) getArguments().getSerializable("payDetail");
}
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon("KPay Refund");
KPayViewModel.invalidAmountMsg.setValue("");
}
@Override
public void onDestroyView() {
super.onDestroyView();
refundDisposable.dispose();
retrieveUpdateDisposable.dispose();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initViews();
initData();
setupRadioGroupListener();
}
private void initViews() {
radioGroupRefundType = mBinding.getRoot().findViewById(R.id.radio_group_refund_type);
radioOriginal = mBinding.getRoot().findViewById(R.id.radio_original);
radioPartial = mBinding.getRoot().findViewById(R.id.radio_partial);
etReferenceNo = mBinding.getRoot().findViewById(R.id.et_reference_no);
etOriginalAmount = mBinding.getRoot().findViewById(R.id.et_original_amount);
etRefundAmount = mBinding.getRoot().findViewById(R.id.et_refund_amount);
etRefundReason = mBinding.getRoot().findViewById(R.id.et_refund_reason);
originalAmountLayout = mBinding.getRoot().findViewById(R.id.original_amount_layout);
refundAmountLayout = mBinding.getRoot().findViewById(R.id.refund_amount_layout);
// Set input filters for amount fields
etOriginalAmount.setFilters(new InputFilter[]{new DecimalDigitsInputFilter(11, 2)});
etRefundAmount.setFilters(new InputFilter[]{new DecimalDigitsInputFilter(11, 2)});
}
private void initData() {
payDetail = TransactionUtil.getInstance().initWalletTransaction(TransactionsType.MMQR_REFUND);
payDetail.setInvoiceNo(SystemParamsOperation.getInstance().getIncrementInvoiceNum());
if(getArguments() != null){
PayDetail passData = (PayDetail) getArguments().getSerializable("payDetail");
if(passData != null && passData.getReferNo() != null){
etReferenceNo.setText(passData.getReferNo());
etReferenceNo.setEnabled(false);
}
}
}
private void setupRadioGroupListener() {
radioGroupRefundType.setOnCheckedChangeListener((group, checkedId) -> {
if (checkedId == R.id.radio_partial) {
// Show both amount fields for partial refund
isPartialRefund = true;
originalAmountLayout.setVisibility(View.VISIBLE);
refundAmountLayout.setVisibility(View.VISIBLE);
} else {
// Hide amount fields for original refund
isPartialRefund = false;
originalAmountLayout.setVisibility(View.GONE);
refundAmountLayout.setVisibility(View.GONE);
}
});
}
private void processKPayRefund(String referenceNo, String refundAmount, String originalAmount, String reason) {
String merchantId = TransactionUtil.getInstance().getQRMerchantId();
// Generate unique refund request ID
String refundRequestId = referenceNo + "R";
showLoadingDialog("Processing refund...");
// Create KPay refund request
KPayRefund.RefundRequest refundRequest = KPayViewModel.createRefundRequest(
refundRequestId,
referenceNo,
merchantId,
refundAmount,
reason != null ? reason : "Refund request"
);
Disposable refundDi = KPayViewModel.kPayRefund(refundRequest)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
response -> {
dismissLoadingDialog();
handleRefundResponse(response, referenceNo);
},
throwable -> {
dismissLoadingDialog();
LogUtil.e(TAG, "Refund error: " + throwable.getMessage());
showDeclineDialog("Refund failed!\nCommunication Error!");
ecrActionCancel("Refund failed");
navigateToMain();
},
() -> LogUtil.d(TAG, "Refund request completed")
);
refundDisposable.add(refundDi);
}
private void handleRefundResponse(KPayRefund.RefundResponse response, String referenceNo) {
if (response != null && response.getResponse() != null && "REFUND_SUCCESS".equalsIgnoreCase(response.getResponse().getRefundStatus())) {
LogUtil.d(TAG, "Refund successful!");
String refundAmount = response.getResponse().getRefundAmount();
String dateTime = SystemDateTime.getTodayDateFormat() + " " + SystemDateTime.getTodayTimeFormat();
payDetail.setAmount(refundAmount == null ? 0 : POSUtil.getInstance().convertAmount(refundAmount));
payDetail.setOriginalTransDate(dateTime);
payDetail.setQrTransStatus(1);
payDetail.setQrReferNo(referenceNo);
payDetail.setReferNo(referenceNo);
payDetail.setIsCanceled(true);
retrievedUpdatePayDetail(referenceNo);
} else {
LogUtil.d(TAG, "Refund failed!");
payDetail.setQrTransStatus(-1);
payDetail.setQrReferNo(referenceNo);
payDetail.setReferNo(referenceNo);
String errorMsg = "Refund failed";
if (response != null && response.getResponse() != null && response.getResponse().getMsg() != null) {
errorMsg = response.getResponse().getMsg();
}
payDetail.setTradeResultDes(errorMsg);
sharedViewModel.payDetail.setValue(payDetail);
navigateToNext();
}
}
private void retrievedUpdatePayDetail(String refNum) {
LogUtil.d(TAG, "Trying to update Database!");
retrieveUpdateDisposable.add(KPayViewModel.searchPayByRefNum(refNum)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(oldPay -> {
LogUtil.d(TAG, "Inside the subscribe!");
if (oldPay != null) {
oldPay.setIsCanceled(true);
payDetail.setQrTransId(oldPay.getQrTransId());
payDetail.setCustomerMobile(oldPay.getCustomerMobile());
sharedViewModel.updatePayDetail(oldPay);
}
updateData();
navigateToNext();
},
onError -> {
LogUtil.d(TAG, "On error Unable to retrieve PayDetail");
updateData();
navigateToNext();
},
() -> {
LogUtil.d(TAG, "No data found! navigating to Result Page!");
updateData();
navigateToNext();
}
));
}
private void updateData() {
KPayViewModel.insertPayDetail(payDetail);
sharedViewModel.payDetail.postValue(payDetail);
}
private void navigateToMain() {
routeId = R.id.action_QRRefundDetail_to_nav_main;
safeNavigateToRouteId();
}
private void navigateToNext() {
routeId = R.id.action_QRRefundDetail_to_transactionResultFragment;
safeNavigateToRouteId();
}
private void ecrActionCancel(String msg) {
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
sharedViewModel.isEcr.postValue(false);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg);
sharedViewModel.isEcrFinished.postValue(true);
}
}
}
public class ClickEvent {
public void onCancel() {
safePopBackStack();
}
public void onConfirm() {
KPayViewModel.invalidAmountMsg.setValue("");
String referenceNo = etReferenceNo.getText().toString().trim();
String refundReason = etRefundReason.getText().toString().trim();
// Validate reference number
if (referenceNo.isEmpty()) {
KPayViewModel.invalidAmountMsg.setValue("Enter reference number");
return;
}
if (isPartialRefund) {
// Partial refund validation
String originalAmountStr = etOriginalAmount.getText().toString().trim();
String refundAmountStr = etRefundAmount.getText().toString().trim();
if (originalAmountStr.isEmpty()) {
KPayViewModel.invalidAmountMsg.setValue("Enter original amount");
return;
}
if (refundAmountStr.isEmpty()) {
KPayViewModel.invalidAmountMsg.setValue("Enter refund amount");
return;
}
double originalAmount = Double.parseDouble(originalAmountStr);
double refundAmount = Double.parseDouble(refundAmountStr);
if (originalAmount <= 0) {
KPayViewModel.invalidAmountMsg.setValue("Enter valid original amount");
return;
}
if (refundAmount <= 0) {
KPayViewModel.invalidAmountMsg.setValue("Enter valid refund amount");
return;
}
if (refundAmount > originalAmount) {
KPayViewModel.invalidAmountMsg.setValue("Refund amount cannot exceed original amount");
return;
}
processKPayRefund(referenceNo, refundAmountStr, originalAmountStr, refundReason);
} else {
// Original amount refund - no amount validation needed
processKPayRefund(referenceNo, "0", String.valueOf( etOriginalAmount.getText().toString().trim()), refundReason);
}
}
}
public void navigateToPassword(){
sharedViewModel.transactionsType.setValue(TransactionsType.MMQR_REFUND);
routeId = R.id.action_qrRefundPasswordFragment_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
}
}

View File

@ -2,10 +2,13 @@ package com.utsmm.kbz.ui.qr_pay;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -13,6 +16,7 @@ import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.kpay.KPayViewModel;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.model.PayDetail;
@ -35,27 +39,33 @@ public class QRRefundFragment extends DataBindingFragment {
}
@Override
protected int hostId() {return hostId;}
@Override
protected int routeId() {return routeId;}
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
qrPayViewModel = getFragmentScopeViewModel(QRPayViewModel.class);
sharedViewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
qrPayViewModel = new ViewModelProvider(requireActivity()).get(QRPayViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
adapter = new QRRefundViewAdapter();
return new DataBindingConfig(R.layout.fragment_qr_refund, BR.sharedViewModel, sharedViewModel).addBindingParam(BR.adapter, adapter);
adapter = new QRRefundViewAdapter(this::onRefundItemClicked);
return new DataBindingConfig(R.layout.fragment_qr_refund, BR.sharedViewModel, sharedViewModel)
.addBindingParam(BR.adapter, adapter)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
public void onResume(){
super.onResume();
setToolBarTitleWithBackIcon("Refund");
setToolBarTitleWithBackIcon("QR Refund");
}
@Override
public void onCreate(@Nullable Bundle savedInstance){
super.onCreate(savedInstance);
adapter = new QRRefundViewAdapter(this::onRefundItemClicked);
}
@Override
@ -73,12 +83,10 @@ public class QRRefundFragment extends DataBindingFragment {
}
private void updateList(List<PayDetail> list){
if(list == null || list.isEmpty()){
showSingleInfoDialog("No data test");
adapter.setData(null);
}else{
adapter.setData(list);
if (adapter == null) {
return;
}
adapter.setData(list);
}
public class ClickEvent {
@ -87,4 +95,10 @@ public class QRRefundFragment extends DataBindingFragment {
}
}
private void onRefundItemClicked(PayDetail payDetail) {
Bundle bundle = new Bundle();
bundle.putSerializable("payDetail", payDetail);
routeId = R.id.action_qrRefundList_to_qrRefundDetail;
NavHostFragment.findNavController(this).navigate(R.id.action_qrRefundList_to_qrRefundDetail, bundle);
}
}

View File

@ -11,6 +11,7 @@ import android.view.ViewGroup;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.databinding.ItemQrRefundBinding;
import com.utsmm.kbz.ui.adapters.QRPayAdapter;
import com.utsmyanmar.paylibs.model.PayDetail;
import java.util.ArrayList;
@ -20,16 +21,23 @@ import java.util.List;
public class QRRefundViewAdapter extends RecyclerView.Adapter<QRRefundViewAdapter.ViewHolder> {
private List<PayDetail> payDetailList = new ArrayList<>();
private final OnRefundItemClick listener;
public QRRefundViewAdapter(){}
public QRRefundViewAdapter(List<PayDetail> payDetailList){
this.payDetailList = payDetailList;
public interface OnRefundItemClick {
void onClick(PayDetail payDetail);
}
public QRRefundViewAdapter(OnRefundItemClick listener){
this.listener = listener;
}
// public QRRefundViewAdapter(List<PayDetail> payDetailList, OnRefundItemClick listener){
// this.payDetailList = payDetailList;
// this.listener = listener;
// }
public void setData(List<PayDetail> data){
if(data == null) return;
payDetailList.clear();
payDetailList.addAll(data);
this.payDetailList = data != null ? data : new ArrayList<>();
notifyDataSetChanged();
}
@ -49,7 +57,7 @@ public class QRRefundViewAdapter extends RecyclerView.Adapter<QRRefundViewAdapte
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
PayDetail payDetail = payDetailList.get(position);
holder.bind(payDetail);
holder.bind(payDetail, listener);
}
@Override
@ -65,9 +73,12 @@ public class QRRefundViewAdapter extends RecyclerView.Adapter<QRRefundViewAdapte
this.binding = binding;
}
public void bind(Object object){
binding.setVariable(BR.payDetail, object);
public void bind(PayDetail payDetail, OnRefundItemClick listener){
binding.setVariable(BR.payDetail, payDetail);
binding.executePendingBindings();
binding.getRoot().setOnClickListener( v -> {
if(listener != null) listener.onClick(payDetail);
});
}
}
}

View File

@ -0,0 +1,349 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="sharedViewModel"
type="com.utsmm.kbz.ui.core_viewmodel.SharedViewModel" />
<variable
name="kPayViewModel"
type="com.utsmm.kbz.ui.kpay.KPayViewModel" />
<variable
name="click"
type="com.utsmm.kbz.ui.qr_pay.QRRefundDetailFragment.ClickEvent" />
</data>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<!-- Refund Type Selection -->
<LinearLayout
android:id="@+id/refund_type_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:text="Refund Type"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<RadioGroup
android:id="@+id/radio_group_refund_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<RadioButton
android:id="@+id/radio_original"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:checked="true"
android:text="Original Amount"
android:textSize="16sp" />
<RadioButton
android:id="@+id/radio_partial"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Partial Amount"
android:textSize="16sp" />
</RadioGroup>
</LinearLayout>
<!-- Reference Number Input -->
<LinearLayout
android:id="@+id/reference_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/refund_type_layout">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:text="Reference Number *"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
<EditText
android:id="@+id/et_reference_no"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:hint="Enter reference number"
android:inputType="text"
android:maxLength="20"
android:padding="16dp"
android:textAlignment="center"
android:textColor="@color/black"
android:textSize="18sp"
tools:text="NEX000011" />
</androidx.cardview.widget.CardView>
</LinearLayout>
<!-- Original Amount Input (for partial refunds) -->
<LinearLayout
android:id="@+id/original_amount_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:orientation="vertical"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/reference_layout">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:text="Original Amount *"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_amount_title"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/mmk"
android:textSize="18sp" />
</LinearLayout>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="4dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
<EditText
android:id="@+id/et_original_amount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:hint="0.00"
android:inputType="numberDecimal"
android:padding="16dp"
android:textAlignment="center"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold"
tools:text="1000.00" />
</androidx.cardview.widget.CardView>
</LinearLayout>
</LinearLayout>
<!-- Refund Amount Input (for partial refunds) -->
<LinearLayout
android:id="@+id/refund_amount_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:orientation="vertical"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/original_amount_layout">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:text="Refund Amount *"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_amount_title"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/mmk"
android:textSize="18sp" />
</LinearLayout>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="4dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
<EditText
android:id="@+id/et_refund_amount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:hint="0.00"
android:inputType="numberDecimal"
android:padding="16dp"
android:textAlignment="center"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold"
tools:text="400.00" />
</androidx.cardview.widget.CardView>
</LinearLayout>
</LinearLayout>
<!-- Refund Reason Input -->
<LinearLayout
android:id="@+id/refund_reason_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/refund_amount_layout">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:text="Refund Reason"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
<EditText
android:id="@+id/et_refund_reason"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:hint="Enter refund reason (optional)"
android:inputType="textMultiLine"
android:lines="3"
android:padding="16dp"
android:textColor="@color/black"
android:textSize="16sp"
tools:text="Customer requested refund" />
</androidx.cardview.widget.CardView>
</LinearLayout>
<!-- Error Message -->
<TextView
android:id="@+id/error_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@{kPayViewModel.invalidAmountMsg}"
android:textAlignment="center"
android:textColor="@color/red"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/refund_reason_layout"
tools:text="Invalid amount entered" />
<!-- Action Buttons -->
<LinearLayout
android:id="@+id/button_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/error_message">
<Button
android:id="@+id/btn_cancel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_weight="1"
android:background="@drawable/bg_rounded_btn_cancel_cv"
android:onClick="@{()->click.onCancel()}"
android:text="@string/layout_cancel"
android:textColor="@color/colorPrimary"
android:textSize="16sp" />
<Button
android:id="@+id/btn_confirm"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_weight="1"
android:background="@drawable/bg_rounded_btn_cv"
android:onClick="@{()->click.onConfirm()}"
android:text="Process Refund"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</layout>

View File

@ -11,7 +11,7 @@
type="com.utsmyanmar.paylibs.model.PayDetail" />
<variable
name="onItemClick"
type="com.utsmm.kbz.ui.management.ItemClickListener" />
type="com.utsmm.kbz.ui.qr_pay.QRRefundFragment.ClickEvent" />
</data>
<androidx.cardview.widget.CardView
@ -25,7 +25,7 @@
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:onClick="@{() -> onItemClick.onClickCard(payDetail)}">
android:onClick="@{() -> onItemClick.onCancel()}">
<!-- Card with border -->
<LinearLayout

View File

@ -1103,5 +1103,42 @@
tools:layout="@layout/fragment_qr_refund"
android:name="com.utsmm.kbz.ui.qr_pay.QRRefundFragment"
>
<action
android:id="@+id/action_qrRefundList_to_qrRefundDetail"
app:destination="@id/qrRefundDetail"
/>
<action
app:launchSingleTop="true"
app:popUpTo="@+id/QRRefundPasswordFragment"
app:popUpToInclusive="true"
android:id="@+id/action_qrRefundPasswordFragment_to_inputPasswordFragment"
app:destination="@id/inputPasswordFragment" />
</fragment>
<fragment
android:id="@+id/qrRefundDetail"
tools:layout="@layout/fragment_qr_refund_detail"
android:name="com.utsmm.kbz.ui.qr_pay.QRRefundDetailFragment"
>
<action
android:id="@+id/action_QRRefundDetail_to_transactionResultFragment"
app:destination="@id/transactionResultFragment" />
<action
app:launchSingleTop="true"
app:popUpToInclusive="true"
app:popUpTo="@id/mobile_navigation"
android:id="@+id/action_QRRefundDetail_to_nav_main"
app:destination="@id/nav_main" />
<!-- <action-->
<!-- app:launchSingleTop="true"-->
<!-- app:popUpTo="@+id/QRRefundFragment"-->
<!-- app:popUpToInclusive="true"-->
<!-- android:id="@+id/action_qrRefundDetail_to_inputAmountFragment"-->
<!-- app:destination="@id/inputAmountFragment" />-->
<action
app:launchSingleTop="true"
app:popUpTo="@+id/QRRefundPasswordFragment"
app:popUpToInclusive="true"
android:id="@+id/action_qrRefundPasswordFragment_to_inputPasswordFragment"
app:destination="@id/inputPasswordFragment" />
</fragment>
</navigation>

View File

@ -152,8 +152,7 @@ public interface PayDetailDao {
@Query("SELECT * FROM paydetail WHERE transactionType = 20 ORDER BY PID DESC")
LiveData<List<PayDetail>> getAllQRHistory();
@Query("SELECT * FROM paydetail WHERE transactionType = 20 AND qrTransStatus = 1 ORDER BY PID DESC")
@Query("SELECT * FROM paydetail WHERE transactionType = 20 AND qrTransStatus = 1 AND isCanceled = 0 ORDER BY PID DESC")
LiveData<List<PayDetail>> getRefundableQRHistory();
//isReturnGood
}