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.
- package/CHANGELOG.md +27 -0
- package/DOCS.md +1 -1
- package/ROADMAP.md +6 -1
- package/dist/admin/client/shop/shipping-method-form.svelte +24 -21
- package/dist/admin/client/shop/shipping-method-form.svelte.d.ts +1 -1
- package/dist/admin/client/shop/shipping-methods-list-page.svelte +7 -4
- package/dist/admin/client/shop/shop-products-list-page.svelte +2 -2
- package/dist/admin/components/fields/shop-field.svelte +63 -22
- package/dist/admin/remote/shop.remote.d.ts +4 -60
- package/dist/admin/remote/shop.remote.js +3 -3
- package/dist/db-postgres/schema/shop/product.d.ts +4 -4
- package/dist/db-postgres/schema/shop/product.js +3 -2
- package/dist/db-postgres/schema/shop/productVariant.d.ts +4 -4
- package/dist/db-postgres/schema/shop/productVariant.js +3 -2
- package/dist/db-postgres/schema/shop/shippingMethod.d.ts +4 -4
- package/dist/db-postgres/schema/shop/shippingMethod.js +3 -2
- package/dist/paraglide/messages/_index.d.ts +36 -3
- package/dist/paraglide/messages/_index.js +71 -3
- package/dist/paraglide/messages/en.d.ts +5 -0
- package/dist/paraglide/messages/en.js +14 -0
- package/dist/paraglide/messages/pl.d.ts +5 -0
- package/dist/paraglide/messages/pl.js +14 -0
- package/dist/shop/client/index.d.ts +1 -0
- package/dist/shop/pricing.d.ts +4 -0
- package/dist/shop/pricing.js +18 -0
- package/dist/shop/server/cart-hydrate.js +6 -3
- package/dist/shop/server/populate.d.ts +2 -0
- package/dist/shop/server/shipping.d.ts +11 -4
- package/dist/shop/server/shipping.js +21 -14
- package/dist/shop/server/shop-data.d.ts +8 -2
- package/dist/shop/server/shop-data.js +18 -10
- package/dist/updates/0.15.2/index.d.ts +2 -0
- package/dist/updates/0.15.2/index.js +18 -0
- package/dist/updates/index.js +2 -1
- package/package.json +1 -1
- package/dist/paraglide/messages/hello_world.d.ts +0 -5
- package/dist/paraglide/messages/hello_world.js +0 -33
- package/dist/paraglide/messages/login_hello.d.ts +0 -16
- package/dist/paraglide/messages/login_hello.js +0 -34
- package/dist/paraglide/messages/login_please_login.d.ts +0 -16
- package/dist/paraglide/messages/login_please_login.js +0 -34
|
@@ -1,4 +1,72 @@
|
|
|
1
1
|
/* eslint-disable */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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,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,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;
|
package/dist/shop/pricing.d.ts
CHANGED
|
@@ -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;
|
package/dist/shop/pricing.js
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
98
|
-
const
|
|
97
|
+
// basePrice/priceDelta są 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
|
-
|
|
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
|
-
*
|
|
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:
|
|
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 {
|
|
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.
|
|
10
|
-
throw new Error('price must be non-negative
|
|
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
|
-
|
|
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
|
|
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
|
-
*
|
|
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
|
|
112
|
-
|
|
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
|
-
|
|
3
|
-
|
|
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.
|
|
8
|
-
throw new Error('basePrice must be a non-negative
|
|
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:
|
|
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:
|
|
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
|
|
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,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
|
+
};
|
package/dist/updates/index.js
CHANGED
|
@@ -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
|
-
|
|
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,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" }
|