Commit Graph

34 Commits

Author SHA1 Message Date
Gerhard Scheikl 3fb8600402 fix(thank-you): serve GiroCode as signed PNG URL instead of data URL 2026-05-09 21:14:47 +02:00
Gerhard Scheikl cc7cedfedb fix(payment-info): rewrite OrderIdentity GID to Order GID; surface error detail; brief retry 2026-05-09 21:07:39 +02:00
Gerhard Scheikl 8bc86ef985 payment info updates 2026-05-09 21:05:09 +02:00
Gerhard Scheikl 884070cddc feat(thank-you): payment instructions extension (GiroCode + bank details) for manual payment orders 2026-05-09 20:48:08 +02:00
Gerhard Scheikl 93aec2f368 refactor(automations): detect manual payment via OrderTransaction.manualPaymentGateway
- Drop wireTransferGatewayNames from ShopSettings (new migration).
- Replace string-matching with a GraphQL query against
  Order.transactions[].manualPaymentGateway, the first-class flag
  Shopify exposes for any merchant-defined manual payment method.
- Both webhook handlers now fetch the order on the fly to classify it,
  removing the configurable gateway-names field from settings.
2026-05-09 20:31:31 +02:00
Gerhard Scheikl 0800d1160b feat(automations): auto-email invoice on wire-transfer placed and on fulfillment
- New ShopSettings fields: autoEmailOnWireTransferPlaced,
  autoEmailOnFulfilledNonWireTransfer, wireTransferGatewayNames.
- New Automations section in settings with two toggles + gateway list.
- orders/create webhook now fires automation 1 (wire-transfer placed).
- New orders/fulfilled webhook fires automation 2 (non-wire-transfer fulfilled).
- Shared helper services/invoice/automations.server.ts handles classification
  and idempotent generate+send (skips if already sent).
- Webhook subscription for orders/fulfilled added to all 3 app tomls.

This is the non-Plus fallback for Shopify Flow, whose custom-app actions
are gated to Plus stores only.
2026-05-09 20:21:41 +02:00
Gerhard Scheikl 5061dbb3d5 remove unwanted characters in file name 2026-05-09 19:48:18 +02:00
Gerhard Scheikl 6ded8ec1b9 fix(offers): add read_draft_orders scope so draftOrders query works 2026-05-09 19:41:12 +02:00
Gerhard Scheikl 6224597497 feat(offers): generate Angebot/Offer PDFs for draft orders 2026-05-09 19:26:33 +02:00
Gerhard Scheikl 1ec4faaac5 security: restrict installs to ALLOWED_SHOP and remove generic landing form 2026-05-09 18:01:14 +02:00
Gerhard Scheikl ecd2b00985 feat(pdf): make footer email and website clickable 2026-05-09 17:45:56 +02:00
Gerhard Scheikl 8cceb8af66 fix: use invoice.number for girocode reference 2026-05-09 17:41:42 +02:00
Gerhard Scheikl 9bfce39db2 feat(girocode): use full company name + add Recipient/Bank/Amount/Reference labels 2026-05-09 17:41:22 +02:00
Gerhard Scheikl 85a56cac59 fix(settings): preserve stored logo + persist editor changes on save 2026-05-09 17:17:55 +02:00
Gerhard Scheikl d454843856 fix(email): use invoice language so email matches PDF attachment 2026-05-09 17:14:20 +02:00
Gerhard Scheikl b5d41046a0 feat(invoices): make order number link to admin order page 2026-05-09 17:11:13 +02:00
Gerhard Scheikl cc159f9b6b feat(ui): add Send/Re-send button on invoices page and order block 2026-05-09 17:09:33 +02:00
Gerhard Scheikl 227c00b3a0 fix(settings): place save banner next to Save button 2026-05-09 16:21:55 +02:00
Gerhard Scheikl f97d6dc9d2 feat(email): text colour menu in WYSIWYG (LinumIQ blue + presets) 2026-05-09 16:11:49 +02:00
Gerhard Scheikl 26e4af97bc fix(email): preserve <img style> in WYSIWYG so logo stays scaled 2026-05-09 08:22:07 +02:00
Gerhard Scheikl 67204d79ac feat(email): render shop logo inside WYSIWYG editor (cid swap) 2026-05-09 08:05:00 +02:00
Gerhard Scheikl 573dfbfd50 feat(email): default template with inline logo + shop contact vars
Mirrors the layout from data/mail_template.png:
- Company name + greeting headline
- Body referencing the invoice number
- Inline logo (cid:invoice-logo) attached automatically
- Footer with mailto + website links

New template vars: {{shopEmail}}, {{shopWebsite}}.
Settings UI prefills empty fields with the defaults so users see and
can tweak them without losing the fallback.
2026-05-08 23:12:23 +02:00
Gerhard Scheikl 04933fcac6 feat(email): WYSIWYG template editor with variable substitution
- Add emailSubject{De,En} + emailBodyHtml{De,En} to ShopSettings
- New RichTextEditor component (TipTap) with toolbar + variable insert
- Settings UI: Email templates section per language
- email.server.ts: substitute {{var}} placeholders, fall back to defaults
- Default vars: invoiceNumber, customerName, customerFirstName, orderName,
  totalGross, dueDate, companyName, ownerName
2026-05-08 23:06:40 +02:00
Gerhard Scheikl 537dfd34cb fix(pdf): hide payment terms text on paid invoices 2026-05-08 22:52:18 +02:00
Gerhard Scheikl 64ac54d3c3 fix(ui): align section headings (drop padding=none + redundant inner s-box) 2026-05-08 22:47:10 +02:00
Gerhard Scheikl 093db30b6c feat(email): always BCC shop@linumiq.com on outgoing invoice mails 2026-05-08 22:44:21 +02:00
Gerhard Scheikl 02a93b502b fix(health): add /healthz route and tighten docker healthcheck 2026-05-08 22:42:09 +02:00
Gerhard Scheikl edd72f2776 feat(invoice): add Send invoice email action
Adds a Send button to the order action extension and a corresponding
"send" op to /api/orders/:orderId/invoice. Generates the invoice on
demand if missing, then sends via the configured SMTP.
2026-05-08 15:27:16 +02:00
Gerhard Scheikl a67fc0767e fix(api): wrap invoice API responses with cors() helper
The order-action / order-block UI extensions are hosted on
extensions.shopifycdn.com and call our app via fetch(). Without CORS
headers the browser blocked the response. authenticate.admin already
returns a cors helper and handles OPTIONS preflight - wrap every
Response with it.
2026-05-08 15:12:52 +02:00
Gerhard Scheikl 58cfc30cd7 fix(build): extract STORED_LOGO_SENTINEL to non-server module
Vite/React Router refused to bundle the client because
app/routes/app.settings.tsx imported the constant from a .server file
and used it inside the route component (not just loader/action), so it
could not be tree-shaken out.

Move the sentinel to logoCache.constants.ts, re-export from
logoCache.server.ts for backwards compatibility, and import the constant
from constants in the route while keeping the server-only functions
(deleteStoredLogo, storeUploadedLogo) imported from .server (they are
only referenced inside the action and get tree-shaken correctly).
2026-05-08 14:41:48 +02:00
Gerhard Scheikl a275197ce4 make app production-ready 2026-05-08 11:01:08 +02:00
Gerhard Scheikl 770c6fd16a many updates :-) 2026-05-08 10:40:19 +02:00
Gerhard Scheikl 5b2aa5d62b first version 2026-04-28 21:56:11 +02:00
Gerhard Scheikl 0f75dbaccb initial version (template only) 2026-04-28 13:34:35 +02:00