add payment

This commit is contained in:
shaulascr
2025-04-19 15:39:47 +07:00
parent 3bcee3b16c
commit d1fcec6d14
10 changed files with 416 additions and 46 deletions

View File

@ -237,8 +237,13 @@ class OrderRepository(private val apiService: ApiService) {
}
suspend fun getOrderDetails(orderId: Int): OrderDetailResponse? {
val response = apiService.getDetailOrder(orderId)
return if (response.isSuccessful) response.body() else null
return try {
val response = apiService.getDetailOrder(orderId)
if (response.isSuccessful) response.body() else null
} catch (e: Exception) {
Log.e("OrderRepository", "Error getting order details", e)
null
}
}
suspend fun uploadPaymentProof(request : AddEvidenceRequest): Result<AddEvidenceResponse> {

View File

@ -1,21 +1,195 @@
package com.alya.ecommerce_serang.ui.order.detail
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import android.util.Log
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
import com.alya.ecommerce_serang.data.repository.OrderRepository
import com.alya.ecommerce_serang.databinding.ActivityPaymentBinding
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
import com.alya.ecommerce_serang.utils.SessionManager
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class PaymentActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_payment)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
private lateinit var binding: ActivityPaymentBinding
private lateinit var sessionManager: SessionManager
companion object {
private const val TAG = "PaymentActivity"
}
private val viewModel: PaymentViewModel by viewModels {
BaseViewModelFactory {
val apiService = ApiConfig.getApiService(sessionManager)
val orderRepository = OrderRepository(apiService)
PaymentViewModel(orderRepository)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPaymentBinding.inflate(layoutInflater)
setContentView(binding.root)
sessionManager = SessionManager(this)
// Mengambil data dari intent
val orderId = intent.getIntExtra("ORDER_ID", 0)
val paymentInfoId = intent.getIntExtra("ORDER_PAYMENT_ID", 0)
if (orderId == 0) {
Toast.makeText(this, "ID pesanan tidak valid", Toast.LENGTH_SHORT).show()
finish()
}
// Setup toolbar
binding.toolbar.setNavigationOnClickListener {
finish()
}
// Setup petunjuk transfer
binding.layoutMBankingInstructions.setOnClickListener {
// Tampilkan instruksi mBanking
showInstructions("mBanking")
}
binding.layoutATMInstructions.setOnClickListener {
// Tampilkan instruksi ATM
showInstructions("ATM")
}
// Setup button upload bukti bayar
binding.btnUploadPaymentProof.setOnClickListener {
// Intent ke activity upload bukti bayar
// val intent = Intent(this, UploadPaymentProofActivity::class.java)
intent.putExtra("ORDER_ID", orderId)
intent.putExtra("PAYMENT_INFO_ID", paymentInfoId)
Log.d(TAG, "Received Order ID: $orderId, Payment Info ID: $paymentInfoId")
startActivity(intent)
}
// Setup button negosiasi harga
binding.btnNegotiatePrice.setOnClickListener {
// Intent ke activity negosiasi harga
// val intent = Intent(this, NegotiatePriceActivity::class.java)
// intent.putExtra("ORDER_ID", orderId)
// startActivity(intent)
}
// Observe data
observeData()
// Load data
Log.d(TAG, "Fetching order details for Order ID: $orderId")
viewModel.getOrderDetails(orderId)
}
private fun observeData() {
// Observe Order Details
viewModel.orderDetails.observe(this) { order ->
Log.d(TAG, "Order details received: $order")
// Set total amount
binding.tvTotalAmount.text = order.totalAmount ?: "Rp0"
Log.d(TAG, "Total Amount: ${order.totalAmount}")
// Set bank information
binding.tvBankName.text = order.payInfoName ?: "Bank BCA"
binding.tvAccountNumber.text = order.payInfoNum ?: "0123456789"
Log.d(TAG, "Bank Name: ${order.payInfoName}, Account Number: ${order.payInfoNum}")
// Calculate remaining time and due date
setupPaymentDueDate(order.updatedAt)
}
// Observe loading state
viewModel.isLoading.observe(this) { isLoading ->
// Show loading indicator if needed
// binding.progressBar.visibility = if (isLoading) View.VISIBLE else View.GONE
}
// Observe error
viewModel.error.observe(this) { error ->
if (error.isNotEmpty()) {
Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
}
}
}
private fun setupPaymentDueDate(createdAt: String) {
Log.d(TAG, "Setting up payment due date from updated at: $createdAt")
try {
// Parse the created date
val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val createdDate = dateFormat.parse(createdAt) ?: return
// Add 24 hours to get due date
val calendar = Calendar.getInstance()
calendar.time = createdDate
calendar.add(Calendar.HOUR, 24)
val dueDate = calendar.time
// Format due date for display
val dueDateFormat = SimpleDateFormat("dd MMM yyyy", Locale.getDefault())
binding.tvDueDate.text = "Jatuh tempo ${dueDateFormat.format(dueDate)}"
Log.d(TAG, "Due Date: ${dueDateFormat.format(dueDate)}")
// Calculate remaining time
val now = Calendar.getInstance().time
val diff = dueDate.time - now.time
if (diff > 0) {
val hours = diff / (60 * 60 * 1000)
val minutes = (diff % (60 * 60 * 1000)) / (60 * 1000)
binding.tvRemainingTime.text = "$hours jam $minutes menit"
Log.d(TAG, "Remaining Time: $hours hours $minutes minutes")
} else {
binding.tvRemainingTime.text = "Waktu habis"
}
} catch (e: Exception) {
binding.tvDueDate.text = "Jatuh tempo -"
binding.tvRemainingTime.text = "-"
}
}
private fun showInstructions(type: String) {
// Implementasi tampilkan instruksi
val instructions = when (type) {
"mBanking" -> listOf(
"1. Login ke aplikasi mobile banking",
"2. Pilih menu Transfer",
"3. Pilih menu Antar Rekening",
"4. Masukkan nomor rekening tujuan",
"5. Masukkan nominal transfer sesuai tagihan",
"6. Konfirmasi dan selesaikan transfer"
)
"ATM" -> listOf(
"1. Masukkan kartu ATM dan PIN",
"2. Pilih menu Transfer",
"3. Pilih menu Antar Rekening",
"4. Masukkan kode bank dan nomor rekening tujuan",
"5. Masukkan nominal transfer sesuai tagihan",
"6. Konfirmasi dan selesaikan transfer"
)
else -> emptyList()
}
// Tampilkan instruksi dalam dialog
val dialog = AlertDialog.Builder(this)
.setTitle("Petunjuk Transfer $type")
.setItems(instructions.toTypedArray(), null)
.setPositiveButton("Tutup", null)
.create()
dialog.show()
}
}

