From e8c0362a54e6e1bcf55ed045a6f15805bb0d0144 Mon Sep 17 00:00:00 2001 From: Priec Date: Wed, 17 Jun 2026 16:15:22 +0200 Subject: [PATCH] shipping --- assets/i18n/en/main.ftl | 5 +- assets/i18n/sk/main.ftl | 5 +- assets/views/admin/shipping/index.html | 79 ++++++++--- assets/views/shop/_card.html | 35 +++-- docs/integrations/README.md | 120 +++++++++++++++++ docs/integrations/dhl.md | 150 +++++++++++++++++++++ docs/integrations/dpd.md | 147 +++++++++++++++++++++ docs/integrations/packeta.md | 174 +++++++++++++++++++++++++ src/controllers/admin_shipping.rs | 81 +++++++++++- 9 files changed, 761 insertions(+), 35 deletions(-) create mode 100644 docs/integrations/README.md create mode 100644 docs/integrations/dhl.md create mode 100644 docs/integrations/dpd.md create mode 100644 docs/integrations/packeta.md diff --git a/assets/i18n/en/main.ftl b/assets/i18n/en/main.ftl index cbe6be4..6998732 100644 --- a/assets/i18n/en/main.ftl +++ b/assets/i18n/en/main.ftl @@ -261,5 +261,8 @@ bank-account-name = Account holder bank-variable-symbol = Variable symbol bank-amount = Amount admin-shipping = Shipping -admin-shipping-desc = set carrier prices and availability. +admin-shipping-desc = add, edit and remove delivery options. shipping-enabled = Active +shipping-new = Add delivery option +shipping-add = Add +shipping-requires-pickup = Requires pickup point diff --git a/assets/i18n/sk/main.ftl b/assets/i18n/sk/main.ftl index 1d74e65..50f8bd6 100644 --- a/assets/i18n/sk/main.ftl +++ b/assets/i18n/sk/main.ftl @@ -261,5 +261,8 @@ bank-account-name = Príjemca bank-variable-symbol = Variabilný symbol bank-amount = Suma admin-shipping = Doprava -admin-shipping-desc = nastaviť cenu a dostupnosť dopravcov. +admin-shipping-desc = pridať, upraviť a odstrániť možnosti dopravy. shipping-enabled = Aktívne +shipping-new = Pridať možnosť dopravy +shipping-add = Pridať +shipping-requires-pickup = Vyžaduje výdajné miesto diff --git a/assets/views/admin/shipping/index.html b/assets/views/admin/shipping/index.html index 97d7dd1..5d80a96 100644 --- a/assets/views/admin/shipping/index.html +++ b/assets/views/admin/shipping/index.html @@ -11,27 +11,64 @@
{% for method in methods %} -
-
-

{{ method.name }}

-

{{ method.code }}{% if method.requires_pickup_point %} · {{ t(key="checkout-pickup-point", lang=lang | default(value='sk')) }}{% endif %}

-
-
- - -
- - -
+
+
+
+

{{ method.name }}

+

{{ method.code }}{% if method.requires_pickup_point %} · {{ t(key="checkout-pickup-point", lang=lang | default(value='sk')) }}{% endif %}

+
+
+ + +
+ + +
+
+ +
+
{% endfor %}
+ +
+

{{ t(key="shipping-new", lang=lang | default(value='sk')) }}

+
+ + +
+
+ + +
+ + + +
{% endblock content %} diff --git a/assets/views/shop/_card.html b/assets/views/shop/_card.html index fb1e553..3382324 100644 --- a/assets/views/shop/_card.html +++ b/assets/views/shop/_card.html @@ -1,12 +1,29 @@ - -
- {% if product.image %} - {{ product.name }} + +
+ {% if product.image %} + {{ product.name }} + {% endif %} +
+
+

{{ product.name }}

+

{{ product.price }} {{ product.currency }}

+
+
+
+ {% if product.stock > 0 %} +

{{ t(key="in-stock", lang=lang | default(value='sk')) }}: {{ product.stock }}

