diff --git a/.idea/misc.xml b/.idea/misc.xml
index f1044879e31aa73a3e757a2f81a68e7c26bd222a..d7916a51794ccbea94e1583ffbde18195a4950cc 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="ExternalStorageConfigurationManager" enabled="true" />
   <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
diff --git a/app/src/main/java/com/atm/bondowowo/data/model/ScanRequest.kt b/app/src/main/java/com/atm/bondowowo/data/model/ScanRequest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..dcb80dd8a4f59d0b3454d46599dce8ddde61fbd8
--- /dev/null
+++ b/app/src/main/java/com/atm/bondowowo/data/model/ScanRequest.kt
@@ -0,0 +1,8 @@
+package com.atm.bondowowo.data.model
+
+import okhttp3.MultipartBody
+
+
+data class ScanRequest(
+    val file: MultipartBody.Part,
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/atm/bondowowo/data/model/ScanResponse.kt b/app/src/main/java/com/atm/bondowowo/data/model/ScanResponse.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5161a9bc60de19bf293fcb2bcc7a12bab8483b22
--- /dev/null
+++ b/app/src/main/java/com/atm/bondowowo/data/model/ScanResponse.kt
@@ -0,0 +1,15 @@
+package com.atm.bondowowo.data.model
+
+data class ScanResponse(
+    val items: ItemsWrapper
+)
+
+data class ItemsWrapper(
+    val items: List<ScanItemData>
+)
+
+data class ScanItemData(
+    val name: String,
+    val qty: Int,
+    val price: Double
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/atm/bondowowo/data/remote/ApiService.kt b/app/src/main/java/com/atm/bondowowo/data/remote/ApiService.kt
index a1a54404537b435ace213c5fa017bd0f236b989e..6acc07b1068a6bf8363fe04fb1f0242579b25782 100644
--- a/app/src/main/java/com/atm/bondowowo/data/remote/ApiService.kt
+++ b/app/src/main/java/com/atm/bondowowo/data/remote/ApiService.kt
@@ -2,11 +2,16 @@ package com.atm.bondowowo.data.remote
 
 import com.atm.bondowowo.data.model.LoginRequest
 import com.atm.bondowowo.data.model.LoginResponse
+import com.atm.bondowowo.data.model.ScanRequest
+import com.atm.bondowowo.data.model.ScanResponse
 import com.atm.bondowowo.data.model.VerifyResponse
+import okhttp3.MultipartBody
 import retrofit2.Response
 import retrofit2.http.Body
 import retrofit2.http.Header
+import retrofit2.http.Multipart
 import retrofit2.http.POST
+import retrofit2.http.Part
 
 interface ApiService {
     @POST("api/auth/login")
@@ -14,4 +19,11 @@ interface ApiService {
 
     @POST("api/auth/token")
     suspend fun verifyToken(@Header("Authorization") jwtToken: String): Response<Any>
+
+    @Multipart
+    @POST("api/bill/upload")
+    suspend fun uploadScan(
+        @Header("Authorization") jwtToken: String,
+        @Part file: MultipartBody.Part
+    ): Response<ScanResponse>
 }
diff --git a/app/src/main/java/com/atm/bondowowo/ui/scan/ScanFragment.kt b/app/src/main/java/com/atm/bondowowo/ui/scan/ScanFragment.kt
index 760f78a17a8c9f837a714d41f0a7a558ecd9f047..2edfe3ca20816511b1b9952ff9a7514e07b5c1e3 100644
--- a/app/src/main/java/com/atm/bondowowo/ui/scan/ScanFragment.kt
+++ b/app/src/main/java/com/atm/bondowowo/ui/scan/ScanFragment.kt
@@ -9,6 +9,7 @@ import android.graphics.Bitmap
 import android.graphics.BitmapFactory
 import android.net.Uri
 import android.os.Bundle
+import android.os.Environment
 import android.provider.MediaStore
 import android.util.Log
 import android.view.LayoutInflater
@@ -21,32 +22,41 @@ import androidx.activity.result.contract.ActivityResultContracts
 import androidx.core.app.ActivityCompat
 import androidx.core.content.ContextCompat
 import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
 import com.atm.bondowowo.R
+import com.atm.bondowowo.data.local.database.AppDatabase
+import com.atm.bondowowo.data.repository.TransactionRepository
 import com.atm.bondowowo.ui.twibbon.TwibbonActivity
+import com.atm.bondowowo.utils.UserPreferencesUtil
 import com.budiyev.android.codescanner.CodeScanner
 import com.budiyev.android.codescanner.CodeScannerView
 import com.budiyev.android.codescanner.DecodeCallback
 import com.google.zxing.BinaryBitmap
-import com.google.zxing.ChecksumException
-import com.google.zxing.FormatException
 import com.google.zxing.LuminanceSource
 import com.google.zxing.MultiFormatReader
-import com.google.zxing.NotFoundException
 import com.google.zxing.RGBLuminanceSource
 import com.google.zxing.Reader
 import com.google.zxing.common.HybridBinarizer
+import okhttp3.MediaType
+import okhttp3.MultipartBody
+import okhttp3.RequestBody
 import java.io.BufferedInputStream
 import java.io.File
 import java.io.FileInputStream
+import java.io.FileOutputStream
+import java.io.IOException
 import java.io.InputStream
 
 class ScanFragment : Fragment() {
+    private lateinit var scanViewModel: ScanViewModel
+
     private lateinit var tvResult: TextView
     private var WRITE_EXTERNAL_STORAGE_PERMISSION_CODE: Int = 1
     private var READ_EXTERNAL_STORAGE_PERMISSION_CODE: Int = 2
 
     private val CAMERA_PERMISSION_REQUEST_CODE = 100
     private lateinit var codeScanner: CodeScanner
+    private lateinit var scannedFile: File
 
     override fun onCreateView(
         inflater: LayoutInflater,
@@ -58,6 +68,10 @@ class ScanFragment : Fragment() {
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
+        val database = AppDatabase.getInstance(requireContext())
+        val transactionRepository = TransactionRepository(database)
+        val scanViewModelFactory = ScanViewModelFactory(transactionRepository)
+        scanViewModel = ViewModelProvider(this, scanViewModelFactory)[ScanViewModel::class.java]
         val scannerView = view.findViewById<CodeScannerView>(R.id.scanner)
         tvResult = view.findViewById(R.id.tv_result) //
 
@@ -154,18 +168,28 @@ class ScanFragment : Fragment() {
             requireActivity().runOnUiThread {
                 val contents = it.text
                 tvResult.text = contents
-                Toast.makeText(requireContext(), "Scanned: ${it.text}", Toast.LENGTH_LONG).show()
-
-                val scanOptions = arrayOf<String>("Ya", "Tidak")
-                AlertDialog.Builder(requireContext())
-                    .setTitle("Scan Berhasil!\nApakah ingin mengulagi proses Scan?")
-                    .setItems(scanOptions) { _, which ->
-                        when (which) {
-                            0 -> codeScanner.startPreview()
-                            1 -> setToTransaction()
+                val convertedFile = saveByteArrayToFile(it.rawBytes)
+                if (convertedFile !== null) {
+                    scannedFile = convertedFile
+                    Toast.makeText(requireContext(), "Scanned: ${it.text}", Toast.LENGTH_LONG)
+                        .show()
+                    val scanOptions = arrayOf<String>("Ya", "Tidak")
+                    AlertDialog.Builder(requireContext())
+                        .setTitle("Scan Berhasil!\nApakah ingin menyimpan\n proses scan?")
+                        .setItems(scanOptions) { _, which ->
+                            when (which) {
+                                0 -> setToTransaction()
+                                1 -> codeScanner.startPreview()
+                            }
                         }
-                    }
-                    .create().show()
+                        .create().show()
+                } else {
+                    Toast.makeText(
+                        requireContext(),
+                        "Failed to capture Image, please retry",
+                        Toast.LENGTH_SHORT
+                    ).show()
+                }
             }
         }
         scannerView.setOnClickListener {
@@ -174,8 +198,19 @@ class ScanFragment : Fragment() {
     }
 
     private fun setToTransaction() {
-        Log.d("TODO", "next to transaction")
-        TODO("Not yet implemented")
+        val tokenJWT = UserPreferencesUtil.getJWT(requireContext())
+        val requestFile = RequestBody.create(MediaType.parse("image/*"), scannedFile)
+        val imagePart = MultipartBody.Part.createFormData("file", scannedFile.name, requestFile)
+        if (tokenJWT != null) {
+            scanViewModel.uploadScan(tokenJWT, imagePart, requireContext(), scannedFile)
+        } else {
+            Toast.makeText(
+                requireContext(),
+                "Unable to get auth, please Log In again",
+                Toast.LENGTH_SHORT
+            ).show()
+        }
+
     }
 
     private fun openGallery() {
@@ -194,6 +229,7 @@ class ScanFragment : Fragment() {
                 val imagePath = convertMediaUriToPath(imageUri)
                 Log.d("ScanFragment", "Berhasil convertMediaUriToPath")
                 val imgFile = File(imagePath)
+                scannedFile = imgFile
                 scanImageQRCode(imgFile)
                 Log.d("ScanFragment", "Berhasil scanImageQRCode")
             } else {
@@ -212,6 +248,7 @@ class ScanFragment : Fragment() {
     }
 
     private fun scanImageQRCode(file: File) {
+        scannedFile = file
         val inputStream: InputStream = BufferedInputStream(FileInputStream(file))
         val bitmap = BitmapFactory.decodeStream(inputStream)
         val decoded = scanQRImage(bitmap)
@@ -230,8 +267,6 @@ class ScanFragment : Fragment() {
             val result: com.google.zxing.Result = reader.decode(bitmap)
             Log.d("scanQRImage", "berhasil yang bagian Result")
             contents = result.text
-            // TODO MASUKIN BE DISINI
-
             tvResult.text = contents
 
             val scanOptions = arrayOf<String>("Ya", "Tidak")
@@ -256,4 +291,22 @@ class ScanFragment : Fragment() {
         return contents
     }
 
+    fun saveByteArrayToFile(byteArray: ByteArray): File? {
+        val directory =
+            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
+        val fileName = "temp_image_${System.currentTimeMillis()}.png" // Unique filename
+        val file = File(directory, fileName)
+
+        try {
+            val outputStream = FileOutputStream(file)
+            outputStream.write(byteArray)
+            outputStream.flush()
+            outputStream.close()
+            return file
+        } catch (e: IOException) {
+            e.printStackTrace()
+        }
+        return null
+    }
+
 }
diff --git a/app/src/main/java/com/atm/bondowowo/ui/scan/ScanViewModel.kt b/app/src/main/java/com/atm/bondowowo/ui/scan/ScanViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1de35898dc56e7d5fd9957b9165ce90ddfed1b2e
--- /dev/null
+++ b/app/src/main/java/com/atm/bondowowo/ui/scan/ScanViewModel.kt
@@ -0,0 +1,83 @@
+package com.atm.bondowowo.ui.scan
+
+import android.content.Context
+import android.widget.Toast
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.atm.bondowowo.data.model.ScanItemData
+import com.atm.bondowowo.data.model.Transaction
+import com.atm.bondowowo.data.repository.TransactionRepository
+import com.atm.bondowowo.utils.NetworkUtils
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import okhttp3.MultipartBody
+import java.io.File
+import java.time.LocalDateTime
+
+class ScanViewModel(
+    private val transactionRepository: TransactionRepository
+) : ViewModel() {
+    fun uploadScan(tokenJWT: String, imagePart: MultipartBody.Part, context: Context, file: File) {
+        viewModelScope.launch {
+            try {
+                val response = withContext(Dispatchers.IO) {
+                    tokenJWT.let {
+                        NetworkUtils.apiService.uploadScan(
+                            "Bearer $it",
+                            imagePart
+                        )
+                    }
+                }
+                if (response.isSuccessful) {
+                    val scanResponse = response.body()?.items?.items
+                    val scanTransaction = scanResponse?.let { convertFromScanResponse(it) }
+                    if (scanTransaction != null) {
+                        transactionRepository.insertTransaction(scanTransaction)
+                        Toast.makeText(
+                            context,
+                            "Successfully new transaction",
+                            Toast.LENGTH_SHORT
+                        ).show()
+                    } else {
+                        Toast.makeText(
+                            context,
+                            "Unable to add data to phone storage",
+                            Toast.LENGTH_SHORT
+                        ).show()
+                    }
+                } else {
+                    Toast.makeText(
+                        context,
+                        "Failed, please re-Login",
+                        Toast.LENGTH_SHORT
+                    ).show()
+                }
+                file.delete()
+            } catch (e: Exception) {
+                e.printStackTrace()
+                Toast.makeText(context, "Unable to connect server...", Toast.LENGTH_SHORT)
+                    .show()
+            }
+
+        }
+    }
+
+    private fun convertFromScanResponse(itemList: List<ScanItemData>): Transaction {
+        val name = "Transaksi - " + itemList.map { it.name }.joinToString(", ")
+        val kategori = if (itemList.size % 2 == 0) {
+            "pemasukan"
+        } else {
+            "pengeluaran"
+        }
+        val nominal = itemList.fold(0.0) { acc, item -> acc + (item.qty * item.price) }
+        return Transaction(
+            null,
+            nama = name,
+            date = LocalDateTime.now(),
+            kategori = kategori,
+            nominal = nominal,
+            lokasi = "Toko ${itemList[0].name}"
+        )
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/atm/bondowowo/ui/scan/ScanViewModelFactory.kt b/app/src/main/java/com/atm/bondowowo/ui/scan/ScanViewModelFactory.kt
new file mode 100644
index 0000000000000000000000000000000000000000..92b08dd6755da5852a939070354dff454bc28152
--- /dev/null
+++ b/app/src/main/java/com/atm/bondowowo/ui/scan/ScanViewModelFactory.kt
@@ -0,0 +1,19 @@
+package com.atm.bondowowo.ui.scan
+
+import com.atm.bondowowo.ui.scan.ScanViewModel
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.atm.bondowowo.data.repository.TransactionRepository
+
+class ScanViewModelFactory(
+    private val transactionRepository: TransactionRepository
+) : ViewModelProvider.Factory {
+
+    override fun <T : ViewModel> create(modelClass: Class<T>): T {
+        if (modelClass.isAssignableFrom(ScanViewModel::class.java)) {
+            @Suppress("UNCHECKED_CAST")
+            return ScanViewModel(transactionRepository) as T
+        }
+        throw IllegalArgumentException("Unknown ViewModel class")
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/atm/bondowowo/ui/transaction/TransactionInputFragment.kt b/app/src/main/java/com/atm/bondowowo/ui/transaction/TransactionInputFragment.kt
index e282b1b82785bef4f3f7f6c0cd8c0b0a86ecbd1c..cc2709cbd1508dd8460dad2e4163949c8a07aa4e 100644
--- a/app/src/main/java/com/atm/bondowowo/ui/transaction/TransactionInputFragment.kt
+++ b/app/src/main/java/com/atm/bondowowo/ui/transaction/TransactionInputFragment.kt
@@ -112,6 +112,7 @@ class TransactionInputFragment : Fragment() {
         this.listener = listener
     }
 
+    // Failed still broadcast reciever
     private val inputValueReceiver = object : BroadcastReceiver() {
         override fun onReceive(context: Context, intent: Intent) {
             if (intent.action == "com.atm.bondowowo.RANDOM_INPUT_TRANSACTION") {