import type { AdminApiContext } from "@shopify/shopify-app-react-router/server"; import db from "../../db.server"; import { generateInvoice } from "./generateInvoice.server"; import { sendInvoiceEmail } from "./email.server"; const DEFAULT_WIRE_TRANSFER_NAMES = [ "manual", "Überweisung", "Wire Transfer", "Bank Transfer", "Vorkasse", "Bank Deposit", ]; /** * Returns true when any of the order's `payment_gateway_names` matches one of * the configured wire-transfer gateway names (case-insensitive substring). */ export function isWireTransferOrder( paymentGatewayNames: readonly string[] | null | undefined, configured: string, ): boolean { if (!paymentGatewayNames || paymentGatewayNames.length === 0) return false; const needles = (configured.trim() ? configured.split(",") : DEFAULT_WIRE_TRANSFER_NAMES) .map((s) => s.trim().toLowerCase()) .filter(Boolean); if (needles.length === 0) return false; return paymentGatewayNames.some((name) => { const n = (name ?? "").toLowerCase(); return needles.some((needle) => n.includes(needle)); }); } export interface AutoEmailArgs { shopDomain: string; admin: AdminApiContext; /** Numeric Shopify order id (from REST webhook payload `id`). */ orderId: string | number; /** Customer locale forwarded to the email service for subject/body language. */ customerLocale?: string; } /** * Idempotent: if an unsent invoice already exists for the order, it is reused * and emailed. If a sent invoice already exists, sending is skipped (we never * spam the customer with the same invoice twice from automations). */ export async function generateAndEmailInvoice(args: AutoEmailArgs): Promise<{ ok: boolean; reason?: string; invoiceNumber?: string; }> { const orderGid = `gid://shopify/Order/${String(args.orderId).replace(/^.*\//, "")}`; const existing = await db.invoice.findFirst({ where: { shopDomain: args.shopDomain, orderId: orderGid, kind: "invoice", cancelledAt: null, }, orderBy: [{ version: "desc" }, { createdAt: "desc" }], }); if (existing && existing.sentAt) { return { ok: true, reason: "already-sent", invoiceNumber: existing.invoiceNumber }; } let invoiceId = existing?.id; let invoiceNumber = existing?.invoiceNumber; if (!invoiceId) { const generated = await generateInvoice({ shopDomain: args.shopDomain, admin: args.admin, orderId: String(args.orderId), }); invoiceId = generated.invoiceId; invoiceNumber = generated.invoiceNumber; } const result = await sendInvoiceEmail({ shopDomain: args.shopDomain, invoiceId, customerLocale: args.customerLocale, }); if (!result.ok) { return { ok: false, reason: result.errorMessage ?? "email-failed", invoiceNumber }; } return { ok: true, invoiceNumber }; }