moneyutils-in 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # moneyutils-in
2
+
3
+ A lightweight, TypeScript-first utility library for handling INR formatting, GST, discounts, commissions, fees, and common money calculations for Indian e-commerce, booking, and payment applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install moneyutils-in
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```ts
14
+ import {
15
+ formatINR,
16
+ addGST,
17
+ calculatePercentageDiscount,
18
+ calculateCommission,
19
+ } from "moneyutils-in";
20
+
21
+ formatINR(125000);
22
+ // ₹1,25,000.00
23
+
24
+ addGST(1000, 18);
25
+ // Total: ₹1,180
26
+
27
+ calculatePercentageDiscount(2000, 15);
28
+ // Final amount: ₹1,700
29
+
30
+ calculateCommission(5000, 12);
31
+ // Commission: ₹600
32
+ // Net amount: ₹4,400
33
+ ```
34
+
35
+ ## Features
36
+
37
+ - INR formatting with number grouping
38
+ - Rupee ↔ paise conversion
39
+ - GST calculations
40
+ - CGST, SGST and IGST splitting
41
+ - GST-inclusive price extraction
42
+ - Percentage and fixed discounts
43
+ - Percentage calculations
44
+ - Platform and convenience fees
45
+ - Marketplace commissions
46
+ - Cart/order total calculations
47
+ - TypeScript support
48
+ - ESM and CommonJS support
49
+ - Zero runtime dependencies
50
+
51
+ ## Example: Order Calculation
52
+
53
+ ```ts
54
+ import { calculateOrderTotal } from "moneyutils-in";
55
+
56
+ const total = calculateOrderTotal({
57
+ items: [
58
+ { price: 999, quantity: 2 },
59
+ { price: 2499, quantity: 1 },
60
+ ],
61
+ discount: {
62
+ type: "percentage",
63
+ value: 10,
64
+ },
65
+ fees: [{ name: "Delivery", amount: 50 }],
66
+ tax: {
67
+ rate: 18,
68
+ },
69
+ });
70
+
71
+ console.log(total.grandTotal);
72
+ ```
73
+
74
+ ## Disclaimer
75
+
76
+ GST and tax utilities perform calculations based on the values provided by the developer. They do not determine the legally applicable tax rate or tax treatment for a transaction.
77
+
78
+ ## License
79
+
80
+ MIT
@@ -0,0 +1,7 @@
1
+ export interface CommissionResult {
2
+ amount: number;
3
+ commissionRate: number;
4
+ commissionAmount: number;
5
+ netAmount: number;
6
+ }
7
+ export declare function calculateCommission(amount: number, commissionRate: number): CommissionResult;
@@ -0,0 +1,7 @@
1
+ export interface PercentageFeeResult {
2
+ baseAmount: number;
3
+ feeRate: number;
4
+ feeAmount: number;
5
+ totalAmount: number;
6
+ }
7
+ export declare function calculatePercentageFee(amount: number, feeRate: number): PercentageFeeResult;
@@ -0,0 +1,34 @@
1
+ export interface OrderItem {
2
+ price: number;
3
+ quantity: number;
4
+ }
5
+ export interface OrderFee {
6
+ name: string;
7
+ amount: number;
8
+ }
9
+ export type OrderDiscount = {
10
+ type: "percentage";
11
+ value: number;
12
+ } | {
13
+ type: "fixed";
14
+ value: number;
15
+ };
16
+ export interface OrderTax {
17
+ rate: number;
18
+ }
19
+ export interface CalculateOrderTotalInput {
20
+ items: OrderItem[];
21
+ discount?: OrderDiscount;
22
+ fees?: OrderFee[];
23
+ tax?: OrderTax;
24
+ }
25
+ export interface OrderTotalResult {
26
+ subtotal: number;
27
+ discountAmount: number;
28
+ subtotalAfterDiscount: number;
29
+ feeTotal: number;
30
+ taxableAmount: number;
31
+ taxAmount: number;
32
+ grandTotal: number;
33
+ }
34
+ export declare function calculateOrderTotal(input: CalculateOrderTotalInput): OrderTotalResult;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Converts rupees to paise.
3
+ *
4
+ * @example
5
+ * rupeesToPaise(499.99) // 49999
6
+ */
7
+ export declare function rupeesToPaise(rupees: number): number;
8
+ /**
9
+ * Converts paise to rupees.
10
+ *
11
+ * @example
12
+ * paiseToRupees(49999) // 499.99
13
+ */
14
+ export declare function paiseToRupees(paise: number): number;
@@ -0,0 +1,5 @@
1
+ export interface FormatINROptions {
2
+ decimals?: number;
3
+ symbol?: boolean;
4
+ }
5
+ export declare function formatINR(amount: number, options?: FormatINROptions): string;
@@ -0,0 +1,13 @@
1
+ export interface DiscountResult {
2
+ originalAmount: number;
3
+ discountAmount: number;
4
+ finalAmount: number;
5
+ percentage: number;
6
+ }
7
+ export interface FixedDiscountResult {
8
+ originalAmount: number;
9
+ discountAmount: number;
10
+ finalAmount: number;
11
+ }
12
+ export declare function calculatePercentageDiscount(amount: number, percentage: number): DiscountResult;
13
+ export declare function calculateFixedDiscount(amount: number, discount: number): FixedDiscountResult;
@@ -0,0 +1,12 @@
1
+ export type GSTTransactionType = "INTRA_STATE" | "INTER_STATE";
2
+ export interface GSTResult {
3
+ taxableAmount: number;
4
+ gstRate: number;
5
+ cgst: number;
6
+ sgst: number;
7
+ igst: number;
8
+ totalTax: number;
9
+ totalAmount: number;
10
+ }
11
+ export declare function addGST(amount: number, gstRate: number, transactionType?: GSTTransactionType): GSTResult;
12
+ export declare function removeGST(inclusiveAmount: number, gstRate: number, transactionType?: GSTTransactionType): GSTResult;
@@ -0,0 +1,8 @@
1
+ export { formatINR, type FormatINROptions } from "./currency/format-rupee.js";
2
+ export { rupeesToPaise, paiseToRupees } from "./currency/conversion.js";
3
+ export { calculatePercentageDiscount, calculateFixedDiscount, type DiscountResult, type FixedDiscountResult } from "./discount/discount.js";
4
+ export { addGST, removeGST, type GSTResult, type GSTTransactionType } from "./gst/gst.js";
5
+ export { calculateOrderTotal, type OrderItem, type OrderFee, type OrderDiscount, type OrderTax, type CalculateOrderTotalInput, type OrderTotalResult } from "./commerce/order-total.js";
6
+ export { calculatePercentage } from "./percentage/percentage.js";
7
+ export { calculateCommission, type CommissionResult } from "./commerce/commission.js";
8
+ export { calculatePercentageFee, type PercentageFeeResult } from "./commerce/fee.js";
package/dist/index.js ADDED
@@ -0,0 +1,308 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ addGST: () => addGST,
24
+ calculateCommission: () => calculateCommission,
25
+ calculateFixedDiscount: () => calculateFixedDiscount,
26
+ calculateOrderTotal: () => calculateOrderTotal,
27
+ calculatePercentage: () => calculatePercentage,
28
+ calculatePercentageDiscount: () => calculatePercentageDiscount,
29
+ calculatePercentageFee: () => calculatePercentageFee,
30
+ formatINR: () => formatINR,
31
+ paiseToRupees: () => paiseToRupees,
32
+ removeGST: () => removeGST,
33
+ rupeesToPaise: () => rupeesToPaise
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/currency/format-rupee.ts
38
+ function formatINR(amount, options = {}) {
39
+ const {
40
+ decimals = 2,
41
+ symbol = true
42
+ } = options;
43
+ if (!Number.isFinite(amount)) {
44
+ throw new TypeError("Amount must be a finite number");
45
+ }
46
+ const formatted = new Intl.NumberFormat("en-IN", {
47
+ minimumFractionDigits: decimals,
48
+ maximumFractionDigits: decimals
49
+ }).format(amount);
50
+ return symbol ? `\u20B9${formatted}` : formatted;
51
+ }
52
+
53
+ // src/currency/conversion.ts
54
+ function rupeesToPaise(rupees) {
55
+ if (!Number.isFinite(rupees)) {
56
+ throw new TypeError("Amount must be a finite number");
57
+ }
58
+ return Math.round(rupees * 100);
59
+ }
60
+ function paiseToRupees(paise) {
61
+ if (!Number.isFinite(paise)) {
62
+ throw new TypeError("Amount must be a finite number");
63
+ }
64
+ if (!Number.isInteger(paise)) {
65
+ throw new TypeError("Paise must be an integer");
66
+ }
67
+ return paise / 100;
68
+ }
69
+
70
+ // src/internal/round-money.ts
71
+ function roundMoney(value) {
72
+ return Math.round((value + Number.EPSILON) * 100) / 100;
73
+ }
74
+
75
+ // src/internal/validate-amount.ts
76
+ function validateAmount(amount, name = "Amount") {
77
+ if (!Number.isFinite(amount) || amount < 0) {
78
+ throw new TypeError(
79
+ `${name} must be a non-negative finite number`
80
+ );
81
+ }
82
+ }
83
+
84
+ // src/discount/discount.ts
85
+ function calculatePercentageDiscount(amount, percentage) {
86
+ validateAmount(amount);
87
+ if (!Number.isFinite(percentage) || percentage < 0 || percentage > 100) {
88
+ throw new RangeError(
89
+ "Percentage must be between 0 and 100"
90
+ );
91
+ }
92
+ const discountAmount = roundMoney(
93
+ amount * percentage / 100
94
+ );
95
+ const finalAmount = roundMoney(
96
+ amount - discountAmount
97
+ );
98
+ return {
99
+ originalAmount: amount,
100
+ discountAmount,
101
+ finalAmount,
102
+ percentage
103
+ };
104
+ }
105
+ function calculateFixedDiscount(amount, discount) {
106
+ validateAmount(amount);
107
+ validateAmount(discount, "Discount");
108
+ const discountAmount = Math.min(
109
+ discount,
110
+ amount
111
+ );
112
+ return {
113
+ originalAmount: amount,
114
+ discountAmount,
115
+ finalAmount: roundMoney(
116
+ amount - discountAmount
117
+ )
118
+ };
119
+ }
120
+
121
+ // src/gst/gst.ts
122
+ function validateGST(amount, gstRate) {
123
+ validateAmount(amount);
124
+ if (!Number.isFinite(gstRate) || gstRate < 0 || gstRate > 100) {
125
+ throw new RangeError(
126
+ "GST rate must be between 0 and 100"
127
+ );
128
+ }
129
+ }
130
+ function addGST(amount, gstRate, transactionType = "INTRA_STATE") {
131
+ validateGST(amount, gstRate);
132
+ const totalTax = roundMoney(amount * gstRate / 100);
133
+ const cgst = transactionType === "INTRA_STATE" ? roundMoney(totalTax / 2) : 0;
134
+ const sgst = transactionType === "INTRA_STATE" ? roundMoney(totalTax - cgst) : 0;
135
+ const igst = transactionType === "INTER_STATE" ? totalTax : 0;
136
+ return {
137
+ taxableAmount: amount,
138
+ gstRate,
139
+ cgst,
140
+ sgst,
141
+ igst,
142
+ totalTax,
143
+ totalAmount: roundMoney(amount + totalTax)
144
+ };
145
+ }
146
+ function removeGST(inclusiveAmount, gstRate, transactionType = "INTRA_STATE") {
147
+ validateGST(inclusiveAmount, gstRate);
148
+ const taxableAmount = roundMoney(inclusiveAmount / (1 + gstRate / 100));
149
+ const totalTax = roundMoney(inclusiveAmount - taxableAmount);
150
+ const cgst = transactionType === "INTRA_STATE" ? roundMoney(totalTax / 2) : 0;
151
+ const sgst = transactionType === "INTRA_STATE" ? roundMoney(totalTax - cgst) : 0;
152
+ const igst = transactionType === "INTER_STATE" ? totalTax : 0;
153
+ return {
154
+ taxableAmount,
155
+ gstRate,
156
+ cgst,
157
+ sgst,
158
+ igst,
159
+ totalTax,
160
+ totalAmount: inclusiveAmount
161
+ };
162
+ }
163
+
164
+ // src/commerce/order-total.ts
165
+ function calculateOrderTotal(input) {
166
+ const {
167
+ items,
168
+ discount,
169
+ fees = [],
170
+ tax
171
+ } = input;
172
+ if (!Array.isArray(items) || items.length === 0) {
173
+ throw new TypeError("Items must contain at least one item");
174
+ }
175
+ let subtotal = 0;
176
+ for (const item of items) {
177
+ validateAmount(item.price, "Item price");
178
+ if (!Number.isInteger(item.quantity) || item.quantity <= 0) {
179
+ throw new TypeError(
180
+ "Item quantity must be a positive integer"
181
+ );
182
+ }
183
+ subtotal += item.price * item.quantity;
184
+ }
185
+ subtotal = roundMoney(subtotal);
186
+ let discountAmount = 0;
187
+ if (discount) {
188
+ validateAmount(discount.value, "Discount");
189
+ if (discount.type === "percentage") {
190
+ if (discount.value > 100) {
191
+ throw new RangeError(
192
+ "Percentage discount cannot exceed 100"
193
+ );
194
+ }
195
+ discountAmount = roundMoney(
196
+ subtotal * discount.value / 100
197
+ );
198
+ } else {
199
+ discountAmount = Math.min(
200
+ discount.value,
201
+ subtotal
202
+ );
203
+ }
204
+ }
205
+ const subtotalAfterDiscount = roundMoney(
206
+ subtotal - discountAmount
207
+ );
208
+ let feeTotal = 0;
209
+ for (const fee of fees) {
210
+ validateAmount(fee.amount, `Fee "${fee.name}"`);
211
+ feeTotal += fee.amount;
212
+ }
213
+ feeTotal = roundMoney(feeTotal);
214
+ const taxableAmount = roundMoney(
215
+ subtotalAfterDiscount + feeTotal
216
+ );
217
+ let taxAmount = 0;
218
+ if (tax) {
219
+ validateAmount(tax.rate, "Tax rate");
220
+ if (tax.rate > 100) {
221
+ throw new RangeError(
222
+ "Tax rate cannot exceed 100"
223
+ );
224
+ }
225
+ taxAmount = roundMoney(
226
+ taxableAmount * tax.rate / 100
227
+ );
228
+ }
229
+ const grandTotal = roundMoney(
230
+ taxableAmount + taxAmount
231
+ );
232
+ return {
233
+ subtotal,
234
+ discountAmount,
235
+ subtotalAfterDiscount,
236
+ feeTotal,
237
+ taxableAmount,
238
+ taxAmount,
239
+ grandTotal
240
+ };
241
+ }
242
+
243
+ // src/percentage/percentage.ts
244
+ function calculatePercentage(amount, percentage) {
245
+ validateAmount(amount);
246
+ validateAmount(percentage, "Percentage");
247
+ return roundMoney(amount * percentage / 100);
248
+ }
249
+
250
+ // src/commerce/commission.ts
251
+ function calculateCommission(amount, commissionRate) {
252
+ validateAmount(amount);
253
+ validateAmount(commissionRate, "Commission rate");
254
+ if (commissionRate > 100) {
255
+ throw new RangeError(
256
+ "Commission rate cannot exceed 100"
257
+ );
258
+ }
259
+ const commissionAmount = calculatePercentage(
260
+ amount,
261
+ commissionRate
262
+ );
263
+ return {
264
+ amount,
265
+ commissionRate,
266
+ commissionAmount,
267
+ netAmount: roundMoney(
268
+ amount - commissionAmount
269
+ )
270
+ };
271
+ }
272
+
273
+ // src/commerce/fee.ts
274
+ function calculatePercentageFee(amount, feeRate) {
275
+ validateAmount(amount);
276
+ validateAmount(feeRate, "Fee rate");
277
+ if (feeRate > 100) {
278
+ throw new RangeError(
279
+ "Fee rate cannot exceed 100"
280
+ );
281
+ }
282
+ const feeAmount = calculatePercentage(
283
+ amount,
284
+ feeRate
285
+ );
286
+ return {
287
+ baseAmount: amount,
288
+ feeRate,
289
+ feeAmount,
290
+ totalAmount: roundMoney(
291
+ amount + feeAmount
292
+ )
293
+ };
294
+ }
295
+ // Annotate the CommonJS export names for ESM import in node:
296
+ 0 && (module.exports = {
297
+ addGST,
298
+ calculateCommission,
299
+ calculateFixedDiscount,
300
+ calculateOrderTotal,
301
+ calculatePercentage,
302
+ calculatePercentageDiscount,
303
+ calculatePercentageFee,
304
+ formatINR,
305
+ paiseToRupees,
306
+ removeGST,
307
+ rupeesToPaise
308
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,271 @@
1
+ // src/currency/format-rupee.ts
2
+ function formatINR(amount, options = {}) {
3
+ const {
4
+ decimals = 2,
5
+ symbol = true
6
+ } = options;
7
+ if (!Number.isFinite(amount)) {
8
+ throw new TypeError("Amount must be a finite number");
9
+ }
10
+ const formatted = new Intl.NumberFormat("en-IN", {
11
+ minimumFractionDigits: decimals,
12
+ maximumFractionDigits: decimals
13
+ }).format(amount);
14
+ return symbol ? `\u20B9${formatted}` : formatted;
15
+ }
16
+
17
+ // src/currency/conversion.ts
18
+ function rupeesToPaise(rupees) {
19
+ if (!Number.isFinite(rupees)) {
20
+ throw new TypeError("Amount must be a finite number");
21
+ }
22
+ return Math.round(rupees * 100);
23
+ }
24
+ function paiseToRupees(paise) {
25
+ if (!Number.isFinite(paise)) {
26
+ throw new TypeError("Amount must be a finite number");
27
+ }
28
+ if (!Number.isInteger(paise)) {
29
+ throw new TypeError("Paise must be an integer");
30
+ }
31
+ return paise / 100;
32
+ }
33
+
34
+ // src/internal/round-money.ts
35
+ function roundMoney(value) {
36
+ return Math.round((value + Number.EPSILON) * 100) / 100;
37
+ }
38
+
39
+ // src/internal/validate-amount.ts
40
+ function validateAmount(amount, name = "Amount") {
41
+ if (!Number.isFinite(amount) || amount < 0) {
42
+ throw new TypeError(
43
+ `${name} must be a non-negative finite number`
44
+ );
45
+ }
46
+ }
47
+
48
+ // src/discount/discount.ts
49
+ function calculatePercentageDiscount(amount, percentage) {
50
+ validateAmount(amount);
51
+ if (!Number.isFinite(percentage) || percentage < 0 || percentage > 100) {
52
+ throw new RangeError(
53
+ "Percentage must be between 0 and 100"
54
+ );
55
+ }
56
+ const discountAmount = roundMoney(
57
+ amount * percentage / 100
58
+ );
59
+ const finalAmount = roundMoney(
60
+ amount - discountAmount
61
+ );
62
+ return {
63
+ originalAmount: amount,
64
+ discountAmount,
65
+ finalAmount,
66
+ percentage
67
+ };
68
+ }
69
+ function calculateFixedDiscount(amount, discount) {
70
+ validateAmount(amount);
71
+ validateAmount(discount, "Discount");
72
+ const discountAmount = Math.min(
73
+ discount,
74
+ amount
75
+ );
76
+ return {
77
+ originalAmount: amount,
78
+ discountAmount,
79
+ finalAmount: roundMoney(
80
+ amount - discountAmount
81
+ )
82
+ };
83
+ }
84
+
85
+ // src/gst/gst.ts
86
+ function validateGST(amount, gstRate) {
87
+ validateAmount(amount);
88
+ if (!Number.isFinite(gstRate) || gstRate < 0 || gstRate > 100) {
89
+ throw new RangeError(
90
+ "GST rate must be between 0 and 100"
91
+ );
92
+ }
93
+ }
94
+ function addGST(amount, gstRate, transactionType = "INTRA_STATE") {
95
+ validateGST(amount, gstRate);
96
+ const totalTax = roundMoney(amount * gstRate / 100);
97
+ const cgst = transactionType === "INTRA_STATE" ? roundMoney(totalTax / 2) : 0;
98
+ const sgst = transactionType === "INTRA_STATE" ? roundMoney(totalTax - cgst) : 0;
99
+ const igst = transactionType === "INTER_STATE" ? totalTax : 0;
100
+ return {
101
+ taxableAmount: amount,
102
+ gstRate,
103
+ cgst,
104
+ sgst,
105
+ igst,
106
+ totalTax,
107
+ totalAmount: roundMoney(amount + totalTax)
108
+ };
109
+ }
110
+ function removeGST(inclusiveAmount, gstRate, transactionType = "INTRA_STATE") {
111
+ validateGST(inclusiveAmount, gstRate);
112
+ const taxableAmount = roundMoney(inclusiveAmount / (1 + gstRate / 100));
113
+ const totalTax = roundMoney(inclusiveAmount - taxableAmount);
114
+ const cgst = transactionType === "INTRA_STATE" ? roundMoney(totalTax / 2) : 0;
115
+ const sgst = transactionType === "INTRA_STATE" ? roundMoney(totalTax - cgst) : 0;
116
+ const igst = transactionType === "INTER_STATE" ? totalTax : 0;
117
+ return {
118
+ taxableAmount,
119
+ gstRate,
120
+ cgst,
121
+ sgst,
122
+ igst,
123
+ totalTax,
124
+ totalAmount: inclusiveAmount
125
+ };
126
+ }
127
+
128
+ // src/commerce/order-total.ts
129
+ function calculateOrderTotal(input) {
130
+ const {
131
+ items,
132
+ discount,
133
+ fees = [],
134
+ tax
135
+ } = input;
136
+ if (!Array.isArray(items) || items.length === 0) {
137
+ throw new TypeError("Items must contain at least one item");
138
+ }
139
+ let subtotal = 0;
140
+ for (const item of items) {
141
+ validateAmount(item.price, "Item price");
142
+ if (!Number.isInteger(item.quantity) || item.quantity <= 0) {
143
+ throw new TypeError(
144
+ "Item quantity must be a positive integer"
145
+ );
146
+ }
147
+ subtotal += item.price * item.quantity;
148
+ }
149
+ subtotal = roundMoney(subtotal);
150
+ let discountAmount = 0;
151
+ if (discount) {
152
+ validateAmount(discount.value, "Discount");
153
+ if (discount.type === "percentage") {
154
+ if (discount.value > 100) {
155
+ throw new RangeError(
156
+ "Percentage discount cannot exceed 100"
157
+ );
158
+ }
159
+ discountAmount = roundMoney(
160
+ subtotal * discount.value / 100
161
+ );
162
+ } else {
163
+ discountAmount = Math.min(
164
+ discount.value,
165
+ subtotal
166
+ );
167
+ }
168
+ }
169
+ const subtotalAfterDiscount = roundMoney(
170
+ subtotal - discountAmount
171
+ );
172
+ let feeTotal = 0;
173
+ for (const fee of fees) {
174
+ validateAmount(fee.amount, `Fee "${fee.name}"`);
175
+ feeTotal += fee.amount;
176
+ }
177
+ feeTotal = roundMoney(feeTotal);
178
+ const taxableAmount = roundMoney(
179
+ subtotalAfterDiscount + feeTotal
180
+ );
181
+ let taxAmount = 0;
182
+ if (tax) {
183
+ validateAmount(tax.rate, "Tax rate");
184
+ if (tax.rate > 100) {
185
+ throw new RangeError(
186
+ "Tax rate cannot exceed 100"
187
+ );
188
+ }
189
+ taxAmount = roundMoney(
190
+ taxableAmount * tax.rate / 100
191
+ );
192
+ }
193
+ const grandTotal = roundMoney(
194
+ taxableAmount + taxAmount
195
+ );
196
+ return {
197
+ subtotal,
198
+ discountAmount,
199
+ subtotalAfterDiscount,
200
+ feeTotal,
201
+ taxableAmount,
202
+ taxAmount,
203
+ grandTotal
204
+ };
205
+ }
206
+
207
+ // src/percentage/percentage.ts
208
+ function calculatePercentage(amount, percentage) {
209
+ validateAmount(amount);
210
+ validateAmount(percentage, "Percentage");
211
+ return roundMoney(amount * percentage / 100);
212
+ }
213
+
214
+ // src/commerce/commission.ts
215
+ function calculateCommission(amount, commissionRate) {
216
+ validateAmount(amount);
217
+ validateAmount(commissionRate, "Commission rate");
218
+ if (commissionRate > 100) {
219
+ throw new RangeError(
220
+ "Commission rate cannot exceed 100"
221
+ );
222
+ }
223
+ const commissionAmount = calculatePercentage(
224
+ amount,
225
+ commissionRate
226
+ );
227
+ return {
228
+ amount,
229
+ commissionRate,
230
+ commissionAmount,
231
+ netAmount: roundMoney(
232
+ amount - commissionAmount
233
+ )
234
+ };
235
+ }
236
+
237
+ // src/commerce/fee.ts
238
+ function calculatePercentageFee(amount, feeRate) {
239
+ validateAmount(amount);
240
+ validateAmount(feeRate, "Fee rate");
241
+ if (feeRate > 100) {
242
+ throw new RangeError(
243
+ "Fee rate cannot exceed 100"
244
+ );
245
+ }
246
+ const feeAmount = calculatePercentage(
247
+ amount,
248
+ feeRate
249
+ );
250
+ return {
251
+ baseAmount: amount,
252
+ feeRate,
253
+ feeAmount,
254
+ totalAmount: roundMoney(
255
+ amount + feeAmount
256
+ )
257
+ };
258
+ }
259
+ export {
260
+ addGST,
261
+ calculateCommission,
262
+ calculateFixedDiscount,
263
+ calculateOrderTotal,
264
+ calculatePercentage,
265
+ calculatePercentageDiscount,
266
+ calculatePercentageFee,
267
+ formatINR,
268
+ paiseToRupees,
269
+ removeGST,
270
+ rupeesToPaise
271
+ };
@@ -0,0 +1 @@
1
+ export declare function roundMoney(value: number): number;
@@ -0,0 +1 @@
1
+ export declare function validateAmount(amount: number, name?: string): void;
@@ -0,0 +1 @@
1
+ export declare function calculatePercentage(amount: number, percentage: number): number;
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "moneyutils-in",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript-first money utilities for INR formatting, GST, discounts, taxes, payments, and calculations for Indian e-commerce and booking applications.",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "sideEffects": false,
19
+ "scripts": {
20
+ "build": "tsup src/index.ts --format cjs,esm --clean && tsc --emitDeclarationOnly",
21
+ "test": "vitest",
22
+ "test:run": "vitest run",
23
+ "typecheck": "tsc --noEmit",
24
+ "prepublishOnly": "npm run typecheck && npm run test:run && npm run build"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/Dheemanthshenoy/moneyutils-in.git"
29
+ },
30
+ "author": "Dheemanth Shenoy",
31
+ "license": "MIT",
32
+ "bugs": {
33
+ "url": "https://github.com/Dheemanthshenoy/moneyutils-in/issues"
34
+ },
35
+ "homepage": "https://github.com/Dheemanthshenoy/moneyutils-in#readme",
36
+ "keywords": [
37
+ "money",
38
+ "inr",
39
+ "india",
40
+ "currency",
41
+ "gst",
42
+ "discount",
43
+ "tax",
44
+ "ecommerce",
45
+ "booking",
46
+ "payments",
47
+ "typescript"
48
+ ],
49
+ "devDependencies": {
50
+ "@types/node": "^26.6.1",
51
+ "tsup": "^8.5.1",
52
+ "typescript": "^7.0.2",
53
+ "vitest": "^5.0.1"
54
+ }
55
+ }