Commit Graph

6 Commits

Author SHA1 Message Date
3bb7a30c1d SMTP per-shop configurabile dalle Impostazioni (password cifrata AES-256-GCM)
- Settings: smtpHost/Port/User/Pass(cifrata)/Secure/From. Vuoto -> provider
  default dell'app (env); compilato -> invio dal SMTP del merchant.
- crypto.server: encrypt/decrypt AES-256-GCM (chiave APP_ENCRYPTION_KEY).
- mailer: SmtpConfig + buildTransport(smtp) per-shop o env; mailFrom override.
  Sia ricevuta cliente sia notifica merchant usano lo SMTP del merchant.
- proxy: costruisce SmtpConfig (decifra pass), passa ai due invii.
- admin: nuovo tab 'Email (SMTP)'; password mai ri-mostrata (vuoto = invariata).
- Migrazione smtp_settings. APP_ENCRYPTION_KEY: dev in .env, prod = fly secret.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mv83a29B4eFv5ixoj6PoE1
2026-07-07 17:29:33 +02:00
a550d8ff2e A6-bis: testi riquadro operativo editabili (segnaposto) + Impostazioni in tab
- opTextUnfulfilled / opTextShipped editabili dal merchant, con segnaposto
  {{returnAddress}} {{returnCost}} {{orderState}} {{customerName}} {{orderName}}
  {{shopName}}. Default = testi attuali. returnCost deriva da returnAtCustomerExpense
  (a tuo/nostro carico, Art. 57). returnInstructions deprecato (assorbito da opTextShipped).
- Pagina Impostazioni riorganizzata in 4 tab (Email / Notifiche / Regole recesso /
  Reso e stato ordine) + anteprima live del riquadro per stato (non evaso e spedito).
- emailTemplate: renderOperationalBlock ora usa i template + sostituzione segnaposto;
  renderOperationalPreview esportato per l'admin. Migrazione op_texts (additiva).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mv83a29B4eFv5ixoj6PoE1
2026-07-07 16:35:12 +02:00
a6a1900287 R1 A6-bis: operativita' per stato ordine (toggle) + checklist compliance
Comportamenti Pizeta-confirmed, tutti toggle per-shop:
- stateAwareEmail (default ON): la ricevuta durevole include un blocco operativo
  per stato - non evaso => annullo+rimborso; spedito/consegnato => istruzioni reso
  (indirizzo, spese a carico Art.57, prodotto integro, rimborso dopo rientro).
- autoCancelUnfulfilled (default OFF): recesso su ordine non evaso => orderCancel
  (refund+restock). Abilita anche lo stop del remarketing via orders/cancelled.
- returnAtCustomerExpense / returnInstructions / returnAddress: config istruzioni reso.

Impl: helper orderState + cancelOrder (recesso.server); renderOperationalBlock +
param operational in renderReceiptHtml (emailTemplate); mailer passa operational;
proxy calcola stato, passa alla ricevuta, auto-annulla; sezione admin 'Reso e stato
ordine'. Migrazione a6bis_state_ops.

+ CHECKLIST-COMPLIANCE-MERCHANT.md: cosa fa l'app vs obblighi del merchant.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mv83a29B4eFv5ixoj6PoE1
2026-07-07 16:16:22 +02:00
2c8c2a7429 Resi Shopify + notifiche merchant + A6 (finestra/esclusioni) + dashboard recessi
Integrazione Resi Shopify:
- Alla conferma del recesso, crea un Reso nativo (returnCreate) per gli ordini
  evasi -> gestione nella UI Resi nativa. Ordini non evasi: skip (merchant gestisce
  annullo/rimborso). Query via order.fulfillments (returnableFulfillments non
  esiste nella API 2026-04). Campo WithdrawalRequest.shopifyReturnId.

Notifiche al merchant (dietro toggle Settings):
- Email di notifica a ogni recesso (sendMerchantNotification) + tag "Recesso"
  sull'ordine (tagsAdd, scope write_orders). Toggle notifyEnabled/notifyEmail/tagEnabled.

A6 - completezza compliance (dietro toggle, default OFF, non tocca il flusso testato):
- Finestra 14gg: computeDeadline/isWindowExpired (rif = data evasione o ordine +
  defaultWindowDays). Esclusioni Art. 59: checkExclusions su regole ExclusionRule
  (ALL/PRODUCT/TAG). lookupOrder esteso (fulfillments + lineItems product/tags).
  checkCompliance() aggancia lookup+confirm. Toggle enforceWindow/enforceExclusions.
- Pagina admin Esclusioni (CRUD regole) + sezione Regole di recesso in Impostazioni.

Dashboard: pagina Recessi (registro legale read-only). NavMenu: Recessi/Impostazioni/Esclusioni.
Scope: +write_returns,+write_orders. Editor email vincolato (oggetto/intro/nota + anteprima).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mv83a29B4eFv5ixoj6PoE1
2026-07-07 14:47:07 +02:00
d140d90629 Storefront modal + email templating: theme extension, redesign, editable receipt
Storefront (theme app extension recesso-storefront):
- App block + app embed che linkano a /apps/recesso; modal via iframe con
  fallback progressive-enhancement; apertura immediata, dimensione fissa
- Redesign form: pattern modal moderno (header/footer fissi, corpo scorrevole),
  modalita' embed, popover info "i", testo ridotto, de-AI, trattini al posto degli em-dash

Ricevuta email:
- Dati per-shop dinamici da Shopify (nome, url, link stato ordine) via getShopInfo + statusPageUrl
- Template editabili VINCOLATI (oggetto/introduzione/nota) con segnaposto; layout
  fisso e conforme (dichiarazione, timestamp, avviso art. 54-bis)
- Pagina admin (Polaris) con anteprima live + ripristina default
- Campi email in Settings (Prisma) + migrazioni

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mv83a29B4eFv5ixoj6PoE1
2026-07-07 12:17:07 +02:00
4586b2e557 Initial scaffold: Shopify recesso (withdrawal) compliance app
- Remix (TypeScript) + Polaris, official Shopify app template
- Prisma multi-tenant schema (Settings, ExclusionRule, WithdrawalRequest, AuditLog, WebhookEvent) on Postgres
- Mandatory GDPR compliance webhooks (data_request, redact, shop/redact) + HMAC handlers
- API version pinned 2026-04, scopes read_orders/read_products
- Fly deploy config; two-env strategy (custom now, public later)
- Dev setup: shopify.web.toml + Vite allowedHosts for tunnels
- Docs: PLAN.md, ANALISI-REQUISITI-LEGALI.md (Art. 54-bis compliance)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mv83a29B4eFv5ixoj6PoE1
2026-07-06 18:02:17 +02:00