diff --git a/CHANGELOG.md b/CHANGELOG.md index b30b9b9..e3df1cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,107 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +## [0.29.0] - 2026-09-30 +### Added +- **ELTA Courier** carrier (`elta` shipping driver): rates, shipment creation, + tracking, and labels rendered locally in ELTA's own A4 / A6 voucher layout. + Configured through `ELTA_*` env variables (`ELTA_APOST_CODE`, + `ELTA_USER_CODE`, `ELTA_SENDER_*`, `ELTA_LABEL_PAPER_SIZE`, …). Vouchers + are created pending and issued when first printed, so they can be + cancelled until then; once issued, ELTA has to cancel them. +- **Pending Vouchers** now has an ELTA tab next to ACS. Print opens the label + (issuing the voucher), Cancel cancels with the carrier, and **Print + selected** returns one combined PDF for carriers that support it (ELTA). + Issue Manifest only shows on tabs for carriers that batch (ACS). +- **Carrier Vouchers** screen (Sales): every voucher with a number, including + the ones carriers report that we don't have (daily sync of the last 14 + days, plus **Sync now** and **Look up voucher**). Tabs All / Unlinked / + Returns. Each sync also brings every voucher it sees up to date: new + tracking checkpoints for all of them (ours included), and the carrier's + latest details for the ones that came from the carrier. **Status** is ours (normalized, the same on every carrier) and + **Carrier status** is the carrier's own wording. A view page per voucher + has its details (recipient, COD, + extra services, return info, suggested orders, tracking history). Vouchers + are never linked to an order automatically: each gets suggested orders + (the order its reference points to first, then same postcode and phone or + name), and staff link it with **Link to order**. Supported for ELTA, Box + Now and ACS + (finalized vouchers only). +- **Manual carriers**: a new "Manual carrier" shipping driver for couriers + without an integration. The shipping method holds the carrier name, an + optional tracking URL template (`{number}` = voucher number) and whether the + courier collects cash on delivery. Its shipments are created from the order + page, and staff add tracking updates by hand; they move the order through + dispatched / delivered / failed and send the same emails as integrated + carriers. +- **Extra services** (Saturday delivery, timed delivery, insurance, …), one + normalized list mapped to each carrier's own codes, picked by staff in + Create Shipment. Sent to ACS (`Acs_Delivery_Products`, `Insurance_Ammount`, + `Appointment_Until_Time`) and ELTA (`pel_sur_*`, `pel_asf_poso`), printed + on the ELTA label. +- **Add manual voucher** on the order page, for an integrated carrier's + voucher that wasn't created here (API down, or the courier wrote his own). + It previews what the carrier reports for the number, and its tracking + history is picked up like any other shipment. +- Customer tracking: the dispatched email lists each shipment's voucher + number and links to the order page, which shows the carrier, status and + the synced tracking history. Only manual carriers link to the courier's + site. New `storefront.orders.*` and `storefront.tracking_status.*` keys — + re-run `StorefrontTranslationsSeeder` in consuming apps. +- Carrier tracking on the order page's **Timeline**: every checkpoint of the + order's shipments (carrier polling or a manual tracking update) is logged + as it arrives, showing carrier, voucher, status, location and the + carrier's own time. Linking a voucher to an order from Carrier Vouchers + adds its history so far. +- Every shipment stores its cash-on-delivery amount and extra services; the + order page shows them. ACS vouchers now carry the order reference + (`Reference_Key1`) so they can be matched back. + +### Changed +- Creating a shipment no longer marks the order **dispatched**. It moves to + dispatched when the carrier reports picking the parcel up, which is also + when the "on its way" email is sent (previously it was never sent after + Create Shipment). +- `shipments.tracking_reference` and `shipments.order_id` are nullable, and + shipments have a `source` (`created`, `manual_voucher`, `manual`, + `synced`). New migration. +- `SupportsCashCollection::collectsCash()` now receives the shipping method: + `collectsCash(ShippingMethod $method)`. Custom shipping drivers implementing + it need the new signature. +- Create Shipment is available again once all of an order's shipments are + cancelled. +- The order page shows ELTA and manual carriers by name, and hides Print for + shipments without a carrier label. +- `OrderStatusUpdated` carries the cause of the write (`$causeClass`, null + for writes outside `OrderStatusWriter`). + +### Fixed +- Customers got two emails when an order became ready for pickup, + dispatched, delivered or completed: the dedicated one and the generic + "your order is now …" one, which only skipped a `ready-for-pickup` spelling + that is never written. The generic email now skips exactly the writes that + send their own email; a manual status change from the admin still sends + it. +- ELTA labels now print everything ELTA's own client prints (checked + field by field against its `SydetaLabelE` / `sydetaE` reports and + `print_vg()`): the cash-on-delivery amount and breakdown + ("ΑΝΤΙΚΑΤΑΒΟΛΗ 17.00", "* ΑΝΑΛΥΣΗ *", "17.00 MΕΤΡΗΤΑ") in the COD column, + the A6 bottom banner, both A4 copies and the payment stub (with ΠΟΣΟ), the + A4 "* ΠΡΟΣΟΧΗ ΑΝΤΙΚΑΤΑΒΟΛΗ *" / "* Απόδειξη Είσπαξης *" notes, the + sender's "Κωδικός:" line, extra services in ELTA's own slots, and + "* ΠΟΛΛΑΠΛΗ ΑΠΟΣΤΟΛΗ *". Previously the A6 label showed no COD amount at + all. The OCR line is no longer wrapped in doubled `> <` markers, and the + volumetric weight is left empty (not 0.000) when none was given. +- ELTA tracking texts were almost never recognized: ELTA sends them in + unaccented capitals ("ΠΑΡΑΔΟΘΗΚΕ") while the mapping looked for accented + words, so most checkpoints came through as Pending. Box Now's `canceled` + spelling is now recognized too. +- ACS shipments were never detected as delivered: the tracking summary was + read from `ACSValueOutput` instead of `ACSTableOutput`. +- Re-creating a Box Now shipment after cancelling it failed, because the + same `orderNumber` was sent again. Retries now send `{reference}-{id}-2`, + `-3`, … + ## [0.28.0] - 2026-09-30 ### Added - `php artisan boboko:translations:pull` — the reverse of the translation diff --git a/composer.json b/composer.json index 244588a..d8c6d79 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "boboko/core", "description": "Core module — authentication and shared panel behaviour", "type": "library", - "version": "0.28.0", + "version": "0.29.0", "autoload": { "psr-4": { "Modules\\Core\\": "src/" diff --git a/package.json b/package.json index eb0e7a0..75a4e58 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@boboko/core", - "version": "0.28.0", + "version": "0.29.0", "private": true, "type": "module", "description": "Portable Stimulus controllers and styles for boboko-core's cart + checkout module. Installed as a real npm dependency (file:../boboko-core in dev, a tagged git install in prod) so a consuming app's `npm install` resolves this package's own dependencies (leaflet, @hotwired/stimulus) transitively, the same way `composer update boboko/*` does for PHP. See CONTRIBUTE.md's \"JS/CSS: a real npm package\" section.",