+
+ + + +
+ {% else %} +

{{ t(key="out-of-stock", lang=lang | default(value='sk')) }}

{% endif %}
-
-

{{ product.name }}

-

{{ product.price }} {{ product.currency }}

-
- +
diff --git a/docs/integrations/README.md b/docs/integrations/README.md new file mode 100644 index 0000000..e0f138f --- /dev/null +++ b/docs/integrations/README.md @@ -0,0 +1,120 @@ +# Carrier integrations + +This eshop manages **delivery options** as plain rows in the `shipping_methods` +table (admin UI at `/admin/shipping` — add / edit price + toggle / remove). A +delivery option is just a name, a price, and two flags. **None of that talks to +a carrier yet** — it only decides what the customer can pick and how much they +pay. + +Integrating a real carrier (Packeta, DPD, DHL) means wiring two *separate* +concerns on top of an existing delivery option: + +1. **Pickup-point selection** (checkout, browser-side) — only for carriers that + deliver to pickup points / lockers. The customer picks a point via the + carrier's JS map widget; the chosen id + name land in the order. +2. **Shipment creation** (server-side, after the order is placed) — you call the + carrier's HTTP API to register the parcel, then store the returned tracking + number and print the label. + +These are independent: you can ship to a Packeta pickup point manually (no API) +just by enabling the pickup widget, and you can create DHL labels via API for a +home-delivery option that has no pickup point at all. + +> ❗ This is **not** a many-to-many / database relationship between your tables. +> A carrier is an **external HTTP API** you call from the server. The only +> schema you add is a few columns (which carrier a method maps to; a tracking +> number on the order) — see "Shared groundwork" below. + +## What already exists in the codebase + +| Piece | Where | Status | +|---|---|---| +| Delivery option CRUD | `src/controllers/admin_shipping.rs`, `assets/views/admin/shipping/index.html` | ✅ done | +| `shipping_methods` table (`code`, `name`, `price_cents`, `requires_pickup_point`, `enabled`, `position`) | `migration/.../m20260616_150755_shipping_methods.rs` | ✅ done | +| Carrier choice + pickup fields on checkout | `assets/views/shop/checkout.html` (`carrier_code`, `pickup_point_id`, `pickup_point_name`) | ✅ done | +| Order stores carrier + pickup point | `orders` table (`carrier_code`, `carrier_name`, `pickup_point_id`, `pickup_point_name`, `shipping_cents`) | ✅ done | +| Settings lookup | `src/shared/settings.rs` → reads `settings.*` from `config/*.yaml` | ✅ done | +| Packeta pickup-point widget | `assets/views/shop/checkout.html` (loads when `packeta_api_key` set) | ✅ scaffolded | +| Shipment-creation API client (any carrier) | — | ❌ not built | +| Tracking number on order | — | ❌ not built | + +So **pickup-point selection for Packeta is already wired** — it just needs an +API key. Everything else (DPD/DHL widgets, and *all* shipment-creation API +calls) is new work, described per carrier. + +## Shared groundwork (do this once, before any carrier's API step) + +The pickup-widget half needs nothing new. The **shipment-creation** half needs: + +1. **An HTTP client dependency.** Add to `Cargo.toml`: + ```toml + reqwest = { version = "0.12", features = ["json"] } + ``` + (Loco already pulls `tokio`/`serde`/`serde_json`.) + +2. **A place for carrier clients.** Create `src/integrations/mod.rs` and a file + per carrier (`packeta.rs`, `dpd.rs`, `dhl.rs`). Register `pub mod integrations;` + in `src/lib.rs` (next to `pub mod controllers;` etc.). + +3. **Map a delivery option to a carrier.** Add a `carrier` column to + `shipping_methods` so each admin-created option knows which API (if any) to + call. Generate the migration: + ```bash + cargo loco generate migration add_carrier_to_shipping_methods carrier:string + ``` + Values: `none` (manual, the default), `packeta`, `dpd`, `dhl`. Then add a + `