Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/util/licenses/store/compute-cost.ts
6023 views
1
/*
2
* This file is part of CoCalc: Copyright © 2022 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { compute_cost } from "@cocalc/util/licenses/purchase/compute-cost";
7
import type {
8
CostInputPeriod,
9
PurchaseInfo,
10
} from "@cocalc/util/licenses/purchase/types";
11
import { fixRange } from "@cocalc/util/licenses/purchase/purchase-info";
12
import type { ComputeCostProps } from "@cocalc/util/upgrades/shopping";
13
import { CURRENT_VERSION } from "@cocalc/util/licenses/purchase/consts";
14
import { decimalMultiply } from "@cocalc/util/stripe/calc";
15
16
function computeCashVoucherPrice(props: ComputeCostProps) {
17
if (props.type != "cash-voucher") {
18
throw Error("BUG");
19
}
20
const cost_per_unit = props.whenPay == "admin" ? 0 : props.amount;
21
const quantity = props.numVouchers ?? 1;
22
const cost = decimalMultiply(cost_per_unit, quantity);
23
return {
24
// a lot of this is mainly for typescript.
25
cost,
26
cost_per_unit,
27
input: {
28
...props,
29
subscription: "no",
30
},
31
period: "range",
32
cost_per_project_per_month: 0,
33
cost_sub_month: 0,
34
cost_sub_year: 0,
35
quantity,
36
} as const;
37
}
38
39
export function computeCost(
40
props: ComputeCostProps,
41
noRangeShift?: boolean,
42
): CostInputPeriod | undefined {
43
const type = props.type ?? "quota";
44
switch (type) {
45
case "cash-voucher":
46
return computeCashVoucherPrice(props);
47
48
case "disk":
49
case "vm":
50
throw Error(`computing cost of item of type ${type} is deprecated`);
51
52
case "quota":
53
default:
54
if (
55
props.type == "disk" ||
56
props.type == "vm" ||
57
props.type == "cash-voucher"
58
) {
59
throw Error("must be a quota upgrade license");
60
}
61
const {
62
user,
63
run_limit,
64
period,
65
range,
66
ram,
67
cpu,
68
disk,
69
always_running,
70
member,
71
uptime,
72
boost = false, // if true, allow "all zero" values and start at 0 USD
73
} = props;
74
75
if (period == "range" && range?.[1] == null) {
76
return undefined;
77
}
78
79
if (run_limit == null) {
80
return undefined;
81
}
82
83
const input: PurchaseInfo = {
84
version: CURRENT_VERSION,
85
type: "quota",
86
user,
87
upgrade: "custom" as "custom",
88
quantity: run_limit,
89
subscription: (period == "range" ? "no" : period) as
90
| "no"
91
| "monthly"
92
| "yearly",
93
custom_ram: ram,
94
custom_dedicated_ram: 0,
95
custom_cpu: cpu,
96
custom_dedicated_cpu: 0,
97
custom_disk: disk,
98
custom_always_running: always_running,
99
custom_member: member,
100
custom_uptime: uptime,
101
boost,
102
// For computing the *shopping cart checkout price* of a subscription,
103
// we remove the endpoints data. Otherwise, compute_cost(input).cost
104
// returns the price for that exact interval, not the generic monthly
105
// cost, since compute_cost is also used for refunds/value computations
106
// (though we never do prorated refunds of subscriptions anymore!).
107
// In particular, we only include start/end dates for explicit ranges.
108
...(period == "range"
109
? fixRange(range, period, noRangeShift)
110
: { start: null, end: null }),
111
};
112
113
return {
114
...compute_cost(input),
115
input,
116
period,
117
};
118
}
119
}
120
121