Carrier rates: DPD price lists imported (myDPD G300 + MDB 2026-04 → dpd-pricelist-2026-04.json, 1261 rows; Classic/Paketshop Europe per country, Express as zone rows + country→zone map); carrier identity from M_Shipper.M_ShipperCfg_ID (DHL / DPD groups, settings/shipping-carriers endpoint, price-sheet carrier select by config); resolver groups flat weight tiers per country and renders zone rows; markup defaults to 0 % (stored 15 % migrated once); matrix search filter now limits the PDF to the visible rows; price-sheet options panel rebuilt with Nuxt UI components (details)
Software offer: "Anlage Onboarding-Paket" as a separate PDF attached by default (onboardingPdf.ts: from-price, travel + hotel billed on top, not-included list, phases, editable setup scope: on-site process analysis, bins, article import, channels, carriers, label + document printers, scanners/devices, users, test run); portal document + mail/Strapi attachment + activity line, preview via document:'onboarding', attachments.onboarding persisted in the saved conditions. Price sheet: carrier select = configs only (DHL/DPD with logos, no attached shippers), multi-select carriers (shipperIds → one sheet per carrier merged by mergePriceSheets, carrier badges, PDF carrier prefixes, Tier writes under the row's carrier), row/section/surcharge checkboxes with "Alle abwählen" limiting the PDF export, markup 0 % default enforced (old 15 % pattern dropped on load); options panel rebuilt with Nuxt UI (UFieldGroup, USwitch/UCheckbox/URadio/UInputNumber gap fixes); recipes updated (details)
Production deploy: no more SQLite writes into the replaced live dir (lost contract-signing row 2026-10-29) (details)
Price sheet: carrier logos + per-carrier grouping (matrix and PDF), PDF rates first / notes last, services check-all, Nuxt UI country multi-select, markup 0 % everywhere (details)
Top bar: merchant label moved into the left zone as a chip (no longer overlaps the centred Ticket/Order buttons); side zones may shrink (minmax(0,1fr)), search shrinks first, quick-action buttons go icon-only below 1600/1400 px (details)
Order lines: "Alle Artikel mit Bestand" — one position per article of the order's organization that has stock, qty = QtyOnHand (details)
Create sales order page (/create/sales-order) rebuilt with the quick-order modal's design and features, order form on Nuxt UI (details)
Price sheet: Germany preselected on load, pinned DE/AT/FR/NL/CH quick picks, one carrier logo per group + gaps between groups (matrix and PDF), narrower wrapping surcharge column (details)
Sales order edit: positions table anchored under the form columns (grid: form | side panel, positions in row 2 of column 1) — a long side column (shipments / invoices / contacts / tickets) no longer pushes the positions down (details)
Order creation (modal + page): placeholder e-mail generator next to the e-mail field (details)
Quick order: coerce AD_Org_ID / C_Country_ID / C_Region_ID ids to numbers before posting partner + address — a cookie/config string id made iDempiere reject the new customer's C_Location (WrongDataType … should be Integer, prod 2026-10-30) (details)
Commission table edit page on Nuxt UI + printer pickers; shipment Jasper slip: pickup vs. delivery + signature box (details)
Commission table form: badge hover no longer flickers (CSS scale was replacing the SVG translate → inner group scales), compact spacing like the partner form (8 px fields, dashed section heads, 2 rem inputs, smaller hero), grid 2/3 form + 1/3 side, rounded card accent bar, camera id 0 shown as empty (details)
LogShip Cloud offer: with the onboarding annex attached the offer prints only a price-less 'Onboarding-Paket – optional' position (details + price in the annex, forecast one-time row dropped); preview step shows all outgoing documents (offer / annex / flyer) as tabs and 'PDFs herunterladen (n)' saves them all (iframe keyed per doc — nuxt-lazy-load one-shot data-src) (details)
Printing: per-printer dispatch (local CUPS or LogShip Print Agent in the tenant LAN) — spool, agent protocol, settings UI (details)
Print-Agents: remote printer administration on the device — 'Drucker einrichten' dialog (discover USB/network printers via lpinfo/ippfind, create CUPS queues with driver presets + media, test page, enable/disable/accept, cancel, remove) over the agent command channel; command whitelist extended; recipe .claude/rules/printing/print-agent.md (details)
Print-Agent: fresh-start poll re-queues the agent's claimed jobs at once (no 3-min wait after an agent restart) (details)
Print-Agent: fresh-start reconcile list of unconfirmed spooled jobs; maintenance closes spooled jobs without completion report after 30 min (details)
Carrier rates: DPD price lists imported (myDPD G300 + MDB 2026-04 → dpd-pricelist-2026-04.json, 1261 rows; Classic/Paketshop Europe per country, Express as zone rows + country→zone map); carrier identity from M_Shipper.M_ShipperCfg_ID (DHL / DPD groups, settings/shipping-carriers endpoint, price-sheet carrier select by config); resolver groups flat weight tiers per country and renders zone rows; markup defaults to 0 % (stored 15 % migrated once); matrix search filter now limits the PDF to the visible rows; price-sheet options panel rebuilt with Nuxt UI components
Software offer: "Anlage Onboarding-Paket" as a separate PDF attached by default (onboardingPdf.ts: from-price, travel + hotel billed on top, not-included list, phases, editable setup scope: on-site process analysis, bins, article import, channels, carriers, label + document printers, scanners/devices, users, test run); portal document + mail/Strapi attachment + activity line, preview via document:'onboarding', attachments.onboarding persisted in the saved conditions. Price sheet: carrier select = configs only (DHL/DPD with logos, no attached shippers), multi-select carriers (shipperIds → one sheet per carrier merged by mergePriceSheets, carrier badges, PDF carrier prefixes, Tier writes under the row's carrier), row/section/surcharge checkboxes with "Alle abwählen" limiting the PDF export, markup 0 % default enforced (old 15 % pattern dropped on load); options panel rebuilt with Nuxt UI (UFieldGroup, USwitch/UCheckbox/URadio/UInputNumber gap fixes); recipes updated
- Contacts (AD_User) as cards in their own column (PartnerDetailRecordUser mode="cards": avatar, e-mail + send, phones + click-to-dial, inactive badge, add/edit/delete via the existing modal); detail-record "Kontakt (Benutzer)" tab hidden on the edit page (hide-users), view/duplicate keep the table; sticky columns, equal gutters, long e-mails wrap - Toolbar (bannercontrol): UFieldGroup save pair + UDropdownMenu groups "Neu" (Kundenauftrag, Anfrage), "Dokumente" (Angebot, Prognose, Vertrag, SEPA, Bericht), "E-Mails" (Verlauf IM/MP, Zugangsdaten), "…" (Anhang, Duplizieren, Änderungsprotokoll via ChangeLogModal); role/processing conditions kept as disabled items - Tabs: UTabs as a segmented pill bar with icons, active tab highlighted; tab strip inside the edit wrapper so it starts at the form's left edge; first section, contacts card and KPI row aligned on one line - PartnerForm converted to Nuxt UI: 23 sections as UCard with coloured, larger titles, collapsible and collapsed by default (open state in localStorage logship_partner_sections); UFormField (icon label slot + UTooltip hint), UInput/USelect/UTextarea (size sm), USwitch on toggle cards and flags (toggleFlag/setFlag), URadioGroup for the rent mode, UButton everywhere; SelectBox and DatePicker unchanged; compact spacing (field 8 px, label 2 px, halved column gutters, zero card padding) - Fixes: freight-rule select crashed on the '' option (Reka SelectItem forbids it → sentinel), USelect trigger zero width + unstyled panel, 9 Tabler icon names missing from the shipped font (blank glyphs) replaced, contacts/locations loaders no longer throw when the API returns nothing - Recipes: nuxt/ui-components.md (USelect/UTabs/UCard/UFormField gaps), partners/partner-edit-form.md (new form structure + edit page layout)
Production deploy: no more SQLite writes into the replaced live dir (lost contract-signing row 2026-10-29)
- Native module builds (better-sqlite3 rebuild, sqlite3 from source, OCR/PDF runtime asset copies, load gate) now run in the STAGE dir before the swap; the live-dir swap itself takes seconds - `pm2 stop` of the app before the rollback copy / rm -rf of the live dir: SQLite connections close and checkpoint, no request can write to deleted inodes (a contract-signing row written during the minutes-long post-swap build window was lost while its PDFs landed in the new dir) - SQLite backups through the better-sqlite3 online backup API (includes WAL frames); plain cp as fallback
Price sheet: carrier logos + per-carrier grouping (matrix and PDF), PDF rates first / notes last, services check-all, Nuxt UI country multi-select, markup 0 % everywhere
- shippingPriceSheet.ts: CARRIER_LOGO_PATHS / carrierLogoPath() as the single logo map, groupRowsByCarrier() for merged sheets - Matrix: carrier heading row (logo, name, row count) per section and in the surcharge table, logo inline before each service on merged sheets, "Kosten" header carries the single carrier's logo - PDF: DHL/DPD PNG logos bundled as Nitro server asset assets:shipper (carrierLogos.ts), cover "[logo] DHL + [logo] DPD", carrier heading rows + logo before the service in every table; page order cover → rate sections → surcharges → service overview → notes; the per-section notes are collected onto the notes page instead of sitting above the tables - Options panel: "Alle an / Alle aus" for the services list with counter, country selection as USelectMenu multiple (search, flags, ISO codes, taller trigger) replacing the popover, carrier-neutral markup label (shared.js ps_markup), stored markups reset once to 0 % (markupV3) so no section keeps an old percentage - Smoke script mocks assets:shipper too
Top bar: merchant label moved into the left zone as a chip (no longer overlaps the centred Ticket/Order buttons); side zones may shrink (minmax(0,1fr)), search shrinks first, quick-action buttons go icon-only below 1600/1400 px
Order lines: "Alle Artikel mit Bestand" — one position per article of the order's organization that has stock, qty = QtyOnHand
- POST server/api/orders/stock-lines { orgId, priceListId, warehouseId }: active articles of the org with their storage rows (productStorageHelper, no child $expand), QtyOnHand summed over all locators (or the order's warehouse), return-locator stock reported separately, prices from the newest version of the order's price list in chunked m_productprice queries - PartnerOrderLineTable: button next to "Position hinzufügen" (order modal + every create/edit line table) that appends the lines with qty = on hand and PriceList/PriceStd, skips articles already on the order, info line with added / skipped / without-price counts (price 0 → check)
Price sheet: Germany preselected on load, pinned DE/AT/FR/NL/CH quick picks, one carrier logo per group + gaps between groups (matrix and PDF), narrower wrapping surcharge column
- defaultSheetOptions: countryScope 'list' with ['DE'] (stored options reset once via countryV3); PINNED_COUNTRY_CODES as toggle chips above the country select and sorted first in the list - Matrix: a carrier group following another one gets a padded top border; surcharge label column 25 % narrower (142 px) with wrapping labels - PDF: logo only on the carrier heading row (service rows plain), white spacer row between carrier groups, surcharge label column 142 pt
Sales order edit: positions table anchored under the form columns (grid: form | side panel, positions in row 2 of column 1) — a long side column (shipments / invoices / contacts / tickets) no longer pushes the positions down
Order creation (modal + page): placeholder e-mail generator next to the e-mail field
- utils/randomEmail.ts: randomLogyouEmail() → kunde-<10 random base36>@logyou.de (crypto random) - PartnerQuickForm (quick-order modal) and sales/OrderForm (create / edit page): wand button beside the e-mail input proposes an address; it is applied only after the user confirms it in an inline row (Übernehmen / Neu würfeln / Abbrechen)
Quick order: coerce AD_Org_ID / C_Country_ID / C_Region_ID ids to numbers before posting partner + address — a cookie/config string id made iDempiere reject the new customer's C_Location (WrongDataType … should be Integer, prod 2026-10-30)
Commission table edit page on Nuxt UI + printer pickers; shipment Jasper slip: pickup vs. delivery + signature box
Commission tables (Settings → Commission Tables): - CommissionTableForm rebuilt with Nuxt UI (UCard sections, UFormField with icon labels + UTooltip info icons, UInput/UTextarea/USelect/USwitch, UFieldGroup actions); edit page gets the partner-page toolbar (save group, preview, clone, manage printers, back) and a hero header; create/duplicate keep the in-form actions - Shipping (label) printer and A4 printer are now pickers over Settings → Printers (/api/printers): label printers for shipping_printer, paper printers for a4_printer, each item with CUPS queue + location; the stored value stays the CUPS queue name, so the commissioning page pickers / getA4Printer keep working - A queue saved on a table but missing in Settings → Printers is flagged and can be created in place (shared org *); the five queues referenced by Tisch 1–3 (labelprinter-4/-5, commission-a4-1/2/3) were created on prod as CUST_Printer rows - Cameras: USelect over the Synology list (loaded on open) + ID fallback input - Side card "Geräte am Tisch": table illustration (SVG) with numbered device badges 1 label printer, 2 A4 printer, 3 camera, 4 camera 2 matching the numbered fields, hover sync, legend with current values; Organisation & Status card with org picker, tenant, Active switch - Org "*" (id 0) was dropped as falsy on load and on update; tenant falls back to AD_Client identifier
Shipment Jasper report (iDempiere host, templates archived under reference/jasper-reports): - DeliveryViaRule = 'P' (Abholung) replaces "Versand via <carrier>" + logo with "Abholung / Selbstabholung", relabels Lieferdatum → Abholdatum and prints a "WARE ERHALTEN (ABHOLUNG)" signature box (Datum / Unterschrift) right of the barcode — A4 (M_InOut_Document + M_InOut_OrgInfoblock) and A5 slip - Deployed + compiled on 192.168.12.72 (Groovy compile one-liner, backups shipment*.bak-20261030); recipes: printing/jasper-shipment-report.md, commissioning.md printer note
Commission table form: badge hover no longer flickers (CSS scale was replacing the SVG translate → inner group scales), compact spacing like the partner form (8 px fields, dashed section heads, 2 rem inputs, smaller hero), grid 2/3 form + 1/3 side, rounded card accent bar, camera id 0 shown as empty
LogShip Cloud offer: with the onboarding annex attached the offer prints only a price-less 'Onboarding-Paket – optional' position (details + price in the annex, forecast one-time row dropped); preview step shows all outgoing documents (offer / annex / flyer) as tabs and 'PDFs herunterladen (n)' saves them all (iframe keyed per doc — nuxt-lazy-load one-shot data-src)
Printing: per-printer dispatch (local CUPS or LogShip Print Agent in the tenant LAN) — spool, agent protocol, settings UI
The 13 `lp` call sites (server/api/print/*, mobile reconditioning report) now go through server/utils/printDispatch.ts: printFile()/printFiles() resolve the CUPS queue per printer — no binding → local `lp` as before (execFile, whitelisted options, no shell string any more); binding → job spooled for the tenant's Print Agent (status 'queued' + jobId, legacy message/stdout fields kept). Storage root configurable (PRINT_STORAGE_DIR, default /root/storage); the dead GET /api/print smoke route is removed.
Instance-local SQLite data/print-spool.db (server/utils/printSpoolDb.ts): agents (token hash, heartbeat inventory/health), enrolment codes, printer→agent bindings keyed by CUST_Printer_ID (no iDempiere column), jobs (queued→sent→spooled→completed|failed, batch id) and commands. Agent protocol under /api/print-agent (enroll, heartbeat, long-poll jobs/next with inline files ≤ 300 KB, jobs/:id/file, jobs/ack, commands/:id/result, cups backup) — Bearer agent token. Admin routes under /api/settings/print-agents (agents, enrol codes, bindings, jobs, commands, status). Maintenance plugin re-queues stale 'sent' jobs and purges finished rows after 24 h.
Settings → Printers: Print-Agents card (online state, version, device queues with PPD label size, queue depth, job stats, update/lpstat/restart-cups/journal/support-tunnel commands, discovered queues → "Anlegen", job list with retry/cancel); printer form gets the per-printer agent + device-queue picker; create/edit/duplicate save the binding after the iDempiere write. labelMedia/cups-media read agent-reported label sizes for bound queues. Print-job feedback: plugins/05.print-jobs.client.ts shows one toast per single job and one progress toast per batch (SSE relay from the notifications plugin + cross-worker poll of jobs/mine).