pricing4ts
Version:
 Pricing4TS is a TypeScript-based toolkit designed to enhance the server-side functionality of a pricing-driven SaaS by enabling the seamless integration of pricing plans into the application logic. T
192 lines (191 loc) • 8.82 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.explain = explain;
var number_utils_1 = require("./dzn-exporter/number-utils");
function explain(minizincError, pricing) {
var message = minizincError.message;
if (!message) {
return JSON.stringify(minizincError);
}
var _a = message.split(':'), errorId = _a[0], errorMessage = _a[1];
switch (errorId) {
case 'InvalidUsageLimitValueError':
return explainUsageLimitWithoutValueError(pricing, errorMessage);
case 'DeadFeatureError':
return explainDeadFeatureError(pricing, errorMessage);
case 'DeadUsageLimitError':
return explainDeadUsageLimitError(pricing, errorMessage);
default:
return message;
}
}
function explainUsageLimitWithoutValueError(pricing, errorMessage) {
var pricingUsageLimits = pricing.usageLimits;
var usageLimitsWithoutValue = [];
var featuresLinkedToManyUsageLimits = _findFeaturesLinkedToManyUsageLimits(pricing);
for (var _i = 0, _a = Object.values(pricingUsageLimits); _i < _a.length; _i++) {
var usageLimit = _a[_i];
var plansWithUsageLimitInactive = _plansWithInactiveUsageLimit(usageLimit.name, usageLimit.linkedFeatures, pricing, featuresLinkedToManyUsageLimits);
var isUsageLimitInvalid = plansWithUsageLimitInactive.length > 0;
if (isUsageLimitInvalid) {
usageLimitsWithoutValue.push("".concat(usageLimit.name, " in [").concat(plansWithUsageLimitInactive, "]"));
}
}
return ("".concat(errorMessage, " Found usage limits without value > 0: ") + usageLimitsWithoutValue.join(', '));
}
function explainDeadFeatureError(pricing, errorMessage) {
var pricingFeatures = Object.keys(pricing.features);
var deadFeatures = [];
for (var _i = 0, pricingFeatures_1 = pricingFeatures; _i < pricingFeatures_1.length; _i++) {
var feature = pricingFeatures_1[_i];
var isFeatureDead = !(_isFeatureInAnyPlan(feature, pricing.plans) || _isFeatureInAnyAddOn(feature, pricing.addOns));
if (isFeatureDead) {
deadFeatures.push(feature);
}
}
return "".concat(errorMessage, " Found dead features: ") + deadFeatures.join(', ');
}
function explainDeadUsageLimitError(pricing, errorMessage) {
var pricingUsageLimits = Object.keys(pricing.usageLimits);
var deadUsageLimits = [];
for (var _i = 0, pricingUsageLimits_1 = pricingUsageLimits; _i < pricingUsageLimits_1.length; _i++) {
var usageLimit = pricingUsageLimits_1[_i];
var isUsageLimitDead = !(_isUsageLimitInAnyPlan(usageLimit, pricing.plans) ||
_isUsageLimitInAnyAddOn(usageLimit, pricing.usageLimits[usageLimit].valueType, pricing.addOns));
if (isUsageLimitDead) {
deadUsageLimits.push(usageLimit);
}
}
return "".concat(errorMessage, " Found dead usage limits: ") + deadUsageLimits.join(', ');
}
function _isFeatureInAnyPlan(feature, plans) {
if (plans) {
for (var _i = 0, _a = Object.values(plans); _i < _a.length; _i++) {
var plan = _a[_i];
if (plan.features[feature].value || plan.features[feature].defaultValue) {
return true;
}
}
}
return false;
}
function _isUsageLimitInAnyPlan(usageLimit, plans) {
if (plans) {
for (var _i = 0, _a = Object.values(plans); _i < _a.length; _i++) {
var plan = _a[_i];
if ((0, number_utils_1.calculateOverriddenValue)(plan.usageLimits[usageLimit]) > 0) {
return true;
}
}
}
return false;
}
function _isFeatureInAnyAddOn(feature, addOns) {
var _a, _b;
if (addOns) {
for (var _i = 0, _c = Object.values(addOns); _i < _c.length; _i++) {
var addOn = _c[_i];
if ((_b = (_a = addOn.features) === null || _a === void 0 ? void 0 : _a[feature]) === null || _b === void 0 ? void 0 : _b.value) {
return true;
}
}
}
return false;
}
function _isUsageLimitInAnyAddOn(usageLimit, usageLimitValueType, addOns) {
var _a, _b, _c, _d;
if (addOns) {
for (var _i = 0, _e = Object.values(addOns); _i < _e.length; _i++) {
var addOn = _e[_i];
// If the usage limit has a value in the add-on, or extend the plan's value, it is considered active
if ((((_a = addOn.usageLimits) === null || _a === void 0 ? void 0 : _a[usageLimit]) &&
(0, number_utils_1.calculateOverriddenValue)(__assign(__assign({}, (_b = addOn.usageLimits) === null || _b === void 0 ? void 0 : _b[usageLimit]), { valueType: usageLimitValueType })) > 0) ||
(((_c = addOn.usageLimitsExtensions) === null || _c === void 0 ? void 0 : _c[usageLimit]) &&
(0, number_utils_1.calculateOverriddenValue)(__assign(__assign({}, (_d = addOn.usageLimitsExtensions) === null || _d === void 0 ? void 0 : _d[usageLimit]), { valueType: usageLimitValueType })) > 0)) {
return true;
}
}
}
return false;
}
function _plansWithInactiveUsageLimit(usageLimit, linkedFeatures, pricing, featuresLinkedToManyUsageLimits) {
var plansWithInactiveUsageLimit = [];
if (pricing.plans && linkedFeatures && linkedFeatures.length > 0) {
var _loop_1 = function (plan) {
var planFeatures = plan.features;
var isPlanWithLinkedFeatureActive = false;
var _loop_2 = function (feature) {
if (linkedFeatures.includes(feature.name)) {
if (!featuresLinkedToManyUsageLimits.includes(feature.name) &&
(feature.value || feature.defaultValue)) {
isPlanWithLinkedFeatureActive = true;
return "break";
}
else if (featuresLinkedToManyUsageLimits.includes(feature.name)) {
var usageLimitsLinkedToFeature = Object.values(pricing.usageLimits).map(function (u) { var _a; return (_a = u.linkedFeatures) === null || _a === void 0 ? void 0 : _a.includes(feature.name); });
if (usageLimitsLinkedToFeature.some(function (u) { return (0, number_utils_1.calculateOverriddenValue)(plan.usageLimits[usageLimit]) > 0; })) {
isPlanWithLinkedFeatureActive = true;
return "break";
}
}
}
};
// If no feature linked to the limit is active in the plan, an inactive usage limit is not invalid, so there is no need to perform the evaluation
for (var _b = 0, _c = Object.values(planFeatures); _b < _c.length; _b++) {
var feature = _c[_b];
var state_1 = _loop_2(feature);
if (state_1 === "break")
break;
}
if (!isPlanWithLinkedFeatureActive) {
return "continue";
}
var overridenValue = (0, number_utils_1.calculateOverriddenValue)(plan.usageLimits[usageLimit]);
if (overridenValue === 0) {
plansWithInactiveUsageLimit.push(plan.name);
}
};
for (var _i = 0, _a = Object.values(pricing.plans); _i < _a.length; _i++) {
var plan = _a[_i];
_loop_1(plan);
}
}
return plansWithInactiveUsageLimit;
}
function _findFeaturesLinkedToManyUsageLimits(pricing) {
var pricingUsageLimits = pricing.usageLimits;
var linkedFeaturesCounter = {};
for (var _i = 0, _a = Object.values(pricingUsageLimits); _i < _a.length; _i++) {
var usageLimit = _a[_i];
var linkedFeatures = usageLimit.linkedFeatures;
if (linkedFeatures) {
for (var _b = 0, linkedFeatures_1 = linkedFeatures; _b < linkedFeatures_1.length; _b++) {
var feature = linkedFeatures_1[_b];
if (!linkedFeaturesCounter[feature]) {
linkedFeaturesCounter[feature] = 0;
}
linkedFeaturesCounter[feature] += 1;
}
}
}
return Object.entries(linkedFeaturesCounter)
.filter(function (_a) {
var _ = _a[0], count = _a[1];
return count > 1;
})
.map(function (_a) {
var feature = _a[0];
return feature;
});
}