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
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,33 @@
|
|
|
3
3
|
All notable changes to includio-cms are documented here.
|
|
4
4
|
Generated from `src/lib/updates/` — do not edit manually.
|
|
5
5
|
|
|
6
|
+
## 0.15.2 — 2026-04-15
|
|
7
|
+
|
|
8
|
+
Shop: cena przechowywana jako numeric(20,6) — eliminacja driftu brutto/netto po reload; toggle netto/brutto per wariant.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Warianty produktu mają teraz toggle netto/brutto obok pola "Zmiana ceny" — spójne z toggle'em ceny bazowej. Delta zapisywana kanonicznie jako netto.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- 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.
|
|
15
|
+
- Shipping: ta sama poprawka dla ceny metody wysyłki (stored jako netto PLN z 6dp).
|
|
16
|
+
|
|
17
|
+
### Breaking
|
|
18
|
+
- 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.
|
|
19
|
+
- 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.
|
|
20
|
+
|
|
21
|
+
### Migration
|
|
22
|
+
|
|
23
|
+
```sql
|
|
24
|
+
ALTER TABLE shop_products ALTER COLUMN base_price TYPE numeric(20,6) USING (base_price::numeric / 100);
|
|
25
|
+
ALTER TABLE shop_product_variants ALTER COLUMN price_delta TYPE numeric(20,6) USING (price_delta::numeric / 100);
|
|
26
|
+
ALTER TABLE shop_shipping_methods ALTER COLUMN price TYPE numeric(20,6) USING (price::numeric / 100);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Notes
|
|
30
|
+
|
|
31
|
+
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).
|
|
32
|
+
|
|
6
33
|
## 0.15.1 — 2026-04-15
|
|
7
34
|
|
|
8
35
|
Shop: PayU payment adapter + secure order access (token-gated view API, email link).
|
package/DOCS.md
CHANGED
package/ROADMAP.md
CHANGED
|
@@ -304,8 +304,13 @@
|
|
|
304
304
|
- [x] `[feature]` `[P0]` Random Crockford base32 order numbers (`XXXXX-XXXXX`), unguessable
|
|
305
305
|
- [x] `[feature]` `[P0]` CLI scaffold provisions all shop routes (admin + public API) in consumer app
|
|
306
306
|
- [x] `[feature]` `[P1]` PayU payment adapter + webhook — shipped in 0.15.1 (access-token-gated order view, idempotent webhooks, MD5 signature, shipping↔payment compat, poll fallback)
|
|
307
|
-
- [ ] `[feature]` `[P1]` Stripe payment adapter + webhook — deferred to 0.15.
|
|
307
|
+
- [ ] `[feature]` `[P1]` Stripe payment adapter + webhook — deferred to 0.15.3
|
|
308
308
|
- [ ] `[feature]` `[P2]` InPost carrier adapter (headless geowidget config) — deferred to 0.15.3
|
|
309
|
+
|
|
310
|
+
## 0.15.2 — Price precision fix
|
|
311
|
+
|
|
312
|
+
- [x] `[fix]` `[P1]` Price drift on reload — storage jako `numeric(20,6)` (PLN z 6dp), brutto round-tripuje bez utraty ±1gr. Snapshot zamówienia dalej w groszach (KSeF). <!-- files: src/lib/db-postgres/schema/shop/product.ts, productVariant.ts, shippingMethod.ts, src/lib/shop/pricing.ts, src/lib/shop/server/cart-hydrate.ts, shipping.ts, shop-data.ts, src/lib/admin/components/fields/shop-field.svelte, src/lib/admin/client/shop/shipping-method-form.svelte -->
|
|
313
|
+
- [x] `[feature]` `[P2]` Variant price toggle netto/brutto (spójne z toggle\'em ceny bazowej)
|
|
309
314
|
- [x] `[feature]` `[P2]` `nodemailerAdapter` — typowanie `transportOptions` jako `SMTPTransport.Options` (OAuth2, pool, itd.)
|
|
310
315
|
|
|
311
316
|
## 0.16.0 — SEO module
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
export interface ShippingFormPayload {
|
|
11
11
|
name: Record<string, string>;
|
|
12
12
|
description: Record<string, string> | null;
|
|
13
|
-
price: number;
|
|
13
|
+
price: number; // PLN (number, netto)
|
|
14
14
|
vatRate: number;
|
|
15
15
|
carrierType: CarrierType;
|
|
16
|
-
conditions: { freeAbove?: number } | null;
|
|
16
|
+
conditions: { freeAbove?: number } | null; // freeAbove: grosze
|
|
17
17
|
allowedPaymentMethods: string[] | null;
|
|
18
18
|
isActive: boolean;
|
|
19
19
|
sortOrder: number | null;
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
export interface ShippingFormInitial {
|
|
22
22
|
name?: Record<string, string> | unknown;
|
|
23
23
|
description?: Record<string, string> | unknown | null;
|
|
24
|
-
price?: number;
|
|
24
|
+
price?: number | string;
|
|
25
25
|
vatRate?: number;
|
|
26
26
|
carrierType?: string;
|
|
27
27
|
conditions?: { freeAbove?: number } | null;
|
|
@@ -69,29 +69,32 @@
|
|
|
69
69
|
)
|
|
70
70
|
);
|
|
71
71
|
type InputMode = 'net' | 'gross';
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
// initial.price — teraz PLN (number, netto) z API. Hydratujemy jako gross, żeby user widział dokładnie to co wpisał.
|
|
73
|
+
const initialNetPln = initial?.price != null ? Number(initial.price) : null;
|
|
74
|
+
const initialVat = Number(initial?.vatRate ?? vatRates[0] ?? 23);
|
|
75
|
+
let inputMode = $state<InputMode>(initialNetPln != null ? 'gross' : 'gross');
|
|
76
|
+
let inputPrice = $state(
|
|
77
|
+
initialNetPln != null
|
|
78
|
+
? (initialNetPln * (1 + initialVat / 100)).toFixed(2)
|
|
79
|
+
: '0.00'
|
|
80
|
+
);
|
|
74
81
|
let vatRate = $state<number | string>(initial?.vatRate ?? vatRates[0] ?? 23);
|
|
75
82
|
|
|
76
|
-
const
|
|
83
|
+
const inputPln = $derived(parseFloat(inputPrice || '0') || 0);
|
|
77
84
|
const vat = $derived(Number(vatRate) || 0);
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
);
|
|
81
|
-
const grossCents = $derived(
|
|
82
|
-
inputMode === 'gross' ? inputPriceCents : Math.round(inputPriceCents * (1 + vat / 100))
|
|
83
|
-
);
|
|
84
|
-
const vatCents = $derived(grossCents - netCents);
|
|
85
|
+
const netPln = $derived(inputMode === 'net' ? inputPln : inputPln / (1 + vat / 100));
|
|
86
|
+
const grossPln = $derived(inputMode === 'gross' ? inputPln : inputPln * (1 + vat / 100));
|
|
87
|
+
const vatPln = $derived(grossPln - netPln);
|
|
85
88
|
|
|
86
|
-
function
|
|
87
|
-
return
|
|
89
|
+
function formatPln(pln: number) {
|
|
90
|
+
return pln.toFixed(2);
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
function switchMode(newMode: InputMode) {
|
|
91
94
|
if (newMode === inputMode) return;
|
|
92
|
-
const
|
|
95
|
+
const preserved = newMode === 'net' ? netPln : grossPln;
|
|
93
96
|
inputMode = newMode;
|
|
94
|
-
inputPrice =
|
|
97
|
+
inputPrice = formatPln(preserved);
|
|
95
98
|
}
|
|
96
99
|
let carrierType = $state<CarrierType>((initial?.carrierType as CarrierType) ?? 'none');
|
|
97
100
|
let isActive = $state(initial?.isActive ?? true);
|
|
@@ -126,7 +129,7 @@
|
|
|
126
129
|
await onsubmit({
|
|
127
130
|
name: names,
|
|
128
131
|
description: Object.values(descriptions).some((d) => d.length > 0) ? descriptions : null,
|
|
129
|
-
price:
|
|
132
|
+
price: netPln,
|
|
130
133
|
vatRate: Number(vatRate),
|
|
131
134
|
carrierType,
|
|
132
135
|
conditions: freeAboveEnabled
|
|
@@ -226,15 +229,15 @@
|
|
|
226
229
|
<div class="bg-muted/40 border-border grid grid-cols-3 gap-2 rounded-lg border p-2.5 text-center text-xs">
|
|
227
230
|
<div>
|
|
228
231
|
<div class="text-muted-foreground font-semibold uppercase tracking-wide">Netto</div>
|
|
229
|
-
<div class="text-sm font-bold tabular-nums">{
|
|
232
|
+
<div class="text-sm font-bold tabular-nums">{formatPln(netPln)} zł</div>
|
|
230
233
|
</div>
|
|
231
234
|
<div class="border-border border-x">
|
|
232
235
|
<div class="text-muted-foreground font-semibold uppercase tracking-wide">VAT</div>
|
|
233
|
-
<div class="text-sm font-bold tabular-nums">{
|
|
236
|
+
<div class="text-sm font-bold tabular-nums">{formatPln(vatPln)} zł</div>
|
|
234
237
|
</div>
|
|
235
238
|
<div>
|
|
236
239
|
<div class="text-muted-foreground font-semibold uppercase tracking-wide">Brutto</div>
|
|
237
|
-
<div class="text-primary text-sm font-bold tabular-nums">{
|
|
240
|
+
<div class="text-primary text-sm font-bold tabular-nums">{formatPln(grossPln)} zł</div>
|
|
238
241
|
</div>
|
|
239
242
|
</div>
|
|
240
243
|
<label class="flex items-center gap-2">
|
|
@@ -19,7 +19,7 @@ export interface ShippingFormPayload {
|
|
|
19
19
|
export interface ShippingFormInitial {
|
|
20
20
|
name?: Record<string, string> | unknown;
|
|
21
21
|
description?: Record<string, string> | unknown | null;
|
|
22
|
-
price?: number;
|
|
22
|
+
price?: number | string;
|
|
23
23
|
vatRate?: number;
|
|
24
24
|
carrierType?: string;
|
|
25
25
|
conditions?: {
|
|
@@ -35,12 +35,15 @@
|
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
function
|
|
38
|
+
function formatPricePln(pln: number) {
|
|
39
39
|
return new Intl.NumberFormat('pl-PL', {
|
|
40
40
|
style: 'currency',
|
|
41
41
|
currency: 'PLN',
|
|
42
42
|
minimumFractionDigits: 2
|
|
43
|
-
}).format(
|
|
43
|
+
}).format(pln);
|
|
44
|
+
}
|
|
45
|
+
function formatPriceCents(cents: number) {
|
|
46
|
+
return formatPricePln(cents / 100);
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
async function doReorder(fromIndex: number, toIndex: number) {
|
|
@@ -143,11 +146,11 @@
|
|
|
143
146
|
{resolveI18n(m.name as Record<string, string>, interfaceLanguage.current, '')}
|
|
144
147
|
</a>
|
|
145
148
|
</div>
|
|
146
|
-
<div>{
|
|
149
|
+
<div>{formatPricePln(Number(m.price))}</div>
|
|
147
150
|
<div>{m.vatRate}%</div>
|
|
148
151
|
<div>
|
|
149
152
|
{#if cond?.freeAbove != null}
|
|
150
|
-
{
|
|
153
|
+
{formatPriceCents(cond.freeAbove)}
|
|
151
154
|
{:else}
|
|
152
155
|
<span class="text-muted-foreground text-xs">—</span>
|
|
153
156
|
{/if}
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
const entriesQuery = $derived(remotes.listShopProductEntries());
|
|
14
14
|
const collectionsQuery = $derived(remotes.listShopableCollections());
|
|
15
15
|
|
|
16
|
-
function formatPrice(
|
|
16
|
+
function formatPrice(pln: number) {
|
|
17
17
|
return new Intl.NumberFormat('pl-PL', {
|
|
18
18
|
style: 'currency',
|
|
19
19
|
currency: 'PLN',
|
|
20
20
|
minimumFractionDigits: 2
|
|
21
|
-
}).format(
|
|
21
|
+
}).format(pln);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
function resolveTitle(data: Record<string, unknown> | null, fallback: string): string {
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
sku: string;
|
|
28
28
|
name: string;
|
|
29
29
|
priceDelta: string;
|
|
30
|
+
priceDeltaMode: InputMode;
|
|
30
31
|
stock: string;
|
|
31
32
|
}>
|
|
32
33
|
>([]);
|
|
@@ -36,35 +37,34 @@
|
|
|
36
37
|
let errorMessage = $state<string | null>(null);
|
|
37
38
|
let successMessage = $state<string | null>(null);
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
// PLN-precise math — storage w numeric(20,6). Round do groszy tylko przy prezentacji.
|
|
41
|
+
const inputPln = $derived(parseFloat(inputPrice || '0') || 0);
|
|
40
42
|
const vat = $derived(Number(vatRate) || 0);
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
);
|
|
44
|
-
const grossCents = $derived(
|
|
45
|
-
inputMode === 'gross' ? inputPriceCents : Math.round(inputPriceCents * (1 + vat / 100))
|
|
46
|
-
);
|
|
47
|
-
const vatCents = $derived(grossCents - netCents);
|
|
43
|
+
const netPln = $derived(inputMode === 'net' ? inputPln : inputPln / (1 + vat / 100));
|
|
44
|
+
const grossPln = $derived(inputMode === 'gross' ? inputPln : inputPln * (1 + vat / 100));
|
|
45
|
+
const vatPln = $derived(grossPln - netPln);
|
|
48
46
|
|
|
49
|
-
function
|
|
50
|
-
return
|
|
47
|
+
function formatPln(pln: number) {
|
|
48
|
+
return pln.toFixed(2);
|
|
51
49
|
}
|
|
52
50
|
|
|
53
51
|
function switchMode(newMode: InputMode) {
|
|
54
52
|
if (newMode === inputMode) return;
|
|
55
53
|
// Preserve economic value — if user typed gross, switch shows net (computed) in the input, and vice versa.
|
|
56
|
-
const
|
|
54
|
+
const preservedPln = newMode === 'net' ? netPln : grossPln;
|
|
57
55
|
inputMode = newMode;
|
|
58
|
-
inputPrice =
|
|
56
|
+
inputPrice = formatPln(preservedPln);
|
|
59
57
|
}
|
|
60
58
|
|
|
61
59
|
$effect(() => {
|
|
62
60
|
if (!loaded && dataQuery.ready && configQuery.ready) {
|
|
63
61
|
const shop = dataQuery.current;
|
|
64
62
|
if (shop) {
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
// Hydratacja: pokazujemy brutto (zaokrąglone do 2dp) — user widzi dokładnie to co wpisał
|
|
64
|
+
// jeśli wpisywał w trybie gross (bo netto w DB ma 6dp → brutto round-tripuje bez driftu).
|
|
65
|
+
inputMode = 'gross';
|
|
66
|
+
const grossInitial = Number(shop.basePrice) * (1 + Number(shop.vatRate) / 100);
|
|
67
|
+
inputPrice = formatPln(grossInitial);
|
|
68
68
|
vatRate = shop.vatRate;
|
|
69
69
|
isActive = shop.isActive;
|
|
70
70
|
variants = shop.variants.map((v) => ({
|
|
@@ -76,7 +76,9 @@
|
|
|
76
76
|
Object.values(v.name as Record<string, string>)[0] ?? ''
|
|
77
77
|
)
|
|
78
78
|
: '',
|
|
79
|
-
|
|
79
|
+
// Delta hydratowana jako netto (kanoniczna), mode default 'net' dla istniejących.
|
|
80
|
+
priceDelta: formatPln(Number(v.priceDelta)),
|
|
81
|
+
priceDeltaMode: 'net' as InputMode,
|
|
80
82
|
stock: v.stock == null ? '' : String(v.stock)
|
|
81
83
|
}));
|
|
82
84
|
} else {
|
|
@@ -87,16 +89,31 @@
|
|
|
87
89
|
}
|
|
88
90
|
});
|
|
89
91
|
|
|
92
|
+
// Konwersja delty variantu (w trybie wpisu user'a) do netto PLN (kanonicznego).
|
|
93
|
+
function variantDeltaNetPln(v: { priceDelta: string; priceDeltaMode: InputMode }): number {
|
|
94
|
+
const raw = parseFloat(v.priceDelta || '0') || 0;
|
|
95
|
+
return v.priceDeltaMode === 'net' ? raw : raw / (1 + vat / 100);
|
|
96
|
+
}
|
|
97
|
+
|
|
90
98
|
function addVariant() {
|
|
91
99
|
variants.push({
|
|
92
100
|
id: undefined,
|
|
93
101
|
sku: '',
|
|
94
102
|
name: '',
|
|
95
103
|
priceDelta: '0.00',
|
|
104
|
+
priceDeltaMode: 'gross',
|
|
96
105
|
stock: ''
|
|
97
106
|
});
|
|
98
107
|
}
|
|
99
108
|
|
|
109
|
+
function switchVariantMode(i: number, newMode: InputMode) {
|
|
110
|
+
const v = variants[i];
|
|
111
|
+
if (v.priceDeltaMode === newMode) return;
|
|
112
|
+
const netDelta = variantDeltaNetPln(v);
|
|
113
|
+
const preserved = newMode === 'net' ? netDelta : netDelta * (1 + vat / 100);
|
|
114
|
+
variants[i] = { ...v, priceDeltaMode: newMode, priceDelta: formatPln(preserved) };
|
|
115
|
+
}
|
|
116
|
+
|
|
100
117
|
function removeVariant(i: number) {
|
|
101
118
|
variants.splice(i, 1);
|
|
102
119
|
}
|
|
@@ -115,7 +132,7 @@
|
|
|
115
132
|
await remotes.upsertShopDataForEntry({
|
|
116
133
|
entryId,
|
|
117
134
|
data: {
|
|
118
|
-
basePrice:
|
|
135
|
+
basePrice: netPln,
|
|
119
136
|
vatRate: Number(vatRate),
|
|
120
137
|
isActive
|
|
121
138
|
},
|
|
@@ -124,7 +141,7 @@
|
|
|
124
141
|
id: v.id,
|
|
125
142
|
sku: v.sku || null,
|
|
126
143
|
name: v.name ? { pl: v.name } : null,
|
|
127
|
-
priceDelta:
|
|
144
|
+
priceDelta: variantDeltaNetPln(v),
|
|
128
145
|
stock: stockEnabled && v.stock !== '' ? parseInt(v.stock, 10) : null,
|
|
129
146
|
attributes: null
|
|
130
147
|
}))
|
|
@@ -210,15 +227,15 @@
|
|
|
210
227
|
<div class="bg-muted/40 border-border grid grid-cols-3 gap-2 rounded-lg border p-2.5 text-center text-xs">
|
|
211
228
|
<div>
|
|
212
229
|
<div class="text-muted-foreground font-semibold uppercase tracking-wide">Netto</div>
|
|
213
|
-
<div class="text-sm font-bold tabular-nums">{
|
|
230
|
+
<div class="text-sm font-bold tabular-nums">{formatPln(netPln)} zł</div>
|
|
214
231
|
</div>
|
|
215
232
|
<div class="border-border border-x">
|
|
216
233
|
<div class="text-muted-foreground font-semibold uppercase tracking-wide">VAT</div>
|
|
217
|
-
<div class="text-sm font-bold tabular-nums">{
|
|
234
|
+
<div class="text-sm font-bold tabular-nums">{formatPln(vatPln)} zł</div>
|
|
218
235
|
</div>
|
|
219
236
|
<div>
|
|
220
237
|
<div class="text-muted-foreground font-semibold uppercase tracking-wide">Brutto</div>
|
|
221
|
-
<div class="text-primary text-sm font-bold tabular-nums">{
|
|
238
|
+
<div class="text-primary text-sm font-bold tabular-nums">{formatPln(grossPln)} zł</div>
|
|
222
239
|
</div>
|
|
223
240
|
</div>
|
|
224
241
|
</div>
|
|
@@ -253,7 +270,31 @@
|
|
|
253
270
|
/>
|
|
254
271
|
</label>
|
|
255
272
|
<label class="block">
|
|
256
|
-
<
|
|
273
|
+
<div class="mb-0.5 flex items-center justify-between gap-1">
|
|
274
|
+
<span class="text-muted-foreground text-xs">
|
|
275
|
+
Zmiana ceny ({v.priceDeltaMode === 'net' ? 'netto' : 'brutto'}, PLN)
|
|
276
|
+
</span>
|
|
277
|
+
<div class="bg-muted inline-flex rounded-md p-0.5 text-[10px]">
|
|
278
|
+
<button
|
|
279
|
+
type="button"
|
|
280
|
+
class="rounded px-1.5 py-0.5 {v.priceDeltaMode === 'net'
|
|
281
|
+
? 'bg-background text-primary font-semibold shadow-sm'
|
|
282
|
+
: 'text-muted-foreground'}"
|
|
283
|
+
onclick={() => switchVariantMode(i, 'net')}
|
|
284
|
+
>
|
|
285
|
+
Netto
|
|
286
|
+
</button>
|
|
287
|
+
<button
|
|
288
|
+
type="button"
|
|
289
|
+
class="rounded px-1.5 py-0.5 {v.priceDeltaMode === 'gross'
|
|
290
|
+
? 'bg-background text-primary font-semibold shadow-sm'
|
|
291
|
+
: 'text-muted-foreground'}"
|
|
292
|
+
onclick={() => switchVariantMode(i, 'gross')}
|
|
293
|
+
>
|
|
294
|
+
Brutto
|
|
295
|
+
</button>
|
|
296
|
+
</div>
|
|
297
|
+
</div>
|
|
257
298
|
<input
|
|
258
299
|
type="number"
|
|
259
300
|
step="0.01"
|
|
@@ -31,36 +31,8 @@ export declare const upsertShopDataForEntry: import("@sveltejs/kit").RemoteComma
|
|
|
31
31
|
export declare const deleteShopDataForEntry: import("@sveltejs/kit").RemoteCommand<string, Promise<{
|
|
32
32
|
success: boolean;
|
|
33
33
|
}>>;
|
|
34
|
-
export declare const listShippingMethodsAdmin: import("@sveltejs/kit").RemoteQueryFunction<void,
|
|
35
|
-
|
|
36
|
-
name: Record<string, string>;
|
|
37
|
-
createdAt: Date;
|
|
38
|
-
sortOrder: number | null;
|
|
39
|
-
description: Record<string, string> | null;
|
|
40
|
-
vatRate: number;
|
|
41
|
-
isActive: boolean;
|
|
42
|
-
price: number;
|
|
43
|
-
carrierType: string;
|
|
44
|
-
conditions: {
|
|
45
|
-
freeAbove?: number;
|
|
46
|
-
} | null;
|
|
47
|
-
allowedPaymentMethods: string[] | null;
|
|
48
|
-
}[]>;
|
|
49
|
-
export declare const getShippingMethodForAdmin: import("@sveltejs/kit").RemoteQueryFunction<string, {
|
|
50
|
-
id: string;
|
|
51
|
-
name: Record<string, string>;
|
|
52
|
-
createdAt: Date;
|
|
53
|
-
sortOrder: number | null;
|
|
54
|
-
description: Record<string, string> | null;
|
|
55
|
-
vatRate: number;
|
|
56
|
-
isActive: boolean;
|
|
57
|
-
price: number;
|
|
58
|
-
carrierType: string;
|
|
59
|
-
conditions: {
|
|
60
|
-
freeAbove?: number;
|
|
61
|
-
} | null;
|
|
62
|
-
allowedPaymentMethods: string[] | null;
|
|
63
|
-
} | null>;
|
|
34
|
+
export declare const listShippingMethodsAdmin: import("@sveltejs/kit").RemoteQueryFunction<void, import("../../shop/server/shipping.js").ShippingMethodRow[]>;
|
|
35
|
+
export declare const getShippingMethodForAdmin: import("@sveltejs/kit").RemoteQueryFunction<string, import("../../shop/server/shipping.js").ShippingMethodRow | null>;
|
|
64
36
|
export declare const createShippingMethodCmd: import("@sveltejs/kit").RemoteCommand<{
|
|
65
37
|
name: Record<string, string>;
|
|
66
38
|
price: number;
|
|
@@ -73,21 +45,7 @@ export declare const createShippingMethodCmd: import("@sveltejs/kit").RemoteComm
|
|
|
73
45
|
allowedPaymentMethods?: string[] | null | undefined;
|
|
74
46
|
isActive?: boolean | undefined;
|
|
75
47
|
sortOrder?: number | null | undefined;
|
|
76
|
-
}, Promise<
|
|
77
|
-
id: string;
|
|
78
|
-
name: Record<string, string>;
|
|
79
|
-
createdAt: Date;
|
|
80
|
-
sortOrder: number | null;
|
|
81
|
-
description: Record<string, string> | null;
|
|
82
|
-
vatRate: number;
|
|
83
|
-
isActive: boolean;
|
|
84
|
-
price: number;
|
|
85
|
-
carrierType: string;
|
|
86
|
-
conditions: {
|
|
87
|
-
freeAbove?: number;
|
|
88
|
-
} | null;
|
|
89
|
-
allowedPaymentMethods: string[] | null;
|
|
90
|
-
}>>;
|
|
48
|
+
}, Promise<import("../../shop/server/shipping.js").ShippingMethodRow>>;
|
|
91
49
|
export declare const updateShippingMethodCmd: import("@sveltejs/kit").RemoteCommand<{
|
|
92
50
|
id: string;
|
|
93
51
|
input: {
|
|
@@ -103,21 +61,7 @@ export declare const updateShippingMethodCmd: import("@sveltejs/kit").RemoteComm
|
|
|
103
61
|
isActive?: boolean | undefined;
|
|
104
62
|
sortOrder?: number | null | undefined;
|
|
105
63
|
};
|
|
106
|
-
}, Promise<
|
|
107
|
-
id: string;
|
|
108
|
-
name: Record<string, string>;
|
|
109
|
-
createdAt: Date;
|
|
110
|
-
sortOrder: number | null;
|
|
111
|
-
description: Record<string, string> | null;
|
|
112
|
-
vatRate: number;
|
|
113
|
-
isActive: boolean;
|
|
114
|
-
price: number;
|
|
115
|
-
carrierType: string;
|
|
116
|
-
conditions: {
|
|
117
|
-
freeAbove?: number;
|
|
118
|
-
} | null;
|
|
119
|
-
allowedPaymentMethods: string[] | null;
|
|
120
|
-
}>>;
|
|
64
|
+
}, Promise<import("../../shop/server/shipping.js").ShippingMethodRow>>;
|
|
121
65
|
export declare const deleteShippingMethodCmd: import("@sveltejs/kit").RemoteCommand<string, Promise<{
|
|
122
66
|
success: boolean;
|
|
123
67
|
}>>;
|
|
@@ -31,7 +31,7 @@ export const getShopDataForEntry = query(z.string(), async (entryId) => {
|
|
|
31
31
|
return getShopDataByEntry(entryId);
|
|
32
32
|
});
|
|
33
33
|
const shopDataInputSchema = z.object({
|
|
34
|
-
basePrice: z.number().
|
|
34
|
+
basePrice: z.number().nonnegative().max(1e9), // PLN (≤6dp)
|
|
35
35
|
vatRate: z.number().int().min(0).max(100),
|
|
36
36
|
isActive: z.boolean().optional(),
|
|
37
37
|
sortOrder: z.number().int().nullable().optional()
|
|
@@ -40,7 +40,7 @@ const variantInputSchema = z.object({
|
|
|
40
40
|
id: z.string().optional(),
|
|
41
41
|
sku: z.string().nullable().optional(),
|
|
42
42
|
name: z.record(z.string(), z.string()).nullable().optional(),
|
|
43
|
-
priceDelta: z.number().
|
|
43
|
+
priceDelta: z.number().optional(), // PLN
|
|
44
44
|
stock: z.number().int().nullable().optional(),
|
|
45
45
|
attributes: z.record(z.string(), z.string()).nullable().optional()
|
|
46
46
|
});
|
|
@@ -60,7 +60,7 @@ export const deleteShopDataForEntry = command(z.string(), async (entryId) => {
|
|
|
60
60
|
const shippingMethodInputSchema = z.object({
|
|
61
61
|
name: z.record(z.string(), z.string()),
|
|
62
62
|
description: z.record(z.string(), z.string()).nullable().optional(),
|
|
63
|
-
price: z.number().
|
|
63
|
+
price: z.number().nonnegative().max(1e9), // PLN netto (≤6dp)
|
|
64
64
|
vatRate: z.number().int().min(0).max(100),
|
|
65
65
|
carrierType: z.string().optional(),
|
|
66
66
|
conditions: z
|
|
@@ -39,10 +39,10 @@ export declare const shopProductsTable: import("drizzle-orm/pg-core/table", { wi
|
|
|
39
39
|
basePrice: import("drizzle-orm/pg-core", { with: { "resolution-mode": "require" } }).PgColumn<{
|
|
40
40
|
name: "base_price";
|
|
41
41
|
tableName: "shop_products";
|
|
42
|
-
dataType: "
|
|
43
|
-
columnType: "
|
|
44
|
-
data:
|
|
45
|
-
driverParam: string
|
|
42
|
+
dataType: "string";
|
|
43
|
+
columnType: "PgNumeric";
|
|
44
|
+
data: string;
|
|
45
|
+
driverParam: string;
|
|
46
46
|
notNull: true;
|
|
47
47
|
hasDefault: false;
|
|
48
48
|
isPrimaryKey: false;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { boolean, integer, pgTable, timestamp, uuid } from 'drizzle-orm/pg-core';
|
|
1
|
+
import { boolean, integer, numeric, pgTable, timestamp, uuid } from 'drizzle-orm/pg-core';
|
|
2
2
|
import { entriesTable } from '../entry.js';
|
|
3
3
|
export const shopProductsTable = pgTable('shop_products', {
|
|
4
4
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
@@ -6,7 +6,8 @@ export const shopProductsTable = pgTable('shop_products', {
|
|
|
6
6
|
.notNull()
|
|
7
7
|
.unique()
|
|
8
8
|
.references(() => entriesTable.id, { onDelete: 'cascade' }),
|
|
9
|
-
|
|
9
|
+
// PLN z 6dp (wzorzec PrestaShop DECIMAL(20,6)) — netto kanoniczne. Konwersja do groszy raz, przy snapshot zamówienia.
|
|
10
|
+
basePrice: numeric('base_price', { precision: 20, scale: 6 }).notNull(),
|
|
10
11
|
vatRate: integer('vat_rate').notNull(),
|
|
11
12
|
isActive: boolean('is_active').default(true).notNull(),
|
|
12
13
|
sortOrder: integer('sort_order'),
|
|
@@ -75,10 +75,10 @@ export declare const shopProductVariantsTable: import("drizzle-orm/pg-core/table
|
|
|
75
75
|
priceDelta: import("drizzle-orm/pg-core", { with: { "resolution-mode": "require" } }).PgColumn<{
|
|
76
76
|
name: "price_delta";
|
|
77
77
|
tableName: "shop_product_variants";
|
|
78
|
-
dataType: "
|
|
79
|
-
columnType: "
|
|
80
|
-
data:
|
|
81
|
-
driverParam: string
|
|
78
|
+
dataType: "string";
|
|
79
|
+
columnType: "PgNumeric";
|
|
80
|
+
data: string;
|
|
81
|
+
driverParam: string;
|
|
82
82
|
notNull: true;
|
|
83
83
|
hasDefault: true;
|
|
84
84
|
isPrimaryKey: false;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { integer, jsonb, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
|
1
|
+
import { integer, jsonb, numeric, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
|
2
2
|
import { shopProductsTable } from './product.js';
|
|
3
3
|
export const shopProductVariantsTable = pgTable('shop_product_variants', {
|
|
4
4
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
@@ -7,7 +7,8 @@ export const shopProductVariantsTable = pgTable('shop_product_variants', {
|
|
|
7
7
|
.references(() => shopProductsTable.id, { onDelete: 'cascade' }),
|
|
8
8
|
sku: text('sku'),
|
|
9
9
|
name: jsonb('name').$type(),
|
|
10
|
-
|
|
10
|
+
// PLN z 6dp (netto delta, może być ujemne w przyszłości — obecnie schema nonneg)
|
|
11
|
+
priceDelta: numeric('price_delta', { precision: 20, scale: 6 }).default('0').notNull(),
|
|
11
12
|
stock: integer('stock'),
|
|
12
13
|
attributes: jsonb('attributes').$type(),
|
|
13
14
|
sortOrder: integer('sort_order'),
|
|
@@ -61,10 +61,10 @@ export declare const shopShippingMethodsTable: import("drizzle-orm/pg-core/table
|
|
|
61
61
|
price: import("drizzle-orm/pg-core", { with: { "resolution-mode": "require" } }).PgColumn<{
|
|
62
62
|
name: "price";
|
|
63
63
|
tableName: "shop_shipping_methods";
|
|
64
|
-
dataType: "
|
|
65
|
-
columnType: "
|
|
66
|
-
data:
|
|
67
|
-
driverParam: string
|
|
64
|
+
dataType: "string";
|
|
65
|
+
columnType: "PgNumeric";
|
|
66
|
+
data: string;
|
|
67
|
+
driverParam: string;
|
|
68
68
|
notNull: true;
|
|
69
69
|
hasDefault: false;
|
|
70
70
|
isPrimaryKey: false;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { boolean, integer, jsonb, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
|
1
|
+
import { boolean, integer, jsonb, numeric, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
|
2
2
|
export const shopShippingMethodsTable = pgTable('shop_shipping_methods', {
|
|
3
3
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
4
4
|
name: jsonb('name').$type().notNull(),
|
|
5
5
|
description: jsonb('description').$type(),
|
|
6
|
-
|
|
6
|
+
// PLN z 6dp, netto kanoniczne. freeAbove (w conditions) — cents/grosze (porównywane z totalGross w groszach).
|
|
7
|
+
price: numeric('price', { precision: 20, scale: 6 }).notNull(),
|
|
7
8
|
vatRate: integer('vat_rate').notNull(),
|
|
8
9
|
carrierType: text('carrier_type').$type().default('none').notNull(),
|
|
9
10
|
conditions: jsonb('conditions').$type(),
|
|
@@ -1,3 +1,36 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export function hello_world(inputs: {
|
|
2
|
+
name: NonNullable<unknown>;
|
|
3
|
+
}, options?: {
|
|
4
|
+
locale?: "en" | "pl";
|
|
5
|
+
}): string;
|
|
6
|
+
/**
|
|
7
|
+
* This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
|
|
8
|
+
*
|
|
9
|
+
* - Changing this function will be over-written by the next build.
|
|
10
|
+
*
|
|
11
|
+
* - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
|
|
12
|
+
* use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
|
|
13
|
+
*
|
|
14
|
+
* @param {{}} inputs
|
|
15
|
+
* @param {{ locale?: "en" | "pl" }} options
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
declare function login_hello(inputs?: {}, options?: {
|
|
19
|
+
locale?: "en" | "pl";
|
|
20
|
+
}): string;
|
|
21
|
+
/**
|
|
22
|
+
* This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
|
|
23
|
+
*
|
|
24
|
+
* - Changing this function will be over-written by the next build.
|
|
25
|
+
*
|
|
26
|
+
* - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
|
|
27
|
+
* use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
|
|
28
|
+
*
|
|
29
|
+
* @param {{}} inputs
|
|
30
|
+
* @param {{ locale?: "en" | "pl" }} options
|
|
31
|
+
* @returns {string}
|
|
32
|
+
*/
|
|
33
|
+
declare function login_please_login(inputs?: {}, options?: {
|
|
34
|
+
locale?: "en" | "pl";
|
|
35
|
+
}): string;
|
|
36
|
+
export { login_hello as login.hello, login_please_login as login.please_login };
|