From ca25ae82306a65775db6aed117cc55380ab4a2c4 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Fri, 30 Oct 2026 11:23:37 +0100 Subject: [PATCH] Add support for tax rounding --- .../src/main/java/eu/pretix/libpretixsync/models/Receipt.kt | 1 + .../main/java/eu/pretix/libpretixsync/models/ReceiptLine.kt | 6 ++++++ .../eu/pretix/libpretixsync/models/db/ReceiptExtensions.kt | 1 + .../pretix/libpretixsync/models/db/ReceiptLineExtensions.kt | 2 ++ .../eu/pretix/libpretixsync/sqldelight/ReceiptExtensions.kt | 1 + .../libpretixsync/sqldelight/ReceiptLineExtensions.kt | 2 ++ .../common/eu/pretix/libpretixsync/sqldelight/Receipt.sq | 4 +++- .../eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq | 4 ++++ .../postgres/eu/pretix/libpretixsync/sqldelight/Receipt.sq | 3 ++- .../eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq | 2 ++ .../src/main/sqldelight/postgres/migrations/121.sqm | 3 +++ .../sqlite/eu/pretix/libpretixsync/sqldelight/Receipt.sq | 3 ++- .../eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq | 3 +++ libpretixsync/src/main/sqldelight/sqlite/migrations/121.sqm | 5 +++++ .../java/eu/pretix/libpretixsync/db/BaseDatabaseTest.java | 2 ++ 15 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 libpretixsync/src/main/sqldelight/postgres/migrations/121.sqm create mode 100644 libpretixsync/src/main/sqldelight/sqlite/migrations/121.sqm diff --git a/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/Receipt.kt b/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/Receipt.kt index 46f9ed41..e046a525 100644 --- a/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/Receipt.kt +++ b/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/Receipt.kt @@ -29,6 +29,7 @@ data class Receipt( val closing: Long? = null, val additionalText: String? = null, val webSecret: String? = null, + val taxRoundingMode: String = "line", ) { enum class PaymentType(val value: String) { CASH("cash"), diff --git a/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/ReceiptLine.kt b/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/ReceiptLine.kt index ed5d0da4..6d0ccfa4 100644 --- a/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/ReceiptLine.kt +++ b/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/ReceiptLine.kt @@ -13,6 +13,7 @@ data class ReceiptLine( val positionId: Long, val type: Type, val price: BigDecimal, + val priceIncludesRoundingCorrection: BigDecimal = BigDecimal("0.00"), val listedPrice: BigDecimal? = null, val priceAfterVoucher: BigDecimal? = null, val customPriceInput: BigDecimal? = null, @@ -28,6 +29,7 @@ data class ReceiptLine( val taxRate: BigDecimal? = null, val taxRule: Long? = null, val taxValue: BigDecimal? = null, + val taxValueIncludesRoundingCorrection: BigDecimal = BigDecimal("0.00"), val taxCode: String? = null, val eventDateFrom: OffsetDateTime? = null, val eventDateTo: OffsetDateTime? = null, @@ -82,6 +84,10 @@ data class ReceiptLine( } } + val grossPriceBeforeRounding = price - priceIncludesRoundingCorrection + val taxValueBeforeRounding = (taxValue ?: BigDecimal.ZERO) - taxValueIncludesRoundingCorrection + val netPriceBeforeRounding = grossPriceBeforeRounding - (taxValueBeforeRounding ?: BigDecimal.ZERO) + val hasAttendeeData: Boolean get() = !attendeeName.isNullOrEmpty() || !attendeeEmail.isNullOrEmpty() || diff --git a/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/db/ReceiptExtensions.kt b/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/db/ReceiptExtensions.kt index a73428c4..13585f51 100644 --- a/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/db/ReceiptExtensions.kt +++ b/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/db/ReceiptExtensions.kt @@ -37,4 +37,5 @@ fun Receipt.toModel() = orderEmail = order_email, orderPhone = order_phone, webSecret = websecret, + taxRoundingMode = tax_rounding_mode, ) diff --git a/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/db/ReceiptLineExtensions.kt b/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/db/ReceiptLineExtensions.kt index a6ed510b..a780da26 100644 --- a/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/db/ReceiptLineExtensions.kt +++ b/libpretixsync/src/main/java/eu/pretix/libpretixsync/models/db/ReceiptLineExtensions.kt @@ -12,6 +12,7 @@ fun ReceiptLine.toModel() = positionId = positionid!!, type = ReceiptLineModel.Type.valueOf(type!!), price = price!!, + priceIncludesRoundingCorrection = price_includes_rounding_correction!!, listedPrice = listed_price, priceAfterVoucher = price_after_voucher, customPriceInput = custom_price_input, @@ -28,6 +29,7 @@ fun ReceiptLine.toModel() = taxCode = tax_code, taxRule = tax_rule, taxValue = tax_value, + taxValueIncludesRoundingCorrection = tax_value_includes_rounding_correction, eventDateFrom = SafeOffsetDateTimeMapper.decode(event_date_from), eventDateTo = SafeOffsetDateTimeMapper.decode(event_date_to), subEventServerId = subevent_id, diff --git a/libpretixsync/src/main/java/eu/pretix/libpretixsync/sqldelight/ReceiptExtensions.kt b/libpretixsync/src/main/java/eu/pretix/libpretixsync/sqldelight/ReceiptExtensions.kt index ca129820..d2040fca 100644 --- a/libpretixsync/src/main/java/eu/pretix/libpretixsync/sqldelight/ReceiptExtensions.kt +++ b/libpretixsync/src/main/java/eu/pretix/libpretixsync/sqldelight/ReceiptExtensions.kt @@ -64,6 +64,7 @@ fun Receipt.toJSON(): JSONObject { jo.put("training", training) jo.put("additional_text", additional_text) jo.put("web_secret", if (websecret != null) websecret else JSONObject.NULL) + jo.put("tax_rounding_mode", if (tax_rounding_mode != null) tax_rounding_mode else JSONObject.NULL) // the following columns are not persisted on the server, // but only used locally to act as holders of data diff --git a/libpretixsync/src/main/java/eu/pretix/libpretixsync/sqldelight/ReceiptLineExtensions.kt b/libpretixsync/src/main/java/eu/pretix/libpretixsync/sqldelight/ReceiptLineExtensions.kt index fb64de79..2a885048 100644 --- a/libpretixsync/src/main/java/eu/pretix/libpretixsync/sqldelight/ReceiptLineExtensions.kt +++ b/libpretixsync/src/main/java/eu/pretix/libpretixsync/sqldelight/ReceiptLineExtensions.kt @@ -17,8 +17,10 @@ fun ReceiptLine.toJSON(): JSONObject { jo.put("custom_price_input", custom_price_input?.setScale(2, RoundingMode.HALF_UP)) jo.put("voucher_code", voucher_code) jo.put("price", price?.setScale(2, RoundingMode.HALF_UP)) + jo.put("price_includes_rounding_correction", price_includes_rounding_correction?.setScale(2, RoundingMode.HALF_UP)) jo.put("tax_rate", tax_rate?.setScale(4, RoundingMode.HALF_UP)) jo.put("tax_value", tax_value?.setScale(2, RoundingMode.HALF_UP) ?: "0.00") + jo.put("tax_value_includes_rounding_correction", tax_value_includes_rounding_correction?.setScale(2, RoundingMode.HALF_UP) ?: "0.00") jo.put("tax_rule", tax_rule ?: JSONObject.NULL) jo.put("tax_code", tax_code ?: JSONObject.NULL) jo.put("secret", secret) diff --git a/libpretixsync/src/main/sqldelight/common/eu/pretix/libpretixsync/sqldelight/Receipt.sq b/libpretixsync/src/main/sqldelight/common/eu/pretix/libpretixsync/sqldelight/Receipt.sq index 09cce33e..5ec08b18 100644 --- a/libpretixsync/src/main/sqldelight/common/eu/pretix/libpretixsync/sqldelight/Receipt.sq +++ b/libpretixsync/src/main/sqldelight/common/eu/pretix/libpretixsync/sqldelight/Receipt.sq @@ -39,7 +39,8 @@ INSERT INTO Receipt ( server_id, started, training, - websecret + websecret, + tax_rounding_mode ) VALUES ( ?, @@ -69,6 +70,7 @@ VALUES ( ?, ?, ?, + ?, ? ); diff --git a/libpretixsync/src/main/sqldelight/common/eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq b/libpretixsync/src/main/sqldelight/common/eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq index 1be994e2..e723e7e9 100644 --- a/libpretixsync/src/main/sqldelight/common/eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq +++ b/libpretixsync/src/main/sqldelight/common/eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq @@ -40,6 +40,7 @@ INSERT INTO ReceiptLine ( listed_price, positionid, price, + price_includes_rounding_correction, price_after_voucher, price_calculated_from_net, receipt, @@ -54,6 +55,7 @@ INSERT INTO ReceiptLine ( tax_rate, tax_rule, tax_value, + tax_value_includes_rounding_correction, tax_code, type, use_reusable_medium, @@ -110,5 +112,7 @@ VALUES ( ?, ?, ?, + ?, + ?, ? ); \ No newline at end of file diff --git a/libpretixsync/src/main/sqldelight/postgres/eu/pretix/libpretixsync/sqldelight/Receipt.sq b/libpretixsync/src/main/sqldelight/postgres/eu/pretix/libpretixsync/sqldelight/Receipt.sq index 7e829dcf..7bb93595 100644 --- a/libpretixsync/src/main/sqldelight/postgres/eu/pretix/libpretixsync/sqldelight/Receipt.sq +++ b/libpretixsync/src/main/sqldelight/postgres/eu/pretix/libpretixsync/sqldelight/Receipt.sq @@ -29,7 +29,8 @@ CREATE TABLE Receipt ( started boolean DEFAULT FALSE, training boolean DEFAULT FALSE NOT NULL, closing bigint REFERENCES Closing (id) ON DELETE CASCADE, - websecret character varying(255) + websecret character varying(255), + tax_rounding_mode character varying(255) DEFAULT 'line' NOT NULL ); CREATE INDEX Receipt_closing_index ON Receipt (closing); diff --git a/libpretixsync/src/main/sqldelight/postgres/eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq b/libpretixsync/src/main/sqldelight/postgres/eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq index f7ebfb10..30407f21 100644 --- a/libpretixsync/src/main/sqldelight/postgres/eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq +++ b/libpretixsync/src/main/sqldelight/postgres/eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq @@ -27,6 +27,7 @@ CREATE TABLE ReceiptLine ( listed_price numeric, positionid bigint, price numeric, + price_includes_rounding_correction numeric DEFAULT 0 NOT NULL, price_after_voucher numeric, price_calculated_from_net boolean DEFAULT FALSE, remote_error character varying(255), @@ -40,6 +41,7 @@ CREATE TABLE ReceiptLine ( tax_rate numeric, tax_rule bigint, tax_value numeric, + tax_value_includes_rounding_correction numeric DEFAULT 0 NOT NULL, tax_code character varying(255), type character varying(255), use_reusable_medium bigint, diff --git a/libpretixsync/src/main/sqldelight/postgres/migrations/121.sqm b/libpretixsync/src/main/sqldelight/postgres/migrations/121.sqm new file mode 100644 index 00000000..49ff02cb --- /dev/null +++ b/libpretixsync/src/main/sqldelight/postgres/migrations/121.sqm @@ -0,0 +1,3 @@ +ALTER TABLE ReceiptLine ADD price_includes_rounding_correction numeric DEFAULT 0 NOT NULL; +ALTER TABLE ReceiptLine ADD tax_value_includes_rounding_correction numeric DEFAULT 0 NOT NULL; +ALTER TABLE Receipt ADD tax_rounding_mode character varying(255) DEFAULT 'line' NOT NULL; diff --git a/libpretixsync/src/main/sqldelight/sqlite/eu/pretix/libpretixsync/sqldelight/Receipt.sq b/libpretixsync/src/main/sqldelight/sqlite/eu/pretix/libpretixsync/sqldelight/Receipt.sq index 1834f457..f414ae01 100644 --- a/libpretixsync/src/main/sqldelight/sqlite/eu/pretix/libpretixsync/sqldelight/Receipt.sq +++ b/libpretixsync/src/main/sqldelight/sqlite/eu/pretix/libpretixsync/sqldelight/Receipt.sq @@ -29,7 +29,8 @@ CREATE TABLE Receipt ( server_id INTEGER, started INTEGER AS Boolean DEFAULT 0, training INTEGER AS Boolean DEFAULT 0 NOT NULL, - websecret TEXT + websecret TEXT, + tax_rounding_mode TEXT DEFAULT 'line' NOT NULL ); CREATE INDEX Receipt_closing_index ON Receipt (closing); diff --git a/libpretixsync/src/main/sqldelight/sqlite/eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq b/libpretixsync/src/main/sqldelight/sqlite/eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq index ba620507..f0eeeda4 100644 --- a/libpretixsync/src/main/sqldelight/sqlite/eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq +++ b/libpretixsync/src/main/sqldelight/sqlite/eu/pretix/libpretixsync/sqldelight/ReceiptLine.sq @@ -1,3 +1,4 @@ +import eu.pretix.libpretixsync.sqldelight.BigDecimalAdapter; import java.math.BigDecimal; import java.util.Date; import kotlin.Boolean; @@ -29,6 +30,7 @@ CREATE TABLE ReceiptLine ( listed_price REAL AS BigDecimal, positionid INTEGER, price REAL AS BigDecimal, + price_includes_rounding_correction REAL AS BigDecimal DEFAULT 0 NOT NULL, price_after_voucher REAL AS BigDecimal, price_calculated_from_net INTEGER AS Boolean DEFAULT 0, receipt INTEGER REFERENCES Receipt (id) ON DELETE CASCADE, @@ -43,6 +45,7 @@ CREATE TABLE ReceiptLine ( tax_rate REAL AS BigDecimal, tax_rule INTEGER, tax_value REAL AS BigDecimal, + tax_value_includes_rounding_correction REAL AS BigDecimal DEFAULT 0 NOT NULL, tax_code TEXT, type TEXT, use_reusable_medium INTEGER, diff --git a/libpretixsync/src/main/sqldelight/sqlite/migrations/121.sqm b/libpretixsync/src/main/sqldelight/sqlite/migrations/121.sqm new file mode 100644 index 00000000..1114e8d8 --- /dev/null +++ b/libpretixsync/src/main/sqldelight/sqlite/migrations/121.sqm @@ -0,0 +1,5 @@ +import java.math.BigDecimal; + +ALTER TABLE ReceiptLine ADD price_includes_rounding_correction REAL AS BigDecimal DEFAULT 0 NOT NULL; +ALTER TABLE ReceiptLine ADD tax_value_includes_rounding_correction REAL AS BigDecimal DEFAULT 0 NOT NULL; +ALTER TABLE Receipt ADD tax_rounding_mode TEXT DEFAULT 'line' NOT NULL; \ No newline at end of file diff --git a/libpretixsync/src/test/java/eu/pretix/libpretixsync/db/BaseDatabaseTest.java b/libpretixsync/src/test/java/eu/pretix/libpretixsync/db/BaseDatabaseTest.java index 4a6dfd95..b179673d 100644 --- a/libpretixsync/src/test/java/eu/pretix/libpretixsync/db/BaseDatabaseTest.java +++ b/libpretixsync/src/test/java/eu/pretix/libpretixsync/db/BaseDatabaseTest.java @@ -97,6 +97,8 @@ public void setUpDb() throws NoSuchAlgorithmException { bigDecimalAdapter, bigDecimalAdapter, bigDecimalAdapter, + bigDecimalAdapter, + bigDecimalAdapter, bigDecimalAdapter ), new ReceiptPayment.Adapter(