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
121
122
123
124
125
126
127
|
/*
* 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.order
import net.taler.common.Amount
import net.taler.common.ContractTerms
import net.taler.common.now
import net.taler.merchantpos.config.Category
import net.taler.merchantpos.config.ConfigProduct
import java.net.URLEncoder
private const val FULFILLMENT_PREFIX = "taler://fulfillment-success/"
data class Order(val id: Int, val currency: String, val availableCategories: Map<Int, Category>) {
val products = ArrayList<ConfigProduct>()
val title: String = id.toString()
val summary: String
get() {
if (products.size == 1) return products[0].description
return getCategoryQuantities().map { (category: Category, quantity: Int) ->
"$quantity x ${category.localizedName}"
}.joinToString()
}
val total: Amount
get() {
var total = Amount.zero(currency)
products.forEach { product ->
total += product.price * product.quantity
}
return total
}
operator fun plus(product: ConfigProduct): Order {
val i = products.indexOf(product)
if (i == -1) {
products.add(product.copy(quantity = 1))
} else {
val quantity = products[i].quantity
products[i] = products[i].copy(quantity = quantity + 1)
}
return this
}
operator fun minus(product: ConfigProduct): Order {
val i = products.indexOf(product)
if (i == -1) return this
val quantity = products[i].quantity
if (quantity <= 1) {
products.remove(product)
} else {
products[i] = products[i].copy(quantity = quantity - 1)
}
return this
}
private fun getCategoryQuantities(): HashMap<Category, Int> {
val categories = HashMap<Category, Int>()
products.forEach { product ->
val categoryId = product.categories[0]
val category = availableCategories.getValue(categoryId)
val oldQuantity = categories[category] ?: 0
categories[category] = oldQuantity + product.quantity
}
return categories
}
/**
* Returns a map of i18n summaries for each locale present in *all* given [Category]s
* or null if there's no locale that fulfills this criteria.
*/
val summaryI18n: Map<String, String>?
get() {
if (products.size == 1) return products[0].descriptionI18n
val categoryQuantities = getCategoryQuantities()
// get all available locales
val availableLocales = categoryQuantities.mapNotNull { (category, _) ->
val nameI18n = category.nameI18n
// if one category doesn't have locales, we can return null here already
nameI18n?.keys ?: return null
}.flatten().toHashSet()
// remove all locales not supported by all categories
categoryQuantities.forEach { (category, _) ->
// category.nameI18n should be non-null now
availableLocales.retainAll(category.nameI18n!!.keys)
if (availableLocales.isEmpty()) return null
}
return availableLocales.map { locale ->
Pair(
locale, categoryQuantities.map { (category, quantity) ->
// category.nameI18n should be non-null now
"$quantity x ${category.nameI18n!![locale]}"
}.joinToString()
)
}.toMap()
}
private val fulfillmentUri: String
get() {
val fulfillmentId = "${now()}-${hashCode()}"
return "$FULFILLMENT_PREFIX${URLEncoder.encode(summary, "UTF-8")}#$fulfillmentId"
}
fun toContractTerms(): ContractTerms {
return ContractTerms(
summary = summary,
summaryI18n = summaryI18n,
amount = total,
fulfillmentUrl = fulfillmentUri,
products = products.map { it.toContractProduct() }
)
}
}
|