Skip to content

Commit ca27942

Browse files
authored
Add Discount model (#60)
* Add Discount model * Add a helper function * Add new columns to receiptline * Add migration
1 parent f7a8f7f commit ca27942

File tree

17 files changed

+399
-4
lines changed

17 files changed

+399
-4
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package eu.pretix.libpretixsync.models
2+
3+
import java.math.BigDecimal
4+
import java.time.OffsetDateTime
5+
6+
data class Discount(
7+
val id: Long,
8+
val serverId: Long,
9+
val eventSlug: String,
10+
val active: Boolean,
11+
val position: Long,
12+
val allSalesChannels: Boolean,
13+
val limitSalesChannels: List<String>,
14+
val availableFrom: OffsetDateTime? = null,
15+
val availableUntil: OffsetDateTime? = null,
16+
val subeventMode: DiscountSubeventMode,
17+
val subeventDateFrom: OffsetDateTime? = null,
18+
val subeventDateUntil: OffsetDateTime? = null,
19+
val conditionAllProducts: Boolean,
20+
val conditionLimitProducts: List<Long>,
21+
val conditionApplyToAddons: Boolean,
22+
val conditionIgnoreVoucherDiscounted: Boolean,
23+
val conditionMinCount: Int,
24+
val conditionMinValue: BigDecimal,
25+
val benefitSameProducts: Boolean,
26+
val benefitLimitProducts: List<Long>,
27+
val benefitDiscountMatchingPercent: BigDecimal,
28+
val benefitOnlyApplyToCheapestNMatches: Int?,
29+
val benefitApplyToAddons: Boolean,
30+
val benefitIgnoreVoucherDiscounted: Boolean,
31+
) {
32+
enum class DiscountSubeventMode {
33+
MIXED,
34+
SAME,
35+
DISTINCT
36+
}
37+
38+
companion object {
39+
/**
40+
* only for use in test, not in production code, since the defaults might change server-side
41+
* and we should not rely on them
42+
*/
43+
fun withDefaults(
44+
id: Long = 1L,
45+
serverId: Long = 1L,
46+
eventSlug: String = "democon",
47+
active: Boolean = true,
48+
position: Long = 1L,
49+
allSalesChannels: Boolean = true,
50+
limitSalesChannels: List<String> = emptyList(),
51+
availableFrom: OffsetDateTime? = null,
52+
availableUntil: OffsetDateTime? = null,
53+
subeventMode: DiscountSubeventMode = DiscountSubeventMode.MIXED,
54+
subeventDateFrom: OffsetDateTime? = null,
55+
subeventDateUntil: OffsetDateTime? = null,
56+
conditionAllProducts: Boolean = true,
57+
conditionLimitProducts: List<Long> = emptyList(),
58+
conditionApplyToAddons: Boolean = true,
59+
conditionIgnoreVoucherDiscounted: Boolean = false,
60+
conditionMinCount: Int = 0,
61+
conditionMinValue: BigDecimal = BigDecimal("0.00"),
62+
benefitSameProducts: Boolean = true,
63+
benefitLimitProducts: List<Long> = emptyList(),
64+
benefitDiscountMatchingPercent: BigDecimal = BigDecimal("0.00"),
65+
benefitOnlyApplyToCheapestNMatches: Int? = null,
66+
benefitApplyToAddons: Boolean = true,
67+
benefitIgnoreVoucherDiscounted: Boolean = false,
68+
): Discount {
69+
return Discount(
70+
id = id,
71+
serverId = serverId,
72+
eventSlug = eventSlug,
73+
active = active,
74+
position = position,
75+
allSalesChannels = allSalesChannels,
76+
limitSalesChannels = limitSalesChannels,
77+
availableFrom = availableFrom,
78+
availableUntil = availableUntil,
79+
subeventMode = subeventMode,
80+
subeventDateFrom = subeventDateFrom,
81+
subeventDateUntil = subeventDateUntil,
82+
conditionAllProducts = conditionAllProducts,
83+
conditionLimitProducts = conditionLimitProducts,
84+
conditionApplyToAddons = conditionApplyToAddons,
85+
conditionIgnoreVoucherDiscounted = conditionIgnoreVoucherDiscounted,
86+
conditionMinCount = conditionMinCount,
87+
conditionMinValue = conditionMinValue,
88+
benefitSameProducts = benefitSameProducts,
89+
benefitLimitProducts = benefitLimitProducts,
90+
benefitDiscountMatchingPercent = benefitDiscountMatchingPercent,
91+
benefitOnlyApplyToCheapestNMatches = benefitOnlyApplyToCheapestNMatches,
92+
benefitApplyToAddons = benefitApplyToAddons,
93+
benefitIgnoreVoucherDiscounted = benefitIgnoreVoucherDiscounted
94+
)
95+
}
96+
}
97+
}

libpretixsync/src/main/java/eu/pretix/libpretixsync/models/ReceiptLine.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ data class ReceiptLine(
4949
val giftCardId: Long? = null,
5050
val giftCardSecret: String? = null,
5151
val priceCalculatedFromNet: Boolean = false,
52+
val linePriceGross: BigDecimal,
53+
val discountId: Long? = null
5254
) {
5355
enum class Type(val value: String) {
5456
PRODUCT_SALE("PRODUCT_SALE"),
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package eu.pretix.libpretixsync.models.db
2+
3+
import eu.pretix.libpretixsync.models.Discount.DiscountSubeventMode
4+
import eu.pretix.libpretixsync.sqldelight.Discount
5+
import eu.pretix.libpretixsync.sqldelight.SafeOffsetDateTimeMapper
6+
import org.json.JSONArray
7+
import org.json.JSONObject
8+
import java.math.BigDecimal
9+
import eu.pretix.libpretixsync.models.Discount as DiscountModel
10+
11+
fun Discount.toModel(): DiscountModel {
12+
val json = JSONObject(this.json_data)
13+
14+
return DiscountModel(
15+
id = this.id,
16+
serverId = this.server_id,
17+
eventSlug = this.event_slug,
18+
active = this.active,
19+
position = this.position,
20+
allSalesChannels = json.optBoolean("all_sales_channels", false),
21+
limitSalesChannels = if (json.has("limit_sales_channels")) {
22+
jsonArrayToStringList(json.getJSONArray("limit_sales_channels"))
23+
} else if (json.has("sales_channels")) { // legacy pretix
24+
jsonArrayToStringList(json.getJSONArray("sales_channels"))
25+
} else {
26+
emptyList()
27+
},
28+
availableFrom = SafeOffsetDateTimeMapper.decode(json, "available_from"),
29+
availableUntil = SafeOffsetDateTimeMapper.decode(json, "available_until"),
30+
subeventMode = when (json.getString("subevent_mode")) {
31+
"mixed" -> DiscountSubeventMode.MIXED
32+
"same" -> DiscountSubeventMode.SAME
33+
"distinct" -> DiscountSubeventMode.DISTINCT
34+
else -> DiscountSubeventMode.MIXED
35+
},
36+
subeventDateFrom = SafeOffsetDateTimeMapper.decode(json, "subevent_date_from"),
37+
subeventDateUntil = SafeOffsetDateTimeMapper.decode(json, "subevent_date_until"),
38+
conditionAllProducts = json.getBoolean("condition_all_products"),
39+
conditionLimitProducts = jsonArrayToLongList(json.getJSONArray("condition_limit_products")),
40+
conditionApplyToAddons = json.getBoolean("condition_apply_to_addons"),
41+
conditionIgnoreVoucherDiscounted = json.getBoolean("condition_ignore_voucher_discounted"),
42+
conditionMinCount = json.getInt("condition_min_count"),
43+
conditionMinValue = BigDecimal(json.getString("condition_min_value")),
44+
benefitSameProducts = json.optBoolean("benefit_same_products", true),
45+
benefitLimitProducts = jsonArrayToLongList(json.optJSONArray("benefit_limit_products")),
46+
benefitDiscountMatchingPercent = BigDecimal(json.getString("benefit_discount_matching_percent")),
47+
benefitOnlyApplyToCheapestNMatches = if (json.isNull("benefit_only_apply_to_cheapest_n_matches"))
48+
null
49+
else
50+
json.getInt("benefit_only_apply_to_cheapest_n_matches"),
51+
benefitApplyToAddons = json.optBoolean("benefit_apply_to_addons", false),
52+
benefitIgnoreVoucherDiscounted = json.optBoolean("benefit_ignore_voucher_discounted", true),
53+
)
54+
}
55+
56+
private fun jsonArrayToLongList(jsonArray: JSONArray?): List<Long> {
57+
if (jsonArray == null) return emptyList()
58+
return (0 until jsonArray.length()).map {
59+
jsonArray.getLong(it)
60+
}
61+
}
62+
63+
private fun jsonArrayToStringList(jsonArray: JSONArray?): List<String> {
64+
if (jsonArray == null) return emptyList()
65+
return (0 until jsonArray.length()).map {
66+
jsonArray.getString(it)
67+
}
68+
}

libpretixsync/src/main/java/eu/pretix/libpretixsync/models/db/ReceiptLineExtensions.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,6 @@ fun ReceiptLine.toModel() =
4848
giftCardId = gift_card_id,
4949
giftCardSecret = gift_card_secret,
5050
priceCalculatedFromNet = price_calculated_from_net == true,
51+
linePriceGross = line_price_gross ?: price,
52+
discountId = discount_id,
5153
)

libpretixsync/src/main/java/eu/pretix/libpretixsync/sqldelight/ReceiptLineExtensions.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,7 @@ fun ReceiptLine.toJSON(): JSONObject {
5353
jo.put("use_reusable_medium", use_reusable_medium)
5454
jo.put("gift_card", gift_card_id)
5555
jo.put("gift_card_secret", gift_card_secret)
56+
jo.put("line_price_gross", line_price_gross ?: JSONObject.NULL)
57+
jo.put("discount", discount_id ?: JSONObject.NULL)
5658
return jo
5759
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package eu.pretix.libpretixsync.sync
2+
3+
import app.cash.sqldelight.TransactionWithoutReturn
4+
import app.cash.sqldelight.db.QueryResult
5+
import eu.pretix.libpretixsync.api.PretixApi
6+
import eu.pretix.libpretixsync.sqldelight.Discount
7+
import eu.pretix.libpretixsync.sqldelight.SyncDatabase
8+
import eu.pretix.libpretixsync.sync.SyncManager.ProgressFeedback
9+
import org.joda.time.format.ISODateTimeFormat
10+
import org.json.JSONObject
11+
12+
class DiscountSyncAdapter(
13+
db: SyncDatabase,
14+
fileStorage: FileStorage,
15+
eventSlug: String,
16+
api: PretixApi,
17+
syncCycleId: String,
18+
feedback: ProgressFeedback?,
19+
) : BaseConditionalSyncAdapter<Discount, Long>(
20+
db = db,
21+
fileStorage = fileStorage,
22+
eventSlug = eventSlug,
23+
api = api,
24+
syncCycleId = syncCycleId,
25+
feedback = feedback,
26+
) {
27+
28+
override fun getResourceName(): String = "discounts"
29+
30+
override fun getId(obj: Discount): Long = obj.server_id!!
31+
32+
override fun getId(obj: JSONObject): Long = obj.getLong("id")
33+
34+
override fun getJSON(obj: Discount): JSONObject = JSONObject(obj.json_data)
35+
36+
override fun queryKnownIDs(): MutableSet<Long> {
37+
val res = mutableSetOf<Long>()
38+
db.discountQueries.selectServerIdsByEventSlug(eventSlug)
39+
.execute { cursor ->
40+
while (cursor.next().value) {
41+
val id = cursor.getLong(0)
42+
?: throw RuntimeException("server_id column not available")
43+
44+
res.add(id)
45+
}
46+
QueryResult.Unit
47+
}
48+
49+
return res
50+
}
51+
52+
override fun insert(jsonobj: JSONObject) {
53+
val availableFrom = if (!jsonobj.isNull("available_from")) {
54+
ISODateTimeFormat.dateTimeParser().parseDateTime(jsonobj.getString("available_from")).toDate()
55+
} else {
56+
null
57+
}
58+
val availableUntil = if (!jsonobj.isNull("available_until")) {
59+
ISODateTimeFormat.dateTimeParser().parseDateTime(jsonobj.getString("available_until")).toDate()
60+
} else {
61+
null
62+
}
63+
db.discountQueries.insert(
64+
server_id = jsonobj.getLong("id"),
65+
event_slug = eventSlug,
66+
active = jsonobj.getBoolean("active"),
67+
available_from = availableFrom,
68+
available_until = availableUntil,
69+
position = jsonobj.getLong("position"),
70+
json_data = jsonobj.toString(),
71+
)
72+
}
73+
74+
override fun update(obj: Discount, jsonobj: JSONObject) {
75+
val availableFrom = if (!jsonobj.isNull("available_from")) {
76+
ISODateTimeFormat.dateTimeParser().parseDateTime(jsonobj.getString("available_from")).toDate()
77+
} else {
78+
null
79+
}
80+
val availableUntil = if (!jsonobj.isNull("available_until")) {
81+
ISODateTimeFormat.dateTimeParser().parseDateTime(jsonobj.getString("available_until")).toDate()
82+
} else {
83+
null
84+
}
85+
db.discountQueries.updateFromJson(
86+
event_slug = eventSlug,
87+
active = jsonobj.getBoolean("active"),
88+
available_from = availableFrom,
89+
available_until = availableUntil,
90+
position = jsonobj.getLong("position"),
91+
json_data = jsonobj.toString(),
92+
id = obj.id,
93+
)
94+
}
95+
96+
override fun delete(key: Long) {
97+
db.discountQueries.deleteByServerId(key)
98+
}
99+
100+
override fun runInTransaction(body: TransactionWithoutReturn.() -> Unit) {
101+
db.discountQueries.transaction(false, body)
102+
}
103+
104+
override fun runBatch(parameterBatch: List<Long>): List<Discount> =
105+
db.discountQueries.selectByServerIdListAndEventSlug(
106+
server_id = parameterBatch,
107+
event_slug = eventSlug,
108+
).executeAsList()
109+
}

libpretixsync/src/main/java/eu/pretix/libpretixsync/sync/SyncManager.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ protected void downloadData(ProgressFeedback feedback, Boolean skip_orders, Stri
412412
download(new ItemSyncAdapter(db, fileStorage, eventSlug, api, configStore.getSyncCycleId(), feedback));
413413
download(new QuestionSyncAdapter(db, fileStorage, eventSlug, api, configStore.getSyncCycleId(), feedback));
414414
if (profile == Profile.PRETIXPOS) {
415+
download(new DiscountSyncAdapter(db, fileStorage, eventSlug, api, configStore.getSyncCycleId(), feedback));
415416
download(new QuotaSyncAdapter(db, fileStorage, eventSlug, api, configStore.getSyncCycleId(), feedback, subEvent));
416417
download(new TaxRuleSyncAdapter(db, fileStorage, eventSlug, api, configStore.getSyncCycleId(), feedback));
417418
download(new TicketLayoutSyncAdapter(db, fileStorage, eventSlug, api, configStore.getSyncCycleId(), feedback, salesChannel));
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
selectById:
2+
SELECT *
3+
FROM Discount
4+
WHERE id = ?;
5+
6+
selectByServerId:
7+
SELECT *
8+
FROM Discount
9+
WHERE server_id = ?;
10+
11+
selectByEventSlug:
12+
SELECT *
13+
FROM Discount
14+
WHERE event_slug = ?;
15+
16+
selectByServerIdListAndEventSlug:
17+
SELECT *
18+
FROM Discount
19+
WHERE server_id IN ? AND event_slug = ?;
20+
21+
selectServerIdsByEventSlug:
22+
SELECT server_id
23+
FROM Discount
24+
WHERE event_slug = ?;
25+
26+
deleteByServerId:
27+
DELETE FROM Discount
28+
WHERE server_id = ?;
29+
30+
insert:
31+
INSERT INTO Discount
32+
(
33+
server_id,
34+
event_slug,
35+
active,
36+
available_from,
37+
available_until,
38+
"position",
39+
json_data
40+
)
41+
VALUES (
42+
?,
43+
?,
44+
?,
45+
?,
46+
?,
47+
?,
48+
?
49+
);
50+
51+
updateFromJson:
52+
UPDATE Discount
53+
SET
54+
event_slug = ?,
55+
active = ?,
56+
available_from = ?,
57+
available_until = ?,
58+
"position" = ?,
59+
json_data = ?
60+
WHERE id = ?;

libpretixsync/src/main/sqldelight/common/eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ INSERT INTO ReceiptLine (
5858
type,
5959
use_reusable_medium,
6060
variation_id,
61-
voucher_code
61+
voucher_code,
62+
line_price_gross,
63+
discount_id
6264
)
6365
VALUES (
6466
?,
@@ -104,5 +106,7 @@ VALUES (
104106
?,
105107
?,
106108
?,
109+
?,
110+
?,
107111
?
108112
);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
CREATE INDEX receipt_server_id ON Receipt(server_id);
1+
CREATE INDEX receipt_server_id ON Receipt(server_id);

0 commit comments

Comments
 (0)