fix: track entity product
This commit is contained in:
@@ -18,14 +18,12 @@ export const getSummedEntityBalances = ({
|
||||
}
|
||||
|
||||
return {
|
||||
balance: Object.values(cusEnt.entities).reduce(
|
||||
(acc, curr) => acc + curr.balance,
|
||||
0,
|
||||
),
|
||||
adjustment: Object.values(cusEnt.entities).reduce(
|
||||
(acc, curr) => acc + curr.adjustment,
|
||||
0,
|
||||
),
|
||||
balance: Object.values(cusEnt.entities)
|
||||
.reduce((acc, curr) => acc.add(curr.balance), new Decimal(0))
|
||||
.toNumber(),
|
||||
adjustment: Object.values(cusEnt.entities)
|
||||
.reduce((acc, curr) => acc.add(curr.adjustment), new Decimal(0))
|
||||
.toNumber(),
|
||||
unused: 0,
|
||||
count: Object.values(cusEnt.entities).length,
|
||||
};
|
||||
|
||||
@@ -95,11 +95,14 @@ export const cusEntToIncludedUsage = ({
|
||||
|
||||
export const cusEntToUsageLimit = ({
|
||||
cusEnt,
|
||||
entityId,
|
||||
}: {
|
||||
cusEnt: FullCusEntWithFullCusProduct;
|
||||
entityId?: string;
|
||||
}) => {
|
||||
const startingBalance = cusEntToIncludedUsage({
|
||||
cusEnt,
|
||||
entityId,
|
||||
});
|
||||
|
||||
if (cusEnt.entitlement.usage_limit) return cusEnt.entitlement.usage_limit;
|
||||
|
||||
@@ -2,11 +2,8 @@ import type {
|
||||
EntityBalance,
|
||||
FullCustomerEntitlement,
|
||||
} from "@models/cusProductModels/cusEntModels/cusEntModels.js";
|
||||
import type { Entity } from "../../models/cusModels/entityModels/entityModels.js";
|
||||
import type { FullCustomer } from "../../models/cusModels/fullCusModel.js";
|
||||
import type { FullCusEntWithFullCusProduct } from "../../models/cusProductModels/cusEntModels/cusEntWithProduct.js";
|
||||
import type { Feature } from "../../models/featureModels/featureModels.js";
|
||||
import { notNullish } from "../utils.js";
|
||||
|
||||
export const formatCusEnt = ({
|
||||
cusEnt,
|
||||
@@ -16,6 +13,17 @@ export const formatCusEnt = ({
|
||||
return `${cusEnt.entitlement.feature_id} (${cusEnt.entitlement.interval}) (${cusEnt.balance})`;
|
||||
};
|
||||
|
||||
export const isEntityCusEnt = ({
|
||||
cusEnt,
|
||||
}: {
|
||||
cusEnt: FullCusEntWithFullCusProduct;
|
||||
}): boolean => {
|
||||
return !!(
|
||||
cusEnt.entitlement.entity_feature_id ||
|
||||
cusEnt.customer_product?.internal_entity_id
|
||||
);
|
||||
};
|
||||
|
||||
export const updateCusEntInFullCus = ({
|
||||
fullCus,
|
||||
cusEntId,
|
||||
@@ -47,33 +55,3 @@ export const updateCusEntInFullCus = ({
|
||||
}
|
||||
}
|
||||
};
|
||||
export const cusEntMatchesEntity = ({
|
||||
cusEnt,
|
||||
entity,
|
||||
features,
|
||||
}: {
|
||||
cusEnt: FullCusEntWithFullCusProduct;
|
||||
entity?: Entity;
|
||||
features?: Feature[];
|
||||
}) => {
|
||||
if (!entity) return true;
|
||||
|
||||
let cusProductMatch = true;
|
||||
|
||||
if (notNullish(cusEnt.customer_product?.internal_entity_id)) {
|
||||
cusProductMatch =
|
||||
cusEnt.customer_product.internal_entity_id === entity.internal_id;
|
||||
}
|
||||
|
||||
let entityFeatureIdMatch = true;
|
||||
// let feature = features?.find(
|
||||
// (f) => f.id == cusEnt.entitlement.entity_feature_id,
|
||||
// );
|
||||
|
||||
if (notNullish(cusEnt.entitlement.entity_feature_id)) {
|
||||
entityFeatureIdMatch =
|
||||
cusEnt.entitlement.entity_feature_id === entity.feature_id;
|
||||
}
|
||||
|
||||
return cusProductMatch && entityFeatureIdMatch;
|
||||
};
|
||||
|
||||
64
shared/utils/cusEntUtils/filterCusEntUtils.ts
Normal file
64
shared/utils/cusEntUtils/filterCusEntUtils.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import type { Entity } from "../../models/cusModels/entityModels/entityModels.js";
|
||||
import type { FullCusEntWithFullCusProduct } from "../../models/cusProductModels/cusEntModels/cusEntWithProduct.js";
|
||||
import type { Feature } from "../../models/featureModels/featureModels.js";
|
||||
import { notNullish, nullish } from "../utils.js";
|
||||
export const cusEntMatchesEntity = ({
|
||||
cusEnt,
|
||||
entity,
|
||||
features,
|
||||
}: {
|
||||
cusEnt: FullCusEntWithFullCusProduct;
|
||||
entity?: Entity;
|
||||
features?: Feature[];
|
||||
}) => {
|
||||
if (!entity) return true;
|
||||
|
||||
let cusProductMatch = true;
|
||||
|
||||
if (notNullish(cusEnt.customer_product?.internal_entity_id)) {
|
||||
cusProductMatch =
|
||||
cusEnt.customer_product.internal_entity_id === entity.internal_id;
|
||||
}
|
||||
|
||||
let entityFeatureIdMatch = true;
|
||||
// let feature = features?.find(
|
||||
// (f) => f.id == cusEnt.entitlement.entity_feature_id,
|
||||
// );
|
||||
|
||||
if (notNullish(cusEnt.entitlement.entity_feature_id)) {
|
||||
entityFeatureIdMatch =
|
||||
cusEnt.entitlement.entity_feature_id === entity.feature_id;
|
||||
}
|
||||
|
||||
return cusProductMatch && entityFeatureIdMatch;
|
||||
};
|
||||
|
||||
export const filterOutEntityCusEnts = ({
|
||||
cusEnts,
|
||||
}: {
|
||||
cusEnts: FullCusEntWithFullCusProduct[];
|
||||
}) => {
|
||||
return cusEnts.filter(
|
||||
(ce) =>
|
||||
nullish(ce.entitlement.entity_feature_id) &&
|
||||
nullish(ce.customer_product?.internal_entity_id),
|
||||
);
|
||||
};
|
||||
|
||||
export const filterPerEntityCusEnts = ({
|
||||
cusEnts,
|
||||
}: {
|
||||
cusEnts: FullCusEntWithFullCusProduct[];
|
||||
}) => {
|
||||
return cusEnts.filter((ce) => notNullish(ce.entitlement.entity_feature_id));
|
||||
};
|
||||
|
||||
export const filterEntityProductCusEnts = ({
|
||||
cusEnts,
|
||||
}: {
|
||||
cusEnts: FullCusEntWithFullCusProduct[];
|
||||
}) => {
|
||||
return cusEnts.filter((ce) =>
|
||||
notNullish(ce.customer_product?.internal_entity_id),
|
||||
);
|
||||
};
|
||||
@@ -2,15 +2,33 @@ import type { FullCusEntWithFullCusProduct } from "../../models/cusProductModels
|
||||
import { FeatureType } from "../../models/featureModels/featureEnums.js";
|
||||
import { AllowanceType } from "../../models/productModels/entModels/entModels.js";
|
||||
import { entIntervalToValue } from "../intervalUtils.js";
|
||||
import { isEntityCusEnt } from "./cusEntUtils.js";
|
||||
|
||||
export const sortCusEntsForDeduction = (
|
||||
cusEnts: FullCusEntWithFullCusProduct[],
|
||||
reverseOrder: boolean = false,
|
||||
entityId?: string,
|
||||
) => {
|
||||
cusEnts.sort((a, b) => {
|
||||
const aEnt = a.entitlement;
|
||||
const bEnt = b.entitlement;
|
||||
|
||||
// 0. Sort customer-level vs entity-level based on tracking context
|
||||
// If entityId is provided: entity-level goes first (deduct entity's own resources first)
|
||||
// If entityId is null: customer-level goes first (deduct customer resources first)
|
||||
const aIsEntity = isEntityCusEnt({ cusEnt: a });
|
||||
const bIsEntity = isEntityCusEnt({ cusEnt: b });
|
||||
|
||||
if (aIsEntity !== bIsEntity) {
|
||||
if (entityId) {
|
||||
// Entity-level tracking: entity entitlements go first
|
||||
return aIsEntity ? -1 : 1;
|
||||
} else {
|
||||
// Customer-level tracking: customer entitlements go first
|
||||
return aIsEntity ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 1. If boolean, go first
|
||||
if (aEnt.feature.type === FeatureType.Boolean) {
|
||||
return -1;
|
||||
@@ -85,6 +103,19 @@ export const sortCusEntsForDeduction = (
|
||||
}
|
||||
}
|
||||
|
||||
// 0a. If both are entity products (attached to entities), sort by entity_id for consistent ordering
|
||||
const aIsProductEntity = !!a.customer_product?.internal_entity_id;
|
||||
const bIsProductEntity = !!b.customer_product?.internal_entity_id;
|
||||
|
||||
if (aIsProductEntity && bIsProductEntity) {
|
||||
const aEntityId = a.customer_product?.entity_id;
|
||||
const bEntityId = b.customer_product?.entity_id;
|
||||
|
||||
if (aEntityId && bEntityId && aEntityId !== bEntityId) {
|
||||
return aEntityId.localeCompare(bEntityId);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a is main product
|
||||
const aIsAddOn = a.customer_product?.product?.is_add_on;
|
||||
const bIsAddOn = b.customer_product?.product?.is_add_on;
|
||||
|
||||
Reference in New Issue
Block a user