blob: 55a3be632aad01a923d0f32098a9f731fb2fe32d (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
package net.taler.merchantpos.order
import android.util.Log
import androidx.annotation.UiThread
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations.map
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import net.taler.merchantpos.Amount.Companion.fromString
import net.taler.merchantpos.config.ConfigurationReceiver
import net.taler.merchantpos.order.RestartState.DISABLED
import net.taler.merchantpos.order.RestartState.ENABLED
import net.taler.merchantpos.order.RestartState.UNDO
import org.json.JSONObject
enum class RestartState { ENABLED, DISABLED, UNDO }
class OrderManager(private val mapper: ObjectMapper) : ConfigurationReceiver {
companion object {
val TAG = OrderManager::class.java.simpleName
}
private val productsByCategory = HashMap<Category, ArrayList<Product>>()
private val mOrder = MutableLiveData<Order>()
private val newOrder // an empty order containing only available categories
get() = Order(productsByCategory.keys.map { it.id to it }.toMap())
internal val order: LiveData<Order> = mOrder
internal val orderTotal: LiveData<Double> = map(mOrder) { it.total }
private val mProducts = MutableLiveData<List<Product>>()
internal val products: LiveData<List<Product>> = mProducts
private val mCategories = MutableLiveData<List<Category>>()
internal val categories: LiveData<List<Category>> = mCategories
private var undoOrder: Order? = null
private val mRestartState = MutableLiveData<RestartState>().apply { value = DISABLED }
internal val restartState: LiveData<RestartState> = mRestartState
@Suppress("BlockingMethodInNonBlockingContext") // run on Dispatchers.Main
override suspend fun onConfigurationReceived(json: JSONObject, currency: String): Boolean {
// parse categories
val categoriesStr = json.getJSONArray("categories").toString()
val categoriesType = object : TypeReference<List<Category>>() {}
val categories: List<Category> = mapper.readValue(categoriesStr, categoriesType)
if (categories.isEmpty()) {
Log.e(TAG, "No valid category found.")
return false
}
// pre-select the first category
categories[0].selected = true
// parse products (live data gets updated in setCurrentCategory())
val productsStr = json.getJSONArray("products").toString()
val productsType = object : TypeReference<List<Product>>() {}
val products: List<Product> = mapper.readValue(productsStr, productsType)
// group products by categories
productsByCategory.clear()
products.forEach { product ->
val productCurrency = fromString(product.price).currency
if (productCurrency != currency) {
Log.e(TAG, "Product $product has currency $productCurrency, $currency expected")
return false
}
product.categories.forEach { categoryId ->
val category = categories.find { it.id == categoryId }
if (category == null) {
Log.e(TAG, "Product $product has unknown category $categoryId")
return false
}
if (productsByCategory.containsKey(category)) {
productsByCategory[category]?.add(product)
} else {
productsByCategory[category] = ArrayList<Product>().apply { add(product) }
}
}
}
return if (productsByCategory.size > 0) {
mCategories.postValue(categories)
mProducts.postValue(productsByCategory[categories[0]])
true
} else {
false
}
}
internal fun setCurrentCategory(category: Category) {
val newCategories = categories.value?.apply {
forEach { if (it.selected) it.selected = false }
category.selected = true
}
mCategories.postValue(newCategories)
mProducts.postValue(productsByCategory[category])
}
@UiThread
internal fun addProduct(product: Product) {
val order = mOrder.value ?: newOrder
mOrder.value = order + product
mRestartState.value = ENABLED
}
@UiThread
internal fun restartOrUndo() {
if (restartState.value == UNDO) {
mOrder.value = undoOrder
mRestartState.value = ENABLED
undoOrder = null
} else {
undoOrder = mOrder.value
mOrder.value = newOrder
mRestartState.value = UNDO
}
}
}
|