datewise/app/routes/webhooks.app.tsx
metatroncubeswdev 19b403f98f fix(billing): register plans approved as test charges; reset plan on uninstall
App Store review 1.2.2: the reviewer's store got a test charge, but billing.check ran with isTest:false and ignored it, so the approved plan never registered. Checks now count test subscriptions too, and cancel uses each subscription's own test flag. Uninstall resets the stored plan to free (Shopify cancels the subscription), so a reinstall asks for approval again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 20:31:33 -04:00

24 lines
1.3 KiB
TypeScript

import type { ActionFunctionArgs } from "react-router";
import prisma from "../db.server";
import { authenticate } from "../shopify.server";
/**
* app/uninstalled: storefront behaviour stops immediately (proxy calls fail without a
* session and the theme extension is removed by Shopify). Data is kept for 48 hours so a
* quick reinstall keeps bookings; Shopify's shop/redact webhook then deletes everything.
*/
export const action = async ({ request }: ActionFunctionArgs) => {
const { shop, topic, session, payload } = await authenticate.webhook(request);
if (topic === "APP_UNINSTALLED") {
if (session) await prisma.session.deleteMany({ where: { shop } });
await prisma.shop.updateMany({ where: { domain: shop }, data: { uninstalledAt: new Date(), plan: "free" } }); // Shopify cancels app subscriptions on uninstall
await prisma.hold.deleteMany({ where: { shop: { domain: shop } } });
await prisma.reminderJob.updateMany({ where: { shop: { domain: shop }, status: "pending" }, data: { status: "cancelled" } });
}
if (topic === "APP_SCOPES_UPDATE" && session) {
const current = (payload as { current?: string[] }).current;
if (current) await prisma.session.update({ where: { id: session.id }, data: { scope: current.toString() } });
}
return new Response();
};