fix: next reset at doesn't anchor for small ent intervals (like minute or hour)

This commit is contained in:
John Yeo
2025-11-04 11:45:36 +00:00
parent 0a3bd4e6a7
commit 7c94afb65e
5 changed files with 53 additions and 31 deletions

View File

@@ -251,6 +251,14 @@ export const handleStripeWebhookEvent = async ({
}
}
if (
process.env.NODE_ENV === "development" &&
error instanceof Error &&
error.message.includes("No stripe account linked to organization")
) {
return;
}
logger.error(`Stripe webhook, error: ${error}`, { error });
throw error;
}

View File

@@ -39,9 +39,7 @@ export const initCusEntEntities = ({
: null;
for (const entity of entities) {
if (!entitlementLinkedToEntity({ entitlement, entity })) {
continue;
}
if (!entitlementLinkedToEntity({ entitlement, entity })) continue;
if (
existingCusEnt &&

View File

@@ -1,16 +1,17 @@
import { applyTrialToEntitlement } from "@/internal/products/entitlements/entitlementUtils.js";
import { freeTrialToStripeTimestamp } from "@/internal/products/free-trials/freeTrialUtils.js";
import { subtractFromUnixTillAligned } from "@/internal/products/prices/billingIntervalUtils.js";
import { formatUnixToDate } from "@/utils/genUtils.js";
import { getNextEntitlementReset } from "@/utils/timeUtils.js";
import {
EntInterval,
AllowanceType,
EntitlementWithFeature,
BillingInterval,
EntInterval,
type EntitlementWithFeature,
FeatureType,
FreeTrial,
type FreeTrial,
} from "@autumn/shared";
import { UTCDate } from "@date-fns/utc";
import { applyTrialToEntitlement } from "@/internal/products/entitlements/entitlementUtils.js";
import { freeTrialToStripeTimestamp } from "@/internal/products/free-trials/freeTrialUtils.js";
import { getNextEntitlementReset } from "@/utils/timeUtils.js";
import { formatUnixToDateTime } from "../../../../../utils/genUtils.js";
import { getAlignedUnix } from "../../../../products/prices/billingIntervalUtils2.js";
export const initNextResetAt = ({
entitlement,
@@ -31,19 +32,17 @@ export const initNextResetAt = ({
if (
entitlement.feature.type === FeatureType.Boolean ||
entitlement.allowance_type === AllowanceType.Unlimited ||
entitlement.interval == EntInterval.Lifetime
entitlement.interval === EntInterval.Lifetime
) {
return null;
}
// 2. If nextResetAt is provided, return it...
if (nextResetAt) {
return nextResetAt;
}
if (nextResetAt) return nextResetAt;
// 3. Calculate next reset at...
let nextResetAtCalculated = null;
let trialEndTimestamp = trialEndsAt
const trialEndTimestamp = trialEndsAt
? Math.round(trialEndsAt / 1000)
: freeTrial
? freeTrialToStripeTimestamp({ freeTrial, now })
@@ -57,7 +56,7 @@ export const initNextResetAt = ({
nextResetAtCalculated = new UTCDate(trialEndTimestamp! * 1000);
}
let resetInterval = entitlement.interval as EntInterval;
const resetInterval = entitlement.interval as EntInterval;
nextResetAtCalculated = getNextEntitlementReset(
nextResetAtCalculated || new UTCDate(now),
@@ -65,11 +64,28 @@ export const initNextResetAt = ({
entitlement.interval_count || 1,
).getTime();
console.log(`--------------------------------`);
console.log(`Interval: `, entitlement.interval);
console.log(`Interval count: `, entitlement.interval_count);
console.log(`Now: `, formatUnixToDateTime(now));
console.log(`Next reset at: `, formatUnixToDateTime(nextResetAtCalculated));
console.log(`Anchor to unix: `, formatUnixToDateTime(anchorToUnix));
// If anchorToUnix, align next reset at to anchorToUnix...
if (anchorToUnix && nextResetAtCalculated) {
nextResetAtCalculated = subtractFromUnixTillAligned({
targetUnix: anchorToUnix,
originalUnix: nextResetAtCalculated,
if (
anchorToUnix &&
nextResetAtCalculated &&
Object.values(BillingInterval).includes(
entitlement.interval as unknown as BillingInterval,
)
) {
nextResetAtCalculated = getAlignedUnix({
anchor: anchorToUnix,
intervalConfig: {
interval: entitlement.interval as unknown as BillingInterval,
intervalCount: entitlement.interval_count || 1,
},
now,
});
}

View File

@@ -148,7 +148,7 @@ export const completeInvoiceCheckout = async ({
);
if (postalInput) {
await postalInput.click();
await postalInput.type("123123");
await postalInput.type("SW59SX");
}
} catch (error) {
console.log("Could not find postal code input:", error);

View File

@@ -30,15 +30,15 @@ export function SelectFeatureSheet({
const setProduct = useProductStore((s) => s.setProduct);
const setSheet = useSheetStore((s) => s.setSheet);
// Get feature IDs that are already added to the plan
const addedFeatureIds = new Set(
product.items?.map((item) => item.feature_id).filter(Boolean) || []
);
// // Get feature IDs that are already added to the plan
// const addedFeatureIds = new Set(
// product.items?.map((item) => item.feature_id).filter(Boolean) || []
// );
// Filter out archived features and features already on the plan
const filteredFeatures = features.filter(
(f: Feature) => !f.archived && !addedFeatureIds.has(f.id)
);
// // Filter out archived features and features already on the plan
// const filteredFeatures = features.filter(
// (f: Feature) => !f.archived && !addedFeatureIds.has(f.id)
// );
useEffect(() => {
// If we're switching from another sheet, open immediately
@@ -100,7 +100,7 @@ export function SelectFeatureSheet({
</SelectTrigger>
<SelectContent className="max-h-80">
<div className="max-h-60 overflow-y-auto">
{filteredFeatures.map((feature: Feature) => (
{features.map((feature: Feature) => (
<SelectItem
key={feature.id}
value={feature.id}