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
169 lines (147 loc) • 4.83 kB
text/typescript
import { calculateOverriddenValue, valueToNumber } from '../../../server/utils/dzn-exporter/number-utils';
import { Feature } from './feature';
import { UsageLimit } from './usage-limit';
export interface AddOn {
name: string;
description?: string;
price: number | string;
unit: string;
private: boolean;
availableFor: string[];
dependsOn?: string[];
excludes?: string[];
features?: { [key: string]: Feature };
usageLimits?: { [key: string]: UsageLimit };
usageLimitsExtensions?: { [key: string]: UsageLimit };
subscriptionConstraints: { minQuantity: number; maxQuantity: number, quantityStep: number };
}
export function getAddOnNames(addOns?: Record<string, AddOn>): string[] {
if (!addOns) {
return [];
}
return Object.values(addOns).map(addOn => addOn.name);
}
export function getAddOnPrices(addOns?: Record<string, AddOn>): number[] {
const prices: number[] = [];
if (!addOns) {
return prices;
}
for (const addOn of Object.values(addOns)) {
const price = addOn.price;
if (typeof price === 'number') {
prices.push(price);
} else if (typeof price === 'string') {
prices.push(100);
}
}
return prices;
}
export function calculateAddOnsFeaturesMatrix(features: Record<string, Feature>, addOns: Record<string, AddOn>): number[][] {
const matrix = [];
for (const addOn of Object.values(addOns)) {
const addOnFeatures = addOn.features;
if (!addOnFeatures) {
matrix.push(new Array(Object.values(features).length).fill(0));
continue;
}
const row = [];
for (const feature of Object.values(features)) {
let value = 0;
const overriddenValue = addOnFeatures[feature.name] ? calculateOverriddenValue({...addOnFeatures[feature.name], valueType: feature.valueType}) : undefined;
if (overriddenValue) {
value = 1;
}
row.push(value);
}
matrix.push(row);
}
return matrix;
}
export function calculateAddOnsUsageLimitsMatrix(
usageLimits: Record<string, UsageLimit>,
addOns: Record<string, AddOn>
): number[][] {
const matrix: number[][] = [];
if (Object.keys(usageLimits).length === 0) {
return matrix;
}
for (const addOn of Object.values(addOns)) {
const addOnUsageLimits = addOn.usageLimits || {};
const numberOfOverriddenAddOns = Object.keys(addOnUsageLimits).length;
if (numberOfOverriddenAddOns === 0) {
matrix.push(new Array(Object.keys(usageLimits).length).fill(0));
continue;
}
const row = [];
for (const usageLimit of Object.values(usageLimits)) {
const value = addOnUsageLimits[usageLimit.name] ? calculateOverriddenValue({...addOnUsageLimits[usageLimit.name], valueType: usageLimit.valueType}) : 0;
row.push(value);
}
matrix.push(row);
}
return matrix;
}
export function calculateAddOnsUsageLimitsExtensionsMatrix(
usageLimits: Record<string, UsageLimit>,
addOns: Record<string, AddOn>
): number[][] {
const matrix: number[][] = [];
if (Object.keys(usageLimits).length === 0) {
return matrix;
}
for (const addOn of Object.values(addOns)) {
const addOnUsageLimits = addOn.usageLimitsExtensions || {};
const numberOfOverriddenAddOns = Object.keys(addOnUsageLimits).length;
if (numberOfOverriddenAddOns === 0) {
matrix.push(new Array(Object.keys(usageLimits).length).fill(0));
continue;
}
const row = [];
for (const usageLimit of Object.values(usageLimits)) {
const value = addOnUsageLimits[usageLimit.name]
? valueToNumber(addOnUsageLimits[usageLimit.name].value)
: 0;
row.push(value);
}
matrix.push(row);
}
return matrix;
}
export function calculateAddOnAvailableForMatrix(
planNames: string[],
addOns?: Record<string, AddOn>
): number[][] {
const matrix: number[][] = [];
if (!addOns || planNames.length === 0) {
return matrix;
}
for (const addOn of Object.values(addOns)) {
const row = [];
for (const planName of planNames) {
const value = addOn.availableFor.includes(planName) ? 1 : 0;
row.push(value);
}
matrix.push(row);
}
return matrix;
}
export function calculateAddOnsDependsOnOExcludesMatrix(addOns?: Record<string, AddOn>, field: "dependsOn" | "excludes" = "dependsOn"): number[][] {
const matrix: number[][] = [];
if (!addOns) {
return matrix;
}
for (const addOn of Object.values(addOns)) {
const selectedField = field === "dependsOn" ? addOn.dependsOn : addOn.excludes;
const row = [];
if (!selectedField) {
row.push(new Array(Object.values(addOns).length).fill(0));
continue;
}
for (const innerAddOn of Object.values(addOns)) {
const value = selectedField.includes(innerAddOn.name) ? 1 : 0;
row.push(value);
}
matrix.push(row);
}
return matrix;
}