includio-cms 0.15.1 → 0.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/DOCS.md +1 -1
  3. package/ROADMAP.md +6 -1
  4. package/dist/admin/client/shop/shipping-method-form.svelte +24 -21
  5. package/dist/admin/client/shop/shipping-method-form.svelte.d.ts +1 -1
  6. package/dist/admin/client/shop/shipping-methods-list-page.svelte +7 -4
  7. package/dist/admin/client/shop/shop-products-list-page.svelte +2 -2
  8. package/dist/admin/components/fields/shop-field.svelte +63 -22
  9. package/dist/admin/remote/shop.remote.d.ts +4 -60
  10. package/dist/admin/remote/shop.remote.js +3 -3
  11. package/dist/db-postgres/schema/shop/product.d.ts +4 -4
  12. package/dist/db-postgres/schema/shop/product.js +3 -2
  13. package/dist/db-postgres/schema/shop/productVariant.d.ts +4 -4
  14. package/dist/db-postgres/schema/shop/productVariant.js +3 -2
  15. package/dist/db-postgres/schema/shop/shippingMethod.d.ts +4 -4
  16. package/dist/db-postgres/schema/shop/shippingMethod.js +3 -2
  17. package/dist/paraglide/messages/_index.d.ts +36 -3
  18. package/dist/paraglide/messages/_index.js +71 -3
  19. package/dist/paraglide/messages/en.d.ts +5 -0
  20. package/dist/paraglide/messages/en.js +14 -0
  21. package/dist/paraglide/messages/pl.d.ts +5 -0
  22. package/dist/paraglide/messages/pl.js +14 -0
  23. package/dist/shop/client/index.d.ts +1 -0
  24. package/dist/shop/pricing.d.ts +4 -0
  25. package/dist/shop/pricing.js +18 -0
  26. package/dist/shop/server/cart-hydrate.js +6 -3
  27. package/dist/shop/server/populate.d.ts +2 -0
  28. package/dist/shop/server/shipping.d.ts +11 -4
  29. package/dist/shop/server/shipping.js +21 -14
  30. package/dist/shop/server/shop-data.d.ts +8 -2
  31. package/dist/shop/server/shop-data.js +18 -10
  32. package/dist/updates/0.15.2/index.d.ts +2 -0
  33. package/dist/updates/0.15.2/index.js +18 -0
  34. package/dist/updates/index.js +2 -1
  35. package/package.json +1 -1
  36. package/dist/paraglide/messages/hello_world.d.ts +0 -5
  37. package/dist/paraglide/messages/hello_world.js +0 -33
  38. package/dist/paraglide/messages/login_hello.d.ts +0 -16
  39. package/dist/paraglide/messages/login_hello.js +0 -34
  40. package/dist/paraglide/messages/login_please_login.d.ts +0 -16
  41. package/dist/paraglide/messages/login_please_login.js +0 -34
@@ -1,4 +1,72 @@
1
1
  /* eslint-disable */