View File

@ -0,0 +1,53 @@
package com.alya.ecommerce_serang.ui.order.detail
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.alya.ecommerce_serang.data.api.response.order.OrderListItemsItem
import com.alya.ecommerce_serang.data.api.response.order.Orders
import com.alya.ecommerce_serang.data.repository.OrderRepository
import kotlinx.coroutines.launch
class PaymentViewModel(private val repository: OrderRepository) : ViewModel() {
companion object {
private const val TAG = "PaymentViewModel"
}
// LiveData untuk Order
private val _orderDetails = MutableLiveData<Orders>()
val orderDetails: LiveData<Orders> get() = _orderDetails
// LiveData untuk OrderItems
private val _orderItems = MutableLiveData<List<OrderListItemsItem>>()
val orderItems: LiveData<List<OrderListItemsItem>> get() = _orderItems
// LiveData untuk status loading
private val _isLoading = MutableLiveData<Boolean>()
val isLoading: LiveData<Boolean> get() = _isLoading
// LiveData untuk error
private val _error = MutableLiveData<String>()
val error: LiveData<String> get() = _error
fun getOrderDetails(orderId: Int) {
_isLoading.value = true
viewModelScope.launch {
try {
val response = repository.getOrderDetails(orderId)
if (response != null) {
_orderDetails.value = response.orders
_orderItems.value = response.orders.orderItems
} else {
_error.value = "Gagal memuat detail pesanan"
}
} catch (e: Exception) {
_error.value = "Terjadi kesalahan: ${e.message}"
Log.e(TAG, "Error fetching order details", e)
} finally {
_isLoading.value = false
}
}
}
}

View File

