fixed fingerprint across product versions and free trial search
This commit is contained in:
@@ -1,20 +1,8 @@
|
||||
import { DrizzleCli } from "@/db/initDrizzle.js";
|
||||
import { Client } from "pg";
|
||||
|
||||
import { AppEnv, customers, CusProductStatus } from "@autumn/shared";
|
||||
import { SupabaseClient } from "@supabase/supabase-js";
|
||||
import {
|
||||
and,
|
||||
desc,
|
||||
eq,
|
||||
ilike,
|
||||
or,
|
||||
count,
|
||||
lt,
|
||||
inArray,
|
||||
isNotNull,
|
||||
gt,
|
||||
sql,
|
||||
} from "drizzle-orm";
|
||||
|
||||
import { and, desc, eq, ilike, or, lt, isNotNull, gt, sql } from "drizzle-orm";
|
||||
import { customerProducts, products } from "@autumn/shared";
|
||||
const customerFields = {
|
||||
internal_id: customers.internal_id,
|
||||
@@ -68,14 +56,13 @@ export class CusSearchService {
|
||||
filters.product_id
|
||||
? eq(customerProducts.product_id, filters.product_id)
|
||||
: undefined,
|
||||
filters.status ? eq(customerProducts.status, filters.status) : undefined,
|
||||
filters.status === "canceled"
|
||||
? and(activeProdFilter, isNotNull(customerProducts.canceled_at))
|
||||
: undefined,
|
||||
filters.status === "free_trial"
|
||||
? and(
|
||||
eq(customerProducts.status, CusProductStatus.Active),
|
||||
gt(customerProducts.trial_ends_at, Date.now()),
|
||||
isNotNull(customerProducts.free_trial_id),
|
||||
)
|
||||
: undefined,
|
||||
);
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
import { z } from "zod";
|
||||
|
||||
export type AttachParams = {
|
||||
freeTrialIds: string[];
|
||||
org: Organization;
|
||||
customer: Customer;
|
||||
products: FullProduct[];
|
||||
|
||||
@@ -13,7 +13,16 @@ import {
|
||||
|
||||
import { customerProducts } from "@autumn/shared";
|
||||
|
||||
import { and, arrayContains, eq, inArray, or, sql } from "drizzle-orm";
|
||||
import {
|
||||
and,
|
||||
arrayContains,
|
||||
eq,
|
||||
inArray,
|
||||
isNotNull,
|
||||
ne,
|
||||
or,
|
||||
sql,
|
||||
} from "drizzle-orm";
|
||||
|
||||
export const ACTIVE_STATUSES = [
|
||||
CusProductStatus.Active,
|
||||
@@ -474,12 +483,14 @@ export class CusProductService {
|
||||
|
||||
static async getByFingerprint({
|
||||
db,
|
||||
freeTrialId,
|
||||
productId,
|
||||
internalCustomerId,
|
||||
fingerprint,
|
||||
}: {
|
||||
db: DrizzleCli;
|
||||
freeTrialId: string;
|
||||
fingerprint: string;
|
||||
productId: string;
|
||||
internalCustomerId: string;
|
||||
fingerprint?: string;
|
||||
}) {
|
||||
let data = await db
|
||||
.select()
|
||||
@@ -488,20 +499,22 @@ export class CusProductService {
|
||||
customers,
|
||||
eq(customerProducts.internal_customer_id, customers.internal_id),
|
||||
)
|
||||
.innerJoin(
|
||||
products,
|
||||
eq(customerProducts.internal_product_id, products.internal_id),
|
||||
)
|
||||
.where(
|
||||
and(
|
||||
eq(customers.fingerprint, fingerprint),
|
||||
eq(customerProducts.free_trial_id, freeTrialId),
|
||||
or(
|
||||
fingerprint ? eq(customers.fingerprint, fingerprint) : undefined,
|
||||
eq(customers.internal_id, internalCustomerId),
|
||||
),
|
||||
eq(products.id, productId),
|
||||
isNotNull(customerProducts.free_trial_id),
|
||||
),
|
||||
);
|
||||
|
||||
return data;
|
||||
|
||||
// const { data, error } = await sb
|
||||
// .from("customer_products")
|
||||
// .select("*, customer:customers!inner(*)")
|
||||
// .eq("free_trial_id", freeTrialId)
|
||||
// .eq("customer.fingerprint", fingerprint);
|
||||
}
|
||||
|
||||
static async getByTrialAndCustomer({
|
||||
|
||||
@@ -342,10 +342,12 @@ export const getFullCusProductData = async ({
|
||||
if (!isCustom) {
|
||||
let freeTrial = null;
|
||||
let freeTrialProduct = products.find((p) => notNullish(p.free_trial));
|
||||
|
||||
if (freeTrialProduct) {
|
||||
freeTrial = await getFreeTrialAfterFingerprint({
|
||||
db,
|
||||
freeTrial: freeTrialProduct.free_trial,
|
||||
productId: freeTrialProduct.id,
|
||||
fingerprint: customer.fingerprint,
|
||||
internalCustomerId: customer.internal_id,
|
||||
multipleAllowed: org.config.multiple_trials,
|
||||
@@ -432,6 +434,7 @@ export const getFullCusProductData = async ({
|
||||
const uniqueFreeTrial = await getFreeTrialAfterFingerprint({
|
||||
db,
|
||||
freeTrial: freeTrial,
|
||||
productId: product.id,
|
||||
fingerprint: customer.fingerprint,
|
||||
internalCustomerId: customer.internal_id,
|
||||
multipleAllowed: org.config.multiple_trials,
|
||||
|
||||
@@ -81,64 +81,17 @@ export const freeTrialToStripeTimestamp = (freeTrial: FreeTrial | null) => {
|
||||
return Math.ceil(trialEnd.getTime() / 1000);
|
||||
};
|
||||
|
||||
export const freeTrialToNumDays = (freeTrial: FreeTrial | null) => {
|
||||
if (!freeTrial) return undefined;
|
||||
return freeTrial.length;
|
||||
};
|
||||
|
||||
export const trialFingerprintExists = async ({
|
||||
db,
|
||||
freeTrialId,
|
||||
fingerprint,
|
||||
}: {
|
||||
db: DrizzleCli;
|
||||
freeTrialId: string;
|
||||
fingerprint: string;
|
||||
}) => {
|
||||
const data = await CusProductService.getByFingerprint({
|
||||
db,
|
||||
freeTrialId,
|
||||
fingerprint,
|
||||
});
|
||||
|
||||
if (data && data.length > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
export const trialWithCustomerExists = async ({
|
||||
db,
|
||||
internalCustomerId,
|
||||
freeTrialId,
|
||||
}: {
|
||||
db: DrizzleCli;
|
||||
internalCustomerId: string;
|
||||
freeTrialId: string;
|
||||
}) => {
|
||||
const data = await CusProductService.getByFingerprint({
|
||||
db,
|
||||
freeTrialId,
|
||||
fingerprint: internalCustomerId,
|
||||
});
|
||||
|
||||
if (data && data.length > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
export const getFreeTrialAfterFingerprint = async ({
|
||||
db,
|
||||
freeTrial,
|
||||
productId,
|
||||
fingerprint,
|
||||
internalCustomerId,
|
||||
multipleAllowed,
|
||||
}: {
|
||||
db: DrizzleCli;
|
||||
freeTrial: FreeTrial | null | undefined;
|
||||
productId: string;
|
||||
fingerprint: string | null | undefined;
|
||||
internalCustomerId: string;
|
||||
multipleAllowed: boolean;
|
||||
@@ -150,31 +103,19 @@ export const getFreeTrialAfterFingerprint = async ({
|
||||
}
|
||||
|
||||
let uniqueFreeTrial: FreeTrial | null = freeTrial;
|
||||
if (uniqueFreeTrial.unique_fingerprint && fingerprint) {
|
||||
let exists = await trialFingerprintExists({
|
||||
db,
|
||||
fingerprint,
|
||||
freeTrialId: uniqueFreeTrial.id,
|
||||
});
|
||||
|
||||
if (exists) {
|
||||
console.log("Free trial fingerprint exists");
|
||||
uniqueFreeTrial = null;
|
||||
}
|
||||
}
|
||||
const data = await CusProductService.getByFingerprint({
|
||||
db,
|
||||
productId,
|
||||
internalCustomerId,
|
||||
fingerprint: uniqueFreeTrial.unique_fingerprint ? fingerprint! : undefined,
|
||||
});
|
||||
|
||||
if (uniqueFreeTrial) {
|
||||
// Check if same customer exists
|
||||
let exists = await trialWithCustomerExists({
|
||||
db,
|
||||
internalCustomerId,
|
||||
freeTrialId: uniqueFreeTrial.id,
|
||||
});
|
||||
const exists = data && data.length > 0;
|
||||
|
||||
if (exists) {
|
||||
console.log("Free trial with customer exists");
|
||||
uniqueFreeTrial = null;
|
||||
}
|
||||
if (exists) {
|
||||
console.log("Free trial fingerprint exists");
|
||||
uniqueFreeTrial = null;
|
||||
}
|
||||
|
||||
return uniqueFreeTrial;
|
||||
|
||||
@@ -22,12 +22,14 @@
|
||||
// "noEmit": true,
|
||||
"paths": {
|
||||
"@/*": ["src/*"],
|
||||
"@shared/*": ["../shared/*"]
|
||||
"@shared/*": ["../shared/*"],
|
||||
"@scripts/*": ["scripts/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src",
|
||||
"tests",
|
||||
"scripts",
|
||||
"tests-old/utils.ts",
|
||||
"tests-old/global.ts",
|
||||
"../shared/db/allTables.ts",
|
||||
|
||||
@@ -68,6 +68,7 @@ export const FullProductSchema = ProductSchema.extend({
|
||||
),
|
||||
free_trial: FreeTrialSchema.nullish(),
|
||||
free_trials: z.array(FreeTrialSchema).nullish(),
|
||||
free_trial_ids: z.array(z.string()).nullish(),
|
||||
});
|
||||
|
||||
export type Product = z.infer<typeof ProductSchema>;
|
||||
|
||||
Reference in New Issue
Block a user