2
- export * from './hello_world.js'
3
- export * from './login_hello.js'
4
- export * from './login_please_login.js'
2
+ import { getLocale, trackMessageCall, experimentalMiddlewareLocaleSplitting, isServer } from "../runtime.js"
3
+ import * as en from "./en.js"
4
+ import * as pl from "./pl.js"
5
+ /**
6
+ * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
7
+ *
8
+ * - Changing this function will be over-written by the next build.
9
+ *
10
+ * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
11
+ * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
12
+ *
13
+ * @param {{ name: NonNullable<unknown> }} inputs
14
+ * @param {{ locale?: "en" | "pl" }} options
15
+ * @returns {string}
16
+ */
17
+ /* @__NO_SIDE_EFFECTS__ */
18
+ export const hello_world = (inputs, options = {}) => {
19
+ if (experimentalMiddlewareLocaleSplitting && isServer === false) {
20
+ return /** @type {any} */ (globalThis).__paraglide_ssr.hello_world(inputs)
21
+ }
22
+ const locale = options.locale ?? getLocale()
23
+ trackMessageCall("hello_world", locale)
24
+ if (locale === "en") return en.hello_world(inputs)
25
+ return pl.hello_world(inputs)
26
+ };
27
+ /**
28
+ * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
29
+ *
30
+ * - Changing this function will be over-written by the next build.
31
+ *
32
+ * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
33
+ * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
34
+ *
35
+ * @param {{}} inputs
36
+ * @param {{ locale?: "en" | "pl" }} options
37
+ * @returns {string}
38
+ */
39
+ /* @__NO_SIDE_EFFECTS__ */
40
+ const login_hello = (inputs = {}, options = {}) => {
41
+ if (experimentalMiddlewareLocaleSplitting && isServer === false) {
42
+ return /** @type {any} */ (globalThis).__paraglide_ssr.login_hello(inputs)
43
+ }
44
+ const locale = options.locale ?? getLocale()
45
+ trackMessageCall("login_hello", locale)
46
+ if (locale === "en") return en.login_hello(inputs)
47
+ return pl.login_hello(inputs)
48
+ };
49
+ export { login_hello as "login.hello" }
50
+ /**
51
+ * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
52
+ *
53
+ * - Changing this function will be over-written by the next build.
54
+ *
55
+ * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
56
+ * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
57
+ *
58
+ * @param {{}} inputs
59
+ * @param {{ locale?: "en" | "pl" }} options
60
+ * @returns {string}
61
+ */
62
+ /* @__NO_SIDE_EFFECTS__ */
63
+ const login_please_login = (inputs = {}, options = {}) => {
64
+ if (experimentalMiddlewareLocaleSplitting && isServer === false) {
65
+ return /** @type {any} */ (globalThis).__paraglide_ssr.login_please_login(inputs)
66
+ }
67
+ const locale = options.locale ?? getLocale()
68
+ trackMessageCall("login_please_login", locale)
69
+ if (locale === "en") return en.login_please_login(inputs)
70
+ return pl.login_please_login(inputs)
71
+ };
72
+ export { login_please_login as "login.please_login" }
@@ -0,0 +1,5 @@
1
+ export const hello_world: (inputs: {
2
+ name: NonNullable<unknown>;
3
+ }) => string;
4
+ export const login_hello: (inputs: {}) => string;
5
+ export const login_please_login: (inputs: {}) => string;
@@ -0,0 +1,14 @@
1
+ /* eslint-disable */
2
+
3
+
4
+ export const hello_world = /** @type {(inputs: { name: NonNullable<unknown> }) => string} */ (i) => {
5
+ return `Hello, ${i.name} from en!`
6
+ };
7
+
8
+ export const login_hello = /** @type {(inputs: {}) => string} */ () => {
9
+ return `Welcome back`
10
+ };
11
+
12
+ export const login_please_login = /** @type {(inputs: {}) => string} */ () => {
13
+ return `Login to your account`
14
+ };
@@ -0,0 +1,5 @@
1
+ export const hello_world: (inputs: {
2
+ name: NonNullable<unknown>;
3
+ }) => string;
4
+ export const login_hello: (inputs: {}) => string;
5
+ export const login_please_login: (inputs: {}) => string;
@@ -0,0 +1,14 @@
1
+ /* eslint-disable */
2
+
3
+
4
+ export const hello_world = /** @type {(inputs: { name: NonNullable<unknown> }) => string} */ (i) => {
5
+ return `Hello, ${i.name} from pl!`
6
+ };
7
+
8
+ export const login_hello = /** @type {(inputs: {}) => string} */ () => {
9
+ return `Witaj ponownie`
10
+ };
11
+
12
+ export const login_please_login = /** @type {(inputs: {}) => string} */ () => {
13
+ return `Zaloguj się na swoje konto`
14
+ };
@@ -8,6 +8,7 @@ export interface ShippingMethodPublic {
8
8
  id: string;
9
9
  name: Record<string, string>;
10
10
  description: Record<string, string> | null;
11
+ /** Netto w PLN (number, ≤6dp). Przed 0.15.2 było w groszach — od 0.15.2 w PLN. */
11
12
  price: number;
12
13
  vatRate: number;
13
14
  carrierType: string;
@@ -1,3 +1,7 @@
1
+ export declare function netPlnFromGrossPln(grossPln: number, vatRate: number): number;
2
+ export declare function grossPlnFromNetPln(netPln: number, vatRate: number): number;
3
+ export declare function toCents(pln: number): number;
4
+ export declare function fromCents(cents: number): number;
1
5
  export declare function grossFromNet(net: number, vatRate: number): number;
2
6
  export declare function netFromGross(gross: number, vatRate: number): number;
3
7
  export declare function vatAmount(net: number, vatRate: number): number;
@@ -1,3 +1,21 @@
1
+ // Pricing — dwie domeny:
2
+ // PLN-precise (number, do 6dp) — używane dla basePrice/priceDelta/shipping.price w DB (numeric 20,6).
3
+ // cents (integer, grosze) — używane w snapshotach zamówienia/faktury (KSeF).
4
+ // Round do groszy odbywa się RAZ, na granicy PLN→cents, po kompletnym mnożeniu netto×(1+VAT).
5
+ export function netPlnFromGrossPln(grossPln, vatRate) {
6
+ return grossPln / (1 + vatRate / 100);
7
+ }
8
+ export function grossPlnFromNetPln(netPln, vatRate) {
9
+ return netPln * (1 + vatRate / 100);
10
+ }
11
+ export function toCents(pln) {
12
+ return Math.round(pln * 100);
13
+ }
14
+ export function fromCents(cents) {
15
+ return cents / 100;
16
+ }
17
+ // Compat shims — `net`/`gross` w CENTACH. Deprecated; nie używać w nowych ścieżkach.
18
+ // Cierpią na drift dla input-as-gross + round-trip. Zostawione dla testów i zewnętrznych konsumentów.
1
19
  export function grossFromNet(net, vatRate) {
2
20
  return Math.round(net * (1 + vatRate / 100));
3
21
  }
@@ -4,7 +4,7 @@ import { entriesTable } from '../../db-postgres/schema/entry.js';
4
4
  import { entryVersionsTable } from '../../db-postgres/schema/entryVersion.js';
5
5
  import { getCMS } from '../../core/cms.js';
6
6
  import { getShopDb, requireShopConfig } from './db.js';
7
- import { grossFromNet } from '../pricing.js';
7
+ import { grossPlnFromNetPln, toCents } from '../pricing.js';
8
8
  export async function hydrateCart(items, opts = {}) {
9
9
  const shop = requireShopConfig();
10
10
  const cms = getCMS();
@@ -94,8 +94,11 @@ export async function hydrateCart(items, opts = {}) {
94
94
  const version = publishedByEntry.get(product.entryId);
95
95
  const title = readTitle(version?.data);
96
96
  const slug = readSlug(version?.data);
97
- const priceNet = product.basePrice + (variant.priceDelta ?? 0);
98
- const priceGross = grossFromNet(priceNet, product.vatRate);
97
+ // basePrice/priceDelta numeric(20,6) drizzle zwraca string. Konwertujemy do PLN (number).
98
+ const priceNetPln = Number(product.basePrice) + Number(variant.priceDelta ?? 0);
99
+ const priceGrossPln = grossPlnFromNetPln(priceNetPln, product.vatRate);
100
+ const priceNet = toCents(priceNetPln);
101
+ const priceGross = toCents(priceGrossPln);
99
102
  const stock = variant.stock;
100
103
  const stockEnabled = shop.features.stock;
101
104
  let effectiveQty = ref.qty;
@@ -1,5 +1,6 @@
1
1
  import type { Field } from '../../types/fields.js';
2
2
  export interface PopulatedShopField {
3
+ /** Netto w PLN (number, ≤6dp). Od 0.15.2. */
3
4
  basePrice: number;
4
5
  vatRate: number;
5
6
  isActive: boolean;
@@ -7,6 +8,7 @@ export interface PopulatedShopField {
7
8
  id: string;
8
9
  sku: string | null;
9
10
  name: Record<string, string> | null;
11
+ /** Netto delta w PLN (number, ≤6dp). Od 0.15.2. */
10
12
  priceDelta: number;
11
13
  stock: number | null;
12
14
  attributes: Record<string, string> | null;
@@ -1,6 +1,9 @@
1
1
  import { shopShippingMethodsTable } from '../../db-postgres/schema/shop/index.js';
2
2
  import type { ShopCarrierType } from '../../db-postgres/schema/shop/shippingMethod.js';
3
- export type ShippingMethodRow = typeof shopShippingMethodsTable.$inferSelect;
3
+ type RawShippingMethodRow = typeof shopShippingMethodsTable.$inferSelect;
4
+ export type ShippingMethodRow = Omit<RawShippingMethodRow, 'price'> & {
5
+ price: number;
6
+ };
4
7
  export interface ShippingConditions {
5
8
  freeAbove?: number;
6
9
  }
@@ -26,10 +29,14 @@ export declare function deleteShippingMethod(id: string): Promise<void>;
26
29
  export declare function reorderShippingMethods(orderedIds: string[]): Promise<void>;
27
30
  /**
28
31
  * Resolve effective shipping cost for a given cart.
29
- * Applies `conditions.freeAbove` threshold against the cart gross total.
30
- * Returns integer (smallest currency unit).
32
+ * Applies `conditions.freeAbove` threshold against the cart gross total (grosze).
33
+ * method.price PLN (numeric 20,6). Zwraca kwoty w groszach (integer) do snapshotu zamówienia.
31
34
  */
32
- export declare function resolveShippingPrice(method: Pick<ShippingMethodRow, 'price' | 'vatRate' | 'conditions'>, cartTotalGross: number): {
35
+ export declare function resolveShippingPrice(method: {
36
+ price: number | string;
37
+ vatRate: number;
38
+ conditions: ShippingConditions | null | unknown;
39
+ }, cartTotalGross: number): {
33
40
  net: number;
34
41
  gross: number;
35
42
  vat: number;
@@ -1,13 +1,16 @@
1
1
  import { asc, eq } from 'drizzle-orm';
2
2
  import { shopShippingMethodsTable } from '../../db-postgres/schema/shop/index.js';
3
- import { grossFromNet } from '../pricing.js';
3
+ import { grossPlnFromNetPln, toCents } from '../pricing.js';
4
4
  import { getShopDb } from './db.js';
5
+ function mapShippingRow(r) {
6
+ return { ...r, price: Number(r.price) };
7
+ }
5
8
  function validate(input) {
6
9
  if (!input.name || Object.keys(input.name).length === 0) {
7
10
  throw new Error('Shipping method name (i18n) is required.');
8
11
  }
9
- if (!Number.isInteger(input.price) || input.price < 0) {
10
- throw new Error('price must be non-negative integer (smallest currency unit).');
12
+ if (!Number.isFinite(input.price) || input.price < 0 || input.price > 1e9) {
13
+ throw new Error('price must be non-negative finite number (PLN, 1e9).');
11
14
  }
12
15
  if (!Number.isInteger(input.vatRate) || input.vatRate < 0 || input.vatRate > 100) {
13
16
  throw new Error('vatRate must be integer 0..100.');
@@ -15,17 +18,18 @@ function validate(input) {
15
18
  if (input.conditions?.freeAbove != null) {
16
19
  const fa = input.conditions.freeAbove;
17
20
  if (!Number.isInteger(fa) || fa < 0) {
18
- throw new Error('conditions.freeAbove must be non-negative integer.');
21
+ throw new Error('conditions.freeAbove must be non-negative integer (grosze).');
19
22
  }
20
23
  }
21
24
  }
22
25
  export async function listShippingMethods(opts = {}) {
23
26
  const db = getShopDb();
24
- return db
27
+ const rows = await db
25
28
  .select()
26
29
  .from(shopShippingMethodsTable)
27
30
  .where(opts.activeOnly ? eq(shopShippingMethodsTable.isActive, true) : undefined)
28
31
  .orderBy(asc(shopShippingMethodsTable.sortOrder), asc(shopShippingMethodsTable.createdAt));
32
+ return rows.map(mapShippingRow);
29
33
  }
30
34
  export async function getShippingMethod(id) {
31
35
  const db = getShopDb();
@@ -33,7 +37,7 @@ export async function getShippingMethod(id) {
33
37
  .select()
34
38
  .from(shopShippingMethodsTable)
35
39
  .where(eq(shopShippingMethodsTable.id, id));
36
- return row ?? null;
40
+ return row ? mapShippingRow(row) : null;
37
41
  }
38
42
  export async function createShippingMethod(input) {
39
43
  validate(input);
@@ -43,7 +47,7 @@ export async function createShippingMethod(input) {
43
47
  .values({
44
48
  name: input.name,
45
49
  description: input.description ?? null,
46
- price: input.price,
50
+ price: String(input.price),
47
51
  vatRate: input.vatRate,
48
52
  carrierType: input.carrierType ?? 'none',
49
53
  conditions: input.conditions ?? null,
@@ -52,7 +56,7 @@ export async function createShippingMethod(input) {
52
56
  sortOrder: input.sortOrder ?? null
53
57
  })
54
58
  .returning();
55
- return row;
59
+ return mapShippingRow(row);
56
60
  }
57
61
  export async function updateShippingMethod(id, input) {
58
62
  const db = getShopDb();
@@ -62,7 +66,7 @@ export async function updateShippingMethod(id, input) {
62
66
  if (input.description !== undefined)
63
67
  patch.description = input.description;
64
68
  if (input.price !== undefined)
65
- patch.price = input.price;
69
+ patch.price = String(input.price);
66
70
  if (input.vatRate !== undefined)
67
71
  patch.vatRate = input.vatRate;
68
72
  if (input.carrierType !== undefined)
@@ -82,7 +86,7 @@ export async function updateShippingMethod(id, input) {
82
86
  .returning();
83
87
  if (!row)
84
88
  throw new Error('Shipping method not found');
85
- return row;
89
+ return mapShippingRow(row);
86
90
  }
87
91
  export async function deleteShippingMethod(id) {
88
92
  const db = getShopDb();
@@ -100,15 +104,18 @@ export async function reorderShippingMethods(orderedIds) {
100
104
  }
101
105
  /**
102
106
  * Resolve effective shipping cost for a given cart.
103
- * Applies `conditions.freeAbove` threshold against the cart gross total.
104
- * Returns integer (smallest currency unit).
107
+ * Applies `conditions.freeAbove` threshold against the cart gross total (grosze).
108
+ * method.price PLN (numeric 20,6). Zwraca kwoty w groszach (integer) do snapshotu zamówienia.
105
109
  */
106
110
  export function resolveShippingPrice(method, cartTotalGross) {
107
111
  const cond = method.conditions ?? null;
108
112
  if (cond?.freeAbove != null && cartTotalGross >= cond.freeAbove) {
109
113
  return { net: 0, gross: 0, vat: 0, isFree: true };
110
114
  }
111
- const gross = grossFromNet(method.price, method.vatRate);
112
- return { net: method.price, gross, vat: gross - method.price, isFree: false };
115
+ const priceNetPln = Number(method.price);
116
+ const priceGrossPln = grossPlnFromNetPln(priceNetPln, method.vatRate);
117
+ const net = toCents(priceNetPln);
118
+ const gross = toCents(priceGrossPln);
119
+ return { net, gross, vat: gross - net, isFree: false };
113
120
  }
114
121
  export { validate as validateShippingMethodInput };
@@ -1,6 +1,12 @@
1
1
  import { shopProductsTable, shopProductVariantsTable } from '../../db-postgres/schema/shop/index.js';
2
- export type ShopDataRow = typeof shopProductsTable.$inferSelect;
3
- export type VariantRow = typeof shopProductVariantsTable.$inferSelect;
2
+ type RawShopDataRow = typeof shopProductsTable.$inferSelect;
3
+ type RawVariantRow = typeof shopProductVariantsTable.$inferSelect;
4
+ export type ShopDataRow = Omit<RawShopDataRow, 'basePrice'> & {
5
+ basePrice: number;
6
+ };
7
+ export type VariantRow = Omit<RawVariantRow, 'priceDelta'> & {
8
+ priceDelta: number;
9
+ };
4
10
  export interface ShopDataWithVariants extends ShopDataRow {
5
11
  variants: VariantRow[];
6
12
  }
@@ -3,14 +3,21 @@ import { shopProductsTable, shopProductVariantsTable } from '../../db-postgres/s
3
3
  import { entriesTable } from '../../db-postgres/schema/entry.js';
4
4
  import { entryVersionsTable } from '../../db-postgres/schema/entryVersion.js';
5
5
  import { getShopDb } from './db.js';
6
+ const MAX_PLN = 1e9;
6
7
  function validateShopData(input) {
7
- if (!Number.isInteger(input.basePrice) || input.basePrice < 0) {
8
- throw new Error('basePrice must be a non-negative integer (smallest currency unit).');
8
+ if (!Number.isFinite(input.basePrice) || input.basePrice < 0 || input.basePrice > MAX_PLN) {
9
+ throw new Error('basePrice must be a non-negative finite number (PLN, 1e9).');
9
10
  }
10
11
  if (!Number.isInteger(input.vatRate) || input.vatRate < 0 || input.vatRate > 100) {
11
12
  throw new Error('vatRate must be an integer between 0 and 100.');
12
13
  }
13
14
  }
15
+ function mapShopRow(r) {
16
+ return { ...r, basePrice: Number(r.basePrice) };
17
+ }
18
+ function mapVariantRow(v) {
19
+ return { ...v, priceDelta: Number(v.priceDelta) };
20
+ }
14
21
  export async function getShopDataByEntry(entryId) {
15
22
  const db = getShopDb();
16
23
  const [row] = await db
@@ -24,18 +31,19 @@ export async function getShopDataByEntry(entryId) {
24
31
  .from(shopProductVariantsTable)
25
32
  .where(eq(shopProductVariantsTable.productId, row.id))
26
33
  .orderBy(asc(shopProductVariantsTable.sortOrder), asc(shopProductVariantsTable.createdAt));
27
- return { ...row, variants };
34
+ return { ...mapShopRow(row), variants: variants.map(mapVariantRow) };
28
35
  }
29
36
  export async function upsertShopData(entryId, input, variants) {
30
37
  validateShopData(input);
31
38
  const db = getShopDb();
32
39
  const existing = await getShopDataByEntry(entryId);
33
40
  let productId;
41
+ const basePriceSql = String(input.basePrice);
34
42
  if (existing) {
35
43
  const [updated] = await db
36
44
  .update(shopProductsTable)
37
45
  .set({
38
- basePrice: input.basePrice,
46
+ basePrice: basePriceSql,
39
47
  vatRate: input.vatRate,
40
48
  isActive: input.isActive ?? existing.isActive,
41
49
  sortOrder: input.sortOrder ?? existing.sortOrder,
@@ -50,7 +58,7 @@ export async function upsertShopData(entryId, input, variants) {
50
58
  .insert(shopProductsTable)
51
59
  .values({
52
60
  entryId,
53
- basePrice: input.basePrice,
61
+ basePrice: basePriceSql,
54
62
  vatRate: input.vatRate,
55
63
  isActive: input.isActive ?? true,
56
64
  sortOrder: input.sortOrder
@@ -73,7 +81,7 @@ export async function upsertShopData(entryId, input, variants) {
73
81
  .set({
74
82
  sku: v.sku ?? null,
75
83
  name: v.name ?? null,
76
- priceDelta: v.priceDelta ?? 0,
84
+ priceDelta: String(v.priceDelta ?? 0),
77
85
  stock: v.stock ?? null,
78
86
  attributes: v.attributes ?? null
79
87
  })
@@ -84,7 +92,7 @@ export async function upsertShopData(entryId, input, variants) {
84
92
  productId,
85
93
  sku: v.sku ?? null,
86
94
  name: v.name ?? null,
87
- priceDelta: v.priceDelta ?? 0,
95
+ priceDelta: String(v.priceDelta ?? 0),
88
96
  stock: v.stock ?? null,
89
97
  attributes: v.attributes ?? null
90
98
  });
@@ -101,7 +109,7 @@ export async function upsertShopData(entryId, input, variants) {
101
109
  productId,
102
110
  sku: null,
103
111
  name: null,
104
- priceDelta: 0,
112
+ priceDelta: '0',
105
113
  stock: null,
106
114
  attributes: null
107
115
  });
@@ -123,7 +131,7 @@ export async function getDefaultVariant(productId) {
123
131
  .where(eq(shopProductVariantsTable.productId, productId))
124
132
  .orderBy(asc(shopProductVariantsTable.createdAt))
125
133
  .limit(1);
126
- return v ?? null;
134
+ return v ? mapVariantRow(v) : null;
127
135
  }
128
136
  export async function deleteShopData(entryId) {
129
137
  const db = getShopDb();
@@ -170,7 +178,7 @@ export async function listShopEntries(opts = {}) {
170
178
  entryId: r.entryId,
171
179
  collectionSlug: r.collectionSlug,
172
180
  shopId: r.shopId,
173
- basePrice: r.basePrice,
181
+ basePrice: Number(r.basePrice),
174
182
  vatRate: r.vatRate,
175
183
  isActive: r.isActive,
176
184
  variantCount: variants.length,
@@ -0,0 +1,2 @@
1
+ import type { CmsUpdate } from '../index.js';
2
+ export declare const update: CmsUpdate;
@@ -0,0 +1,18 @@
1
+ export const update = {
2
+ version: '0.15.2',
3
+ date: '2026-04-15',
4
+ description: 'Shop: cena przechowywana jako numeric(20,6) — eliminacja driftu brutto/netto po reload; toggle netto/brutto per wariant.',
5
+ features: [
6
+ 'Warianty produktu mają teraz toggle netto/brutto obok pola "Zmiana ceny" — spójne z toggle\'em ceny bazowej. Delta zapisywana kanonicznie jako netto.'
7
+ ],
8
+ fixes: [
9
+ 'Shop: po wpisaniu ceny brutto (np. 65,00 zł przy VAT 23%) i refreshu, cena nie "ucieka" o ±1 grosz. Wartości przechowywane są jako PLN z 6 miejscami po przecinku (wzorzec PrestaShop), zamiast jednostek groszy — brutto zawsze odtwarzane z netto bez utraty informacji.',
10
+ 'Shipping: ta sama poprawka dla ceny metody wysyłki (stored jako netto PLN z 6dp).'
11
+ ],
12
+ breakingChanges: [
13
+ 'Kolumny `shop_products.base_price`, `shop_product_variants.price_delta`, `shop_shipping_methods.price` zmieniły typ z `integer` (grosze) na `numeric(20,6)` (PLN). Snapshot zamówienia (`shop_orders.*`, `shop_order_items.price_*_snapshot`) pozostaje w groszach (`integer`) — KSeF-compatible.',
14
+ 'Publiczne typy `ShopDataWithVariants.basePrice`, `VariantRow.priceDelta`, `ShippingMethodRow.price` — wartość dalej `number`, ale wyrażona w PLN (nie groszach). Dla konsumentów SDK/populate: mnożenie × 100 jeśli potrzebujesz groszy.'
15
+ ],
16
+ sql: 'ALTER TABLE shop_products ALTER COLUMN base_price TYPE numeric(20,6) USING (base_price::numeric / 100);\nALTER TABLE shop_product_variants ALTER COLUMN price_delta TYPE numeric(20,6) USING (price_delta::numeric / 100);\nALTER TABLE shop_shipping_methods ALTER COLUMN price TYPE numeric(20,6) USING (price::numeric / 100);',
17
+ notes: 'Migrację SQL trzeba uruchomić RAZ, PRZED `db:push` — dzieli istniejące wartości ÷100, bo stare dane były w groszach, a nowy typ przechowuje PLN. Po migracji `db:push` tylko zsynchronizuje schemat (bez zmiany danych).'
18
+ };
@@ -46,7 +46,8 @@ import { update as update0145 } from './0.14.5/index.js';
46
46
  import { update as update0146 } from './0.14.6/index.js';
47
47
  import { update as update0150 } from './0.15.0/index.js';
48
48
  import { update as update0151 } from './0.15.1/index.js';
49
- export const updates = [update0065, update0066, update0067, update0068, update0069, update010, update011, update012, update013, update014, update015, update020, update022, update050, update051, update052, update053, update054, update055, update056, update057, update058, update060, update061, update062, update070, update071, update072, update073, update080, update090, update0100, update0110, update0120, update0130, update0131, update0132, update0133, update0134, update0140, update0141, update0142, update0143, update0144, update0145, update0146, update0150, update0151];
49
+ import { update as update0152 } from './0.15.2/index.js';
50
+ export const updates = [update0065, update0066, update0067, update0068, update0069, update010, update011, update012, update013, update014, update015, update020, update022, update050, update051, update052, update053, update054, update055, update056, update057, update058, update060, update061, update062, update070, update071, update072, update073, update080, update090, update0100, update0110, update0120, update0130, update0131, update0132, update0133, update0134, update0140, update0141, update0142, update0143, update0144, update0145, update0146, update0150, update0151, update0152];
50
51
  export const getUpdatesFrom = (fromVersion) => {
51
52
  const fromParts = fromVersion.split('.').map(Number);
52
53
  return updates.filter((update) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "includio-cms",
3
- "version": "0.15.1",
3
+ "version": "0.15.2",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",
@@ -1,5 +0,0 @@
1
- export function hello_world(inputs: {
2
- name: NonNullable<unknown>;
3
- }, options?: {
4
- locale?: "en" | "pl";
5
- }): string;
@@ -1,33 +0,0 @@
1
- /* eslint-disable */
2
- import { getLocale, trackMessageCall, experimentalMiddlewareLocaleSplitting, isServer } from '../runtime.js';
3
-
4
- const en_hello_world = /** @type {(inputs: { name: NonNullable<unknown> }) => string} */ (i) => {
5
- return `Hello, ${i.name} from en!`
6
- };
7
-
8
- const pl_hello_world = /** @type {(inputs: { name: NonNullable<unknown> }) => string} */ (i) => {
9
- return `Hello, ${i.name} from pl!`
10
- };
11
-
12
- /**
13
- * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
14
- *
15
- * - Changing this function will be over-written by the next build.
16
- *
17
- * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
18
- * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
19
- *
20
- * @param {{ name: NonNullable<unknown> }} inputs
21
- * @param {{ locale?: "en" | "pl" }} options
22
- * @returns {string}
23
- */
24
- /* @__NO_SIDE_EFFECTS__ */
25
- export const hello_world = (inputs, options = {}) => {
26
- if (experimentalMiddlewareLocaleSplitting && isServer === false) {
27
- return /** @type {any} */ (globalThis).__paraglide_ssr.hello_world(inputs)
28
- }
29
- const locale = options.locale ?? getLocale()
30
- trackMessageCall("hello_world", locale)
31
- if (locale === "en") return en_hello_world(inputs)
32
- return pl_hello_world(inputs)
33
- };
@@ -1,16 +0,0 @@
1
- export { login_hello as login.hello };
2
- /**
3
- * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
4
- *
5
- * - Changing this function will be over-written by the next build.
6
- *
7
- * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
8
- * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
9
- *
10
- * @param {{}} inputs
11
- * @param {{ locale?: "en" | "pl" }} options
12
- * @returns {string}
13
- */
14
- declare function login_hello(inputs?: {}, options?: {
15
- locale?: "en" | "pl";
16
- }): string;
@@ -1,34 +0,0 @@
1
- /* eslint-disable */
2
- import { getLocale, trackMessageCall, experimentalMiddlewareLocaleSplitting, isServer } from '../runtime.js';
3
-
4
- const en_login_hello = /** @type {(inputs: {}) => string} */ () => {
5
- return `Welcome back`
6
- };
7
-
8
- const pl_login_hello = /** @type {(inputs: {}) => string} */ () => {
9
- return `Witaj ponownie`
10
- };
11
-
12
- /**
13
- * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
14
- *
15
- * - Changing this function will be over-written by the next build.
16
- *
17
- * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
18
- * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
19
- *
20
- * @param {{}} inputs
21
- * @param {{ locale?: "en" | "pl" }} options
22
- * @returns {string}
23
- */
24
- /* @__NO_SIDE_EFFECTS__ */
25
- const login_hello = (inputs = {}, options = {}) => {
26
- if (experimentalMiddlewareLocaleSplitting && isServer === false) {
27
- return /** @type {any} */ (globalThis).__paraglide_ssr.login_hello(inputs)
28
- }
29
- const locale = options.locale ?? getLocale()
30
- trackMessageCall("login_hello", locale)
31
- if (locale === "en") return en_login_hello(inputs)
32
- return pl_login_hello(inputs)
33
- };
34
- export { login_hello as "login.hello" }
@@ -1,16 +0,0 @@
1
- export { login_please_login as login.please_login };
2
- /**
3
- * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
4
- *
5
- * - Changing this function will be over-written by the next build.
6
- *
7
- * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
8
- * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
9
- *
10
- * @param {{}} inputs
11
- * @param {{ locale?: "en" | "pl" }} options
12
- * @returns {string}
13
- */
14
- declare function login_please_login(inputs?: {}, options?: {
15
- locale?: "en" | "pl";
16
- }): string;
@@ -1,34 +0,0 @@
1
- /* eslint-disable */
2
- import { getLocale, trackMessageCall, experimentalMiddlewareLocaleSplitting, isServer } from '../runtime.js';
3
-
4
- const en_login_please_login = /** @type {(inputs: {}) => string} */ () => {
5
- return `Login to your account`
6
- };
7
-
8
- const pl_login_please_login = /** @type {(inputs: {}) => string} */ () => {
9
- return `Zaloguj się na swoje konto`
10
- };
11
-
12
- /**
13
- * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
14
- *
15
- * - Changing this function will be over-written by the next build.
16
- *
17
- * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
18
- * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
19
- *
20
- * @param {{}} inputs
21
- * @param {{ locale?: "en" | "pl" }} options
22
- * @returns {string}
23
- */
24
- /* @__NO_SIDE_EFFECTS__ */
25
- const login_please_login = (inputs = {}, options = {}) => {
26
- if (experimentalMiddlewareLocaleSplitting && isServer === false) {
27
- return /** @type {any} */ (globalThis).__paraglide_ssr.login_please_login(inputs)
28
- }
29
- const locale = options.locale ?? getLocale()
30
- trackMessageCall("login_please_login", locale)
31
- if (locale === "en") return en_login_please_login(inputs)
32
- return pl_login_please_login(inputs)
33
- };
34
- export { login_please_login as "login.please_login" }