@ -1,5 +1,7 @@
package com.alya.ecommerce_serang.ui.order.history
import android.content.Intent
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -8,6 +10,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.response.order.OrdersItem
import com.alya.ecommerce_serang.ui.order.detail.PaymentActivity
import com.google.android.material.button.MaterialButton
class OrderHistoryAdapter(
private val onOrderClickListener: (OrdersItem) -> Unit
@ -15,6 +19,12 @@ class OrderHistoryAdapter(
private val orders = mutableListOf<OrdersItem>()
private var fragmentStatus: String = "all"
fun setFragmentStatus(status: String) {
fragmentStatus = status
}
fun submitList(newOrders: List<OrdersItem>) {
orders.clear()
orders.addAll(newOrders)
@ -34,7 +44,6 @@ class OrderHistoryAdapter(
inner class OrderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val tvStoreName: TextView = itemView.findViewById(R.id.tvStoreName)
private val tvOrderStatus: TextView = itemView.findViewById(R.id.tvOrderStatus)
private val rvOrderItems: RecyclerView = itemView.findViewById(R.id.rvOrderItems)
private val tvShowMore: TextView = itemView.findViewById(R.id.tvShowMore)
private val tvTotalAmount: TextView = itemView.findViewById(R.id.tvTotalAmount)
@ -46,9 +55,6 @@ class OrderHistoryAdapter(
val storeName = if (order.orderItems.isNotEmpty()) order.orderItems[0].storeName else ""
tvStoreName.text = storeName
// Set order status based on shipment status
tvOrderStatus.text = getStatusLabel(order.shipmentStatus)
// Set total amount
tvTotalAmount.text = order.totalAmount
@ -56,8 +62,8 @@ class OrderHistoryAdapter(
val itemCount = order.orderItems.size
tvItemCountLabel.text = itemView.context.getString(R.string.item_count_prod, itemCount)
// Set deadline date
tvDeadlineDate.text = formatDate(order.createdAt) // This would need a proper date formatting function
// Set deadline date, adjust to each status
tvDeadlineDate.text = formatDate(order.createdAt)
// Set up the order items RecyclerView
val productAdapter = OrderProductAdapter()
@ -86,6 +92,10 @@ class OrderHistoryAdapter(
itemView.setOnClickListener {
onOrderClickListener(order)
}
//adjust each fragment
adjustButtonsAndText(fragmentStatus, order)
}
private fun getStatusLabel(status: String): String {
@ -102,6 +112,127 @@ class OrderHistoryAdapter(
}
}
private fun adjustButtonsAndText(status: String, order: OrdersItem) {
Log.d("OrderHistoryAdapter", "Adjusting buttons for status: $status")
// Mendapatkan referensi ke tombol-tombol
val btnLeft = itemView.findViewById<MaterialButton>(R.id.btn_left)
val btnRight = itemView.findViewById<MaterialButton>(R.id.btn_right)
val statusOrder = itemView.findViewById<TextView>(R.id.tvOrderStatus)
val deadlineLabel = itemView.findViewById<TextView>(R.id.tvDeadlineLabel)
// Reset visibility
btnLeft.visibility = View.GONE
btnRight.visibility = View.GONE
statusOrder.visibility = View.GONE
deadlineLabel.visibility = View.GONE
when (status) {
"pending" -> {
statusOrder.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.pending_orders)
}
deadlineLabel.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.dl_pending)
}
}
"unpaid" -> {
statusOrder.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.unpaid_orders)
}
deadlineLabel.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.dl_unpaid)
}
btnLeft.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.canceled_order_btn)
setOnClickListener {
}
}
btnRight.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.sent_evidence)
setOnClickListener {
val intent = Intent(itemView.context, PaymentActivity::class.java)
// Menambahkan data yang diperlukan
intent.putExtra("ORDER_ID", order.orderId)
intent.putExtra("ORDER_PAYMENT_ID", order.paymentInfoId)
// Memulai aktivitas
itemView.context.startActivity(intent)
}
}
}
"processed" -> {
// Untuk status processed, tampilkan "Hubungi Penjual"
statusOrder.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.processed_orders)
}
deadlineLabel.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.dl_processed)
}
}
"shipped" -> {
// Untuk status shipped, tampilkan "Lacak Pengiriman" dan "Terima Barang"
statusOrder.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.shipped_orders)
}
deadlineLabel.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.dl_shipped)
}
btnLeft.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.claim_complaint)
setOnClickListener {
// Handle click event
}
}
btnRight.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.claim_order)
setOnClickListener {
// Handle click event
}
}
}
"delivered" -> {
// Untuk status delivered, tampilkan "Beri Ulasan"
btnRight.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.add_review)
setOnClickListener {
// Handle click event
}
}
}
"completed" -> {
statusOrder.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.shipped_orders)
}
deadlineLabel.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.dl_shipped)
}
btnRight.apply {
visibility = View.VISIBLE
text = itemView.context.getString(R.string.add_review)
setOnClickListener {
// Handle click event
}
}
}
}
}
private fun formatDate(dateString: String): String {
// In a real app, you would parse the date string and format it
// For this example, just return the string as is

View File

@ -77,6 +77,8 @@ class OrderListFragment : Fragment() {
navigateToOrderDetail(order)
}
orderAdapter.setFragmentStatus(status)
binding.rvOrders.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = orderAdapter

View File

@ -9,6 +9,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.response.order.OrderItemsItem
import com.bumptech.glide.Glide
import com.google.android.material.button.MaterialButton
class OrderProductAdapter : RecyclerView.Adapter<OrderProductAdapter.ProductViewHolder>() {
@ -53,8 +54,11 @@ class OrderProductAdapter : RecyclerView.Adapter<OrderProductAdapter.ProductView
.placeholder(R.drawable.placeholder_image)
// .error(R.drawable.error_image)
.into(ivProductImage)
}
private fun formatCurrency(amount: Int): String {
// In a real app, you would use NumberFormat for proper currency formatting
// For simplicity, just return a basic formatted string

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/white" />
<corners android:radius="8dp" />
<stroke
android:width="2dp"

View File

@ -2,9 +2,9 @@
<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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".ui.order.detail.PaymentActivity">
<com.google.android.material.appbar.AppBarLayout
@ -18,15 +18,14 @@
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@android:color/white"
app:navigationIcon="@drawable/ic_arrow_back">
app:navigationIcon="@drawable/ic_back_24">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pembayaran"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold" />
android:fontFamily="@font/dmsans_bold"
android:textSize="18sp" />
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
@ -103,7 +102,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:cardCornerRadius="8dp"
app:cardElevation="2dp">
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
@ -210,23 +209,6 @@
android:layout_height="1dp"
android:background="#E0E0E0" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Detail Pesanan"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvOrderItems"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="2"
tools:listitem="@layout/item_order_product" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
@ -239,7 +221,7 @@
android:padding="16dp"
app:layout_constraintBottom_toBottomOf="parent">
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/btnNegotiatePrice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -249,7 +231,7 @@
android:textAllCaps="false"
android:textColor="@color/blue_500" />
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/btnUploadPaymentProof"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -60,6 +60,7 @@
android:gravity="center_vertical"
android:textColor="@android:color/darker_gray"
android:textSize="14sp"
android:visibility="visible"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/rvOrderItems"
app:layout_constraintEnd_toEndOf="parent"

View File

@ -77,5 +77,24 @@
<string name="completed_orders">Selesai</string>
<string name="shipped_orders">Dikirim</string>
<string name="canceled_orders">Dibatalkan</string>
<!-- deadline label -->
<string name="dl_pending">Batas Tagihan</string>
<string name="dl_unpaid">Batas Pembayaran</string>
<string name="dl_processed">Batas Pengiriman</string>
<string name="dal_paid">Semua Pesanan </string>
<string name="dl_delivered">Semua Pesanan </string>
<string name="dl_completed">Semua Pesanan </string>
<string name="dl_shipped">Tanggal Pesanan Sampai</string>
<string name="dl_canceled">Semua Pesanan </string>
<string name="sent_evidence">Kirim Bukti Pembayaran </string>
<string name="canceled_order_btn">Batalkan Pesanan </string>
<string name="claim_complaint">Ajukan Komplain </string>
<string name="claim_order">Pesanan Diterima </string>
<string name="add_review">Beri Ulasan </string>
</resources>