entity testing

This commit is contained in:
Ayush Rodrigues
2025-03-27 03:24:27 -07:00
parent 811e8ad78f
commit 3d81955f36
10 changed files with 59 additions and 31 deletions

View File

@@ -8,20 +8,16 @@
"tests",
"vite"
],
"type": "module",
"scripts": {
"frontend:build": "npm run build -w shared && npm run build -w frontend",
"frontend:start": "npm run start -w frontend",
"vite:build": "npm run build -w shared && npm run build -w vite",
"vite:start": "npm run start -w vite",
"server:build": "npm run build -w shared && npm run prod:build -w server",
"server:start": "npm run prod:start -w server",
"server:cron": "npm run cron:start -w server",
"server:workers": "npm run workers:start -w server",
"dev": "concurrently \"cd server && npm run dev\" \"cd vite && npm run dev\" \"redis-server\""
}
}

View File

@@ -268,6 +268,9 @@ export const getStripeSubItems = async ({
cusProducts: attachParams.cusProducts,
});
console.log("Existing usage", existingUsage);
console.log("Feature:", priceEnt.feature.name);
if (
billingType == BillingType.UsageInArrear ||
billingType == BillingType.InArrearProrated ||

View File

@@ -126,7 +126,7 @@ export const handleCreateEntity = async (req: any, res: any) => {
// Create entity!
const { sb, env, orgId, logtail: logger } = req;
const { customer_id, feature_id, entities: inputEntities } = req.body;
const { customer_id, feature_id, entity: inputEntities } = req.body;
let [customer, features, org] = await Promise.all([
CusService.getById({ sb, id: customer_id, orgId, env, logger }),
@@ -216,16 +216,16 @@ export const handleCreateEntity = async (req: any, res: any) => {
}
// Get linked features
let linkedFeatures = features.filter((f: any) =>
["credits"].includes(f.id)
let linkedCusEnts = cusEnts.filter(
(e: any) => e.entitlement.entity_feature_id === feature.id
);
// For each linked feature, create customer entitlement for entity...
for (const linkedFeature of linkedFeatures) {
let linkedCusEnt = getLinkedCusEnt({
linkedFeature,
cusEnts,
});
for (const linkedCusEnt of linkedCusEnts) {
// let linkedCusEnt = getLinkedCusEnt({
// linkedFeature,
// cusEnts,
// });
// console.log("linkedCusEnt", linkedCusEnt?.entitlement.feature.id);
let allowance = linkedCusEnt?.entitlement.allowance;

View File

@@ -71,8 +71,6 @@ const initCusEntBalance = ({
let newBalance = resetBalance! - existingUsage;
// Bring over entities...
if (
entitlement.entity_feature_id ==
existingCusEnt.entitlement.entity_feature_id

View File

@@ -80,7 +80,8 @@ export const entsAreSame = (ent1: Entitlement, ent2: Entitlement) => {
ent1.interval === ent2.interval &&
ent1.allowance_type === ent2.allowance_type &&
ent1.allowance === ent2.allowance &&
ent1.carry_from_previous === ent2.carry_from_previous
ent1.carry_from_previous === ent2.carry_from_previous &&
ent1.entity_feature_id === ent2.entity_feature_id
);
};

View File

@@ -44,6 +44,7 @@ export const CreateEntitlementSchema = z.object({
allowance: z.number().nullish(),
interval: z.nativeEnum(EntInterval).nullish(),
carry_from_previous: z.boolean().default(false),
entity_feature_id: z.string().nullish(),
});
export const PublicEntitlementSchema = z.object({

View File

@@ -19,6 +19,7 @@ export const CreateEntitlement = () => {
const handleCreateEntitlement = async () => {
const newEntitlement = CreateEntitlementSchema.parse(entitlement);
console.log("New entitlement", newEntitlement);
setProduct({
...product,
@@ -40,14 +41,16 @@ export const CreateEntitlement = () => {
Create Entitlement
</Button>
</DialogTrigger>
<DialogContent className="w-[500px]">
<DialogContent className="">
<DialogHeader>
<DialogTitle>Create Entitlement</DialogTitle>
</DialogHeader>
<EntitlementConfig
entitlement={entitlement}
setEntitlement={setEntitlement}
/>
<div className="flex w-full overflow-hidden">
<EntitlementConfig
entitlement={entitlement}
setEntitlement={setEntitlement}
/>
</div>
<DialogFooter>
<Button onClick={handleCreateEntitlement} variant="gradientPrimary">

View File

@@ -59,7 +59,9 @@ export const EntitlementConfig = ({
const [originalEntitlement, _] = useState<Entitlement | null>(
entitlement || null
);
const [showPerEntity, setShowPerEntity] = useState(false);
const [showPerEntity, setShowPerEntity] = useState(
entitlement?.entity_feature_id ? true : false
);
const [showPopover, setShowPopover] = useState(false);
const [selectedFeature, setSelectedFeature] = useState<Feature | null>(
getFeature(entitlement?.internal_feature_id, features) || null
@@ -70,6 +72,7 @@ export const EntitlementConfig = ({
allowance_type: entitlement?.allowance_type || AllowanceType.Fixed,
allowance: entitlement?.allowance || "",
interval: entitlement?.interval || EntInterval.Month,
entity_feature_id: entitlement?.entity_feature_id || "",
});
useEffect(() => {
@@ -79,6 +82,10 @@ export const EntitlementConfig = ({
feature_id: selectedFeature.id,
feature: selectedFeature,
...fields,
entity_feature_id:
fields.entity_feature_id && showPerEntity
? fields.entity_feature_id
: null,
allowance: fields.allowance ? Number(fields.allowance) : 0,
});
@@ -91,10 +98,16 @@ export const EntitlementConfig = ({
} else {
setEntitlement(null);
}
}, [selectedFeature, fields, originalEntitlement, setEntitlement]);
}, [
selectedFeature,
fields,
originalEntitlement,
setEntitlement,
showPerEntity,
]);
return (
<div className="">
<div className="w-full overflow-hidden">
<FieldLabel>Entitlement </FieldLabel>
<Select
value={selectedFeature?.internal_id}
@@ -243,7 +256,7 @@ export const EntitlementConfig = ({
/>
</div>
{showPerEntity && (
<div className="flex flex-col w-full">
<div className="flex flex-col w-full overflow-hidden">
<FieldLabel className="flex items-center gap-2">
Entity
<Tooltip delayDuration={400}>
@@ -256,14 +269,18 @@ export const EntitlementConfig = ({
</TooltipContent>
</Tooltip>
</FieldLabel>
<Select>
<Select
value={fields.entity_feature_id}
onValueChange={(value) =>
setFields({ ...fields, entity_feature_id: value })
}
>
<SelectTrigger>
<SelectValue placeholder="Select feature" />
</SelectTrigger>
<SelectContent>
{features
.filter((feature: Feature) => {
// Filter out boolean features and the currently selected feature
if (feature.type === FeatureType.Boolean) {
return false;
}
@@ -278,11 +295,13 @@ export const EntitlementConfig = ({
.map((feature: Feature) => (
<SelectItem
key={feature.internal_id}
value={feature.internal_id!}
value={feature.id}
>
<div className="flex gap-2 items-center">
{feature.name}
<FeatureTypeBadge type={feature.type} />
per {feature.name}
<span className="font-mono text-t3">
{feature.id}
</span>
</div>
</SelectItem>
))}
@@ -313,7 +332,7 @@ export const EntitlementConfig = ({
}
>
<SelectTrigger>
<SelectValue placeholder="Select duration" />
<SelectValue placeholder="Select reset" />
</SelectTrigger>
<SelectContent>
{Object.values(EntInterval).map((interval) => (

View File

@@ -51,6 +51,13 @@ export const ProductEntitlementTable = ({
return entitlement.allowance_type;
}
if (entitlement.entity_feature_id) {
if (entitlement.interval === "lifetime") {
return `${entitlement.allowance} / ${entitlement.entity_feature_id}`;
}
return `${entitlement.allowance} / ${entitlement.entity_feature_id} / ${entitlement.interval}`;
}
if (entitlement.interval === "lifetime") {
return entitlement.allowance;
}

View File

@@ -75,7 +75,7 @@ export default function UpdateEntitlement({
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent>
<DialogContent className="">
<DialogTitle>Update Entitlement</DialogTitle>
<EntitlementConfig
entitlement={selectedEntitlement}