fixed some error with eventsRouter?
This commit is contained in:
103
server/src/external/autumn/autumnCli.ts
vendored
Normal file
103
server/src/external/autumn/autumnCli.ts
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
export class Autumn {
|
||||
private apiKey: string;
|
||||
public headers: Record<string, string>;
|
||||
public baseUrl: string;
|
||||
|
||||
constructor() {
|
||||
this.apiKey = process.env.AUTUMN_API_KEY || "";
|
||||
this.headers = {
|
||||
Authorization: `Bearer ${this.apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
this.baseUrl = "https://api.useautumn.com/v1";
|
||||
}
|
||||
|
||||
async get(path: string) {
|
||||
const response = await fetch(`${this.baseUrl}${path}`, {
|
||||
headers: this.headers,
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async post(path: string, body: any) {
|
||||
const response = await fetch(`${this.baseUrl}${path}`, {
|
||||
method: "POST",
|
||||
headers: this.headers,
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async createCustomer({
|
||||
id,
|
||||
email,
|
||||
name,
|
||||
fingerprint,
|
||||
}: {
|
||||
id: string;
|
||||
email: string;
|
||||
name: string;
|
||||
fingerprint?: string;
|
||||
}) {
|
||||
const data = await this.post("/customers", {
|
||||
id,
|
||||
email,
|
||||
name,
|
||||
fingerprint,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async attach({
|
||||
customerId,
|
||||
productId,
|
||||
options,
|
||||
}: {
|
||||
customerId: string;
|
||||
productId: string;
|
||||
options?: any;
|
||||
}) {
|
||||
const data = await this.post(`/attach`, {
|
||||
customer_id: customerId,
|
||||
product_id: productId,
|
||||
options,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async sendEvent({
|
||||
customerId,
|
||||
eventName,
|
||||
properties,
|
||||
}: {
|
||||
customerId: string;
|
||||
eventName: string;
|
||||
properties?: any;
|
||||
}) {
|
||||
const data = await this.post(`/events`, {
|
||||
customer_id: customerId,
|
||||
event_name: eventName,
|
||||
properties,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async entitled({
|
||||
customerId,
|
||||
featureId,
|
||||
quantity,
|
||||
}: {
|
||||
customerId: string;
|
||||
featureId: string;
|
||||
quantity?: number;
|
||||
}) {
|
||||
const data = await this.get(
|
||||
`/entitled?customer_id=${customerId}&feature_id=${featureId}&quantity=${quantity}`
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
1
server/src/external/autumn/autumnUtils.ts
vendored
Normal file
1
server/src/external/autumn/autumnUtils.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
@@ -26,6 +26,10 @@ export const createNewCustomer = async ({
|
||||
customer: CreateCustomer;
|
||||
nextResetAt?: number;
|
||||
}) => {
|
||||
console.log("Creating new customer");
|
||||
console.log("Org ID:", orgId);
|
||||
console.log("Customer data:", customer);
|
||||
|
||||
const org = await OrgService.getFullOrg({
|
||||
sb,
|
||||
orgId,
|
||||
@@ -33,6 +37,9 @@ export const createNewCustomer = async ({
|
||||
|
||||
const customerData: Customer = {
|
||||
...customer,
|
||||
name: customer.name || "",
|
||||
email: customer.email || "",
|
||||
|
||||
internal_id: generateId("cus"),
|
||||
org_id: orgId,
|
||||
created_at: Date.now(),
|
||||
|
||||
@@ -32,6 +32,7 @@ import { ProductService } from "@/internal/products/ProductService.js";
|
||||
import { handleChangeProduct } from "@/internal/customers/change-product/handleChangeProduct.js";
|
||||
import chalk from "chalk";
|
||||
import { AttachParams } from "@/internal/customers/products/AttachParams.js";
|
||||
import { Autumn } from "@/external/autumn/autumnCli.js";
|
||||
|
||||
export const attachRouter = Router();
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Router } from "express";
|
||||
import {
|
||||
AppEnv,
|
||||
CreateEventSchema,
|
||||
Customer,
|
||||
ErrCode,
|
||||
Event,
|
||||
@@ -28,33 +29,7 @@ const getEventAndCustomer = async (req: any) => {
|
||||
const orgId = req.orgId;
|
||||
const env = req.env;
|
||||
|
||||
let newEvent: Event;
|
||||
let customer: Customer;
|
||||
try {
|
||||
// 1. Validate request body
|
||||
EventSchema.omit({
|
||||
id: true,
|
||||
org_id: true,
|
||||
env: true,
|
||||
properties: true,
|
||||
}).parse(req.body);
|
||||
newEvent = {
|
||||
id: generateId("evt"),
|
||||
org_id: orgId,
|
||||
env: env,
|
||||
timestamp: Date.now(),
|
||||
properties: body.properties || {},
|
||||
|
||||
event_name: body.event_name,
|
||||
customer_id: body.customer_id,
|
||||
};
|
||||
} catch (error: any) {
|
||||
throw new RecaseError({
|
||||
message: "Invalid request body -> " + formatZodError(error),
|
||||
code: ErrCode.InvalidEvent,
|
||||
statusCode: StatusCodes.BAD_REQUEST,
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Check if customer ID is valid
|
||||
customer = await CusService.getCustomer({
|
||||
@@ -64,6 +39,23 @@ const getEventAndCustomer = async (req: any) => {
|
||||
env: env,
|
||||
});
|
||||
|
||||
const parsedEvent = CreateEventSchema.parse(req.body);
|
||||
|
||||
const newEvent: Event = {
|
||||
...parsedEvent,
|
||||
|
||||
properties: parsedEvent.properties || {},
|
||||
|
||||
timestamp: Date.now(),
|
||||
id: generateId("evt"),
|
||||
org_id: orgId,
|
||||
env: env,
|
||||
internal_customer_id: customer.internal_id,
|
||||
};
|
||||
|
||||
// console.log("Customer:", customer);
|
||||
// console.log("Org ID:", req.orgId);
|
||||
|
||||
if (!customer) {
|
||||
customer = await createNewCustomer({
|
||||
sb: req.sb,
|
||||
@@ -137,26 +129,6 @@ eventsRouter.post("", async (req: any, res: any) => {
|
||||
features: affectedFeatures,
|
||||
event,
|
||||
});
|
||||
// await inngest.send({
|
||||
// name: "autumn/update-balance",
|
||||
// data: {
|
||||
// customer,
|
||||
// features: affectedFeatures,
|
||||
// },
|
||||
// });
|
||||
// await updateBalanceTask.trigger(
|
||||
// {
|
||||
// customer,
|
||||
// features: affectedFeatures,
|
||||
// },
|
||||
// {
|
||||
// queue: {
|
||||
// name: "customer",
|
||||
// concurrencyLimit: 1,
|
||||
// },
|
||||
// concurrencyKey: customer.internal_id,
|
||||
// }
|
||||
// );
|
||||
} else {
|
||||
console.log("No affected features found");
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import Stripe from "stripe";
|
||||
import { generateId } from "@/utils/genUtils.js";
|
||||
import RecaseError from "@/utils/errorUtils.js";
|
||||
import { ErrCode } from "@/errors/errCodes.js";
|
||||
import { Autumn } from "@/external/autumn/autumnCli.js";
|
||||
import { CusService } from "../CusService.js";
|
||||
|
||||
export class InvoiceService {
|
||||
static async createInvoice({
|
||||
@@ -83,28 +85,44 @@ export class InvoiceService {
|
||||
status: status || (stripeInvoice.status as InvoiceStatus | null),
|
||||
};
|
||||
|
||||
// Check if invoice already exists
|
||||
// TODO: Fix This
|
||||
const existingInvoice = await this.getInvoiceByStripeId({
|
||||
sb,
|
||||
stripeInvoiceId: stripeInvoice.id,
|
||||
});
|
||||
// // Check if invoice already exists
|
||||
// // TODO: Fix This
|
||||
// const existingInvoice = await this.getInvoiceByStripeId({
|
||||
// sb,
|
||||
// stripeInvoiceId: stripeInvoice.id,
|
||||
// });
|
||||
|
||||
if (existingInvoice) {
|
||||
console.log("Invoice already exists");
|
||||
return;
|
||||
}
|
||||
// if (existingInvoice) {
|
||||
// console.log("Invoice already exists");
|
||||
// return;
|
||||
// }
|
||||
|
||||
const { error } = await sb.from("invoices").upsert(invoice, {
|
||||
onConflict: "stripe_id",
|
||||
});
|
||||
// // const { error } = await sb
|
||||
// // .from("invoices")
|
||||
// // .upsert(invoice, {
|
||||
// // onConflict: "stripe_id",
|
||||
// // })
|
||||
// // .select();
|
||||
|
||||
const { error } = await sb.from("invoices").insert(invoice);
|
||||
|
||||
// const customer = await CusService.getByInternalId({
|
||||
// sb,
|
||||
// internalId: invoice.internal_customer_id,
|
||||
// });
|
||||
|
||||
// const autumn = new Autumn();
|
||||
// await autumn.sendEvent({
|
||||
// customerId: invoice.internal_customer_id,
|
||||
// eventName: "monthly_revenue",
|
||||
// properties: {
|
||||
// value: stripeInvoice.total / 100,
|
||||
// },
|
||||
// });
|
||||
|
||||
if (error) {
|
||||
console.log("Failed to create invoice from stripe", error);
|
||||
throw new RecaseError({
|
||||
code: ErrCode.CreateInvoiceFailed,
|
||||
message: error.message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ErrCode } from "@/errors/errCodes.js";
|
||||
import { createClerkCli, createClerkOrg } from "@/external/clerkUtils.js";
|
||||
import { createClerkCli } from "@/external/clerkUtils.js";
|
||||
import {
|
||||
checkKeyValid,
|
||||
createWebhookEndpoint,
|
||||
@@ -8,12 +8,8 @@ import { encryptData } from "@/utils/encryptUtils.js";
|
||||
import RecaseError, { handleRequestError } from "@/utils/errorUtils.js";
|
||||
import express from "express";
|
||||
import Stripe from "stripe";
|
||||
import { CusService } from "../customers/CusService.js";
|
||||
import { OrgService } from "./OrgService.js";
|
||||
import { Customer, Organization, Product } from "@autumn/shared";
|
||||
import { createStripeCli } from "@/external/stripe/utils.js";
|
||||
import { Client } from "pg";
|
||||
import { ProductService } from "../products/ProductService.js";
|
||||
import { AppEnv } from "@autumn/shared";
|
||||
|
||||
export const orgRouter = express.Router();
|
||||
|
||||
@@ -60,7 +60,6 @@ export const handleRequestError = ({
|
||||
res.status(400).json({
|
||||
message: formatZodError(error),
|
||||
code: ErrCode.InvalidInputs,
|
||||
data: formatZodError(error),
|
||||
});
|
||||
} else {
|
||||
console.log(`Unknown error | ${action}`, error);
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const EventSchema = z.object({
|
||||
// Submitted by the client
|
||||
customer_id: z.string().nonempty(),
|
||||
event_name: z.string().nonempty(),
|
||||
properties: z.record(z.string(), z.any()),
|
||||
idempotency_key: z.string().nullish(),
|
||||
|
||||
// Internal usage
|
||||
id: z.string(),
|
||||
env: z.string(),
|
||||
org_id: z.string(),
|
||||
|
||||
// Submitted by the client
|
||||
customer_id: z.string().nonempty(),
|
||||
event_name: z.string().nonempty(),
|
||||
|
||||
// Optional
|
||||
properties: z.record(z.string(), z.any()),
|
||||
idempotency_key: z.string().optional(),
|
||||
timestamp: z.number().optional(),
|
||||
timestamp: z.number(),
|
||||
internal_customer_id: z.string(),
|
||||
});
|
||||
|
||||
export const CreateEventSchema = EventSchema.omit({
|
||||
id: true,
|
||||
env: true,
|
||||
org_id: true,
|
||||
export const CreateEventSchema = z.object({
|
||||
customer_id: z.string().nonempty(),
|
||||
event_name: z.string().nonempty(),
|
||||
properties: z.record(z.string(), z.any()).nullish(),
|
||||
|
||||
idempotency_key: z.string().nullish(),
|
||||
});
|
||||
|
||||
export type Event = z.infer<typeof EventSchema>;
|
||||
export type CreateEvent = z.infer<typeof CreateEventSchema>;
|
||||
|
||||
Reference in New Issue
Block a user