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
1450 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
const input: PurchaseInfo = {
80
version: CURRENT_VERSION,
81
type: "quota",
82
user,
83
upgrade: "custom" as "custom",
84
quantity: run_limit,
85
subscription: (period == "range" ? "no" : period) as
86
| "no"
87
| "monthly"
88
| "yearly",
89
custom_ram: ram,
90
custom_dedicated_ram: 0,
91
custom_cpu: cpu,
92
custom_dedicated_cpu: 0,
93
custom_disk: disk,
94
custom_always_running: always_running,
95
custom_member: member,
96
custom_uptime: uptime,
97
boost,
98
// For computing the *shopping cart checkout price* of a subscription,
99
// we remove the endpoints data. Otherwise, compute_cost(input).cost
100
// returns the price for that exact interval, not the generic monthly
101
// cost, since compute_cost is also used for refunds/value computations
102
// (though we never do prorated refunds of subscriptions anymore!).
103
// In particular, we only include start/end dates for explicit ranges.
104
...(period == "range"
105
? fixRange(range, period, noRangeShift)
106
: { start: null, end: null }),
107
};
108
return {
109
...compute_cost(input),
110
input,
111
period,
112
};
113
}
114
}
115
116