Revert "FIX: Existing agreement exists, but is out of sync (#41)"

This reverts commit 43477f0798.
This commit is contained in:
Olav Sundfør 2025-05-26 14:32:32 +02:00 committed by GitHub
parent 43477f0798
commit 89ad059938
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 37 additions and 70 deletions

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
test-script.ts
tmp tmp
# Created by https://www.toptal.com/developers/gitignore/api/node,deno,macos,emacs # Created by https://www.toptal.com/developers/gitignore/api/node,deno,macos,emacs

View File

@ -7,12 +7,8 @@ import { STATUS_CODE } from "$fresh/server.ts";
const config = { const config = {
clientId: Deno.env.get("VIPPS_CLIENT_ID"), clientId: Deno.env.get("VIPPS_CLIENT_ID"),
clientSecret: Deno.env.get("VIPPS_CLIENT_SECRET"), clientSecret: Deno.env.get("VIPPS_CLIENT_SECRET"),
ocpApimSubscriptionKeyPrimary: Deno.env.get( ocpApimSubscriptionKeyPrimary: Deno.env.get("VIPPS_OCP_APIM_SUBSCRIPTION_KEY_PRIMARY"),
"VIPPS_OCP_APIM_SUBSCRIPTION_KEY_PRIMARY", ocpApimSubscriptionKeySecondary: Deno.env.get("VIPPS_OCM_APIM_SUBSCRIPTION_KEY_SECONDARY"),
),
ocpApimSubscriptionKeySecondary: Deno.env.get(
"VIPPS_OCM_APIM_SUBSCRIPTION_KEY_SECONDARY",
),
msn: Deno.env.get("VIPPS_MSN"), msn: Deno.env.get("VIPPS_MSN"),
baseUrl: Deno.env.get("VIPPS_API_BASE_URL"), baseUrl: Deno.env.get("VIPPS_API_BASE_URL"),
}; };
@ -37,8 +33,8 @@ const getAccessToken = async function () {
method: "POST", method: "POST",
// @ts-ignore // @ts-ignore
headers: { headers: {
client_id: config.clientId, "client_id": config.clientId,
client_secret: config.clientSecret, "client_secret": config.clientSecret,
...standardVippsHeaders, ...standardVippsHeaders,
}, },
}); });
@ -60,23 +56,23 @@ export const createAgreement = async function (email: string) {
...standardVippsHeaders, ...standardVippsHeaders,
}, },
body: JSON.stringify({ body: JSON.stringify({
interval: { "interval": {
unit: "MONTH", "unit": "MONTH",
count: 1, "count": 1,
}, },
initialCharge: { "initialCharge": {
amount: amount, "amount": amount,
description: "Initial charge", "description": "Initial charge",
transactionType: "DIRECT_CAPTURE", "transactionType": "DIRECT_CAPTURE",
}, },
pricing: { "pricing": {
amount: amount, "amount": amount,
currency: "NOK", "currency": "NOK",
}, },
// email is used to identify the user in the success page // email is used to identify the user in the success page
merchantRedirectUrl: `${getHostUrl()}/donations-success?email=${email}`, "merchantRedirectUrl": `${getHostUrl()}/donations-success?email=${email}`,
merchantAgreementUrl: `${getHostUrl()}`, "merchantAgreementUrl": `${getHostUrl()}`,
productName: "Månedlig støtte til NRSS", "productName": "Månedlig støtte til NRSS",
}), }),
}); });
@ -93,23 +89,15 @@ export const createAgreement = async function (email: string) {
} }
}; };
export const getAgreement = async function (agreementId: string): Promise< export const getAgreement = async function (agreementId: string) {
| {
status: "PENDING" | "ACTIVE" | "STOPPED" | "EXPIRED";
}
| Error
> {
const token = await getAccessToken(); const token = await getAccessToken();
const response = await fetch( const response = await fetch(`${config.baseUrl}/recurring/v3/agreements/${agreementId}`, {
`${config.baseUrl}/recurring/v3/agreements/${agreementId}`, // @ts-ignore
{ headers: {
// @ts-ignore authorization: `Bearer ${token}`,
headers: { ...standardVippsHeaders,
authorization: `Bearer ${token}`,
...standardVippsHeaders,
},
}, },
); });
if (response.status === STATUS_CODE.OK) { if (response.status === STATUS_CODE.OK) {
return response.json(); return response.json();
@ -122,21 +110,18 @@ export const getAgreement = async function (agreementId: string): Promise<
export const cancelAgreement = async function (agreementId: string) { export const cancelAgreement = async function (agreementId: string) {
const token = await getAccessToken(); const token = await getAccessToken();
const response = await fetch( const response = await fetch(`${config.baseUrl}/recurring/v3/agreements/${agreementId}`, {
`${config.baseUrl}/recurring/v3/agreements/${agreementId}`, method: "PATCH",
{ // @ts-ignore
method: "PATCH", headers: {
// @ts-ignore authorization: `Bearer ${token}`,
headers: { "Idempotency-Key": `${agreementId}-${Date.now()}`,
authorization: `Bearer ${token}`, ...standardVippsHeaders,
"Idempotency-Key": `${agreementId}-${Date.now()}`,
...standardVippsHeaders,
},
body: JSON.stringify({
status: "STOPPED",
}),
}, },
); body: JSON.stringify({
"status": "STOPPED",
}),
});
if (response.status === STATUS_CODE.NoContent) { if (response.status === STATUS_CODE.NoContent) {
return true; return true;

View File

@ -1,7 +1,6 @@
import { getHostUrl, validateEmail } from "../../../lib/utils.ts"; import { getHostUrl, validateEmail } from "../../../lib/utils.ts";
import { storage } from "../../../lib/storage.ts"; import { storage } from "../../../lib/storage.ts";
import { createAgreement } from "../../../lib/vipps/vipps.ts"; import { createAgreement } from "../../../lib/vipps/vipps.ts";
import { getAgreement } from "../../../lib/vipps/vipps.ts";
export const handler = async function (req: Request): Promise<Response> { export const handler = async function (req: Request): Promise<Response> {
const email = new URLSearchParams(req.url.split("?")[1] || "").get("email"); const email = new URLSearchParams(req.url.split("?")[1] || "").get("email");
@ -22,27 +21,11 @@ export const handler = async function (req: Request): Promise<Response> {
const hasActiveAgreement = existingAgreement && const hasActiveAgreement = existingAgreement &&
existingAgreement.validAt !== null && existingAgreement.validAt !== null &&
existingAgreement.revokedAt === null; existingAgreement.revokedAt === null;
const agreementInVipps = existingAgreement && (await getAgreement(existingAgreement.agreementId));
if ( if (
agreementInVipps &&
!(agreementInVipps instanceof Error) &&
agreementInVipps.status !== "ACTIVE" &&
hasActiveAgreement hasActiveAgreement
) { ) {
// Somehow the Vipps agreement is not active in our system anymore. console.error("Agreement already exists", email);
// We should reflect the new status in our system. return Response.redirect(errorPage);
await storage.writeVippsAgreement({
...existingAgreement,
revokedAt: new Date(),
});
} else {
// i.e. the agreement in our system was in sync with Vipps.
if (hasActiveAgreement) {
console.error("Agreement already exists", email);
return Response.redirect(errorPage);
}
} }
const agreement = await createAgreement(email); const agreement = await createAgreement(email);