entity testing
This commit is contained in:
@@ -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\""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -71,8 +71,6 @@ const initCusEntBalance = ({
|
||||
|
||||
let newBalance = resetBalance! - existingUsage;
|
||||
|
||||
// Bring over entities...
|
||||
|
||||
if (
|
||||
entitlement.entity_feature_id ==
|
||||
existingCusEnt.entitlement.entity_feature_id
|
||||
|
||||
@@ -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
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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) => (
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ export default function UpdateEntitlement({
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent>
|
||||
<DialogContent className="">
|
||||
<DialogTitle>Update Entitlement</DialogTitle>
|
||||
<EntitlementConfig
|
||||
entitlement={selectedEntitlement}
|
||||
|
||||
Reference in New Issue
Block a user