Skip to content
This repository was archived by the owner on Sep 8, 2021. It is now read-only.

Commit c1941cb

Browse files
committed
Support for percentage based member calculations
1 parent 451aa59 commit c1941cb

File tree

4 files changed

+81
-21
lines changed

4 files changed

+81
-21
lines changed

src/calculator.js

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import {checkClaims} from './claims';
2+
13
class Price {
24
constructor() {
35
this.subtotal = 0;
@@ -22,14 +24,17 @@ function findTax(settings, country, type) {
2224
return null;
2325
}
2426

25-
function couponValidFor(coupon, item) {
27+
function couponValidFor(claims, coupon, item) {
28+
if (!checkClaims(claims, coupon.claims)) {
29+
return false;
30+
}
2631
if (coupon.product_types && coupon.product_types.length) {
2732
return coupon.product_types.indexOf(item.type) > -1;
2833
}
2934
return true;
3035
}
3136

32-
export function calculatePrices(settings, country, currency, coupon, items) {
37+
export function calculatePrices(settings, claims, country, currency, coupon, items) {
3338
const price = new Price();
3439
const includeTaxes = settings && settings.prices_include_taxes;
3540
price.items = [];
@@ -68,10 +73,21 @@ export function calculatePrices(settings, country, currency, coupon, items) {
6873
});
6974
}
7075

71-
if (coupon && couponValidFor(coupon, item)) {
76+
if (coupon && couponValidFor(claims, coupon, item)) {
7277
const amountToDiscount = includeTaxes ? itemPrice.subtotal + itemPrice.taxes : itemPrice.subtotal;
7378
itemPrice.discount = Math.round(amountToDiscount * coupon.percentage / 100);
7479
}
80+
if (settings && settings.member_discounts) {
81+
settings.member_discounts.forEach((discount) => {
82+
console.log('checking if discount applies', discount);
83+
if (couponValidFor(claims, discount, item)) {
84+
const amountToDiscount = includeTaxes ? itemPrice.subtotal + itemPrice.taxes : itemPrice.subtotal;
85+
console.log('applying discount on ', amountToDiscount, discount.percentage);
86+
itemPrice.discount = itemPrice.discount || 0;
87+
itemPrice.discount += Math.round(amountToDiscount * discount.percentage / 100);
88+
}
89+
});
90+
}
7591

7692
itemPrice.total = itemPrice.subtotal - itemPrice.discount + itemPrice.taxes;
7793
price.items.push(itemPrice);

src/calculator.test.js

+34-12
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
import {calculatePrices} from './calculator';
22

33
test('no items', () => {
4-
const price = calculatePrices(null, "USA", "USD", null, []);
4+
const price = calculatePrices(null, null, "USA", "USD", null, []);
55
expect(price.total).toBe(0);
66
});
77

88
test('no taxes', () => {
9-
const price = calculatePrices(null, "USA", "USD", null, [{price: {cents: 100}, type: "test"}]);
9+
const price = calculatePrices(null, null, "USA", "USD", null, [{price: {cents: 100}, type: "test"}]);
1010
expect(price.subtotal).toBe(100);
1111
expect(price.taxes).toBe(0);
1212
expect(price.discount).toBe(0);
1313
expect(price.total).toBe(100);
1414
});
1515

1616
test('fixed vat', () => {
17-
const price = calculatePrices(null, "USA", "USD", null, [{price: {cents: 100}, vat: 9, type: "test"}]);
17+
const price = calculatePrices(null, null, "USA", "USD", null, [{price: {cents: 100}, vat: 9, type: "test"}]);
1818
expect(price.subtotal).toBe(100);
1919
expect(price.taxes).toBe(9);
2020
expect(price.discount).toBe(0);
2121
expect(price.total).toBe(109);
2222
})
2323

2424
test('fixed vat when prices include taxes', () => {
25-
const price = calculatePrices({prices_include_taxes: true}, "USA", "USD", null, [{price: {cents: 100}, vat: 9, type: "test"}]);
25+
const price = calculatePrices({prices_include_taxes: true}, null, "USA", "USD", null, [{price: {cents: 100}, vat: 9, type: "test"}]);
2626
expect(price.subtotal).toBe(92);
2727
expect(price.taxes).toBe(8);
2828
expect(price.discount).toBe(0);
@@ -31,7 +31,7 @@ test('fixed vat when prices include taxes', () => {
3131

3232
test('country based VAT', () => {
3333
const settings = {taxes: [{percentage: 21, product_types: ["test"], countries: ["USA"]}]};
34-
const price = calculatePrices(settings, "USA", "USD", null, [{price: {cents: 100}, type: "test"}]);
34+
const price = calculatePrices(settings, null, "USA", "USD", null, [{price: {cents: 100}, type: "test"}]);
3535
expect(price.subtotal).toBe(100);
3636
expect(price.taxes).toBe(21);
3737
expect(price.discount).toBe(0);
@@ -40,31 +40,31 @@ test('country based VAT', () => {
4040

4141
test('country based VAT when prices include taxes', () => {
4242
const settings = {prices_include_taxes: true, taxes: [{percentage: 21, product_types: ["test"], countries: ["USA"]}]};
43-
const price = calculatePrices(settings, "USA", "USD", null, [{price: {cents: 100}, type: "test"}]);
43+
const price = calculatePrices(settings, null, "USA", "USD", null, [{price: {cents: 100}, type: "test"}]);
4444
expect(price.subtotal).toBe(83);
4545
expect(price.taxes).toBe(17);
4646
expect(price.discount).toBe(0);
4747
expect(price.total).toBe(100);
4848
});
4949

5050
test('coupon with no taxes', () => {
51-
const price = calculatePrices(null, "USA", "USD", {percentage: 10, product_types: ["test"]}, [{price: {cents: 100}, type: "test"}]);
51+
const price = calculatePrices(null, null, "USA", "USD", {percentage: 10, product_types: ["test"]}, [{price: {cents: 100}, type: "test"}]);
5252
expect(price.subtotal).toBe(100);
5353
expect(price.taxes).toBe(0);
5454
expect(price.discount).toBe(10);
5555
expect(price.total).toBe(90);
5656
});
5757

5858
test('coupon with vat', () => {
59-
const price = calculatePrices(null, "USA", "USD", {percentage: 10, product_types: ["test"]}, [{price: {cents: 100}, vat: 9, type: "test"}]);
59+
const price = calculatePrices(null, null, "USA", "USD", {percentage: 10, product_types: ["test"]}, [{price: {cents: 100}, vat: 9, type: "test"}]);
6060
expect(price.subtotal).toBe(100);
6161
expect(price.taxes).toBe(9);
6262
expect(price.discount).toBe(10);
6363
expect(price.total).toBe(99);
6464
});
6565

6666
test('coupon with vat when prices include taxes', () => {
67-
const price = calculatePrices({prices_include_taxes: true}, "USA", "USD", {percentage: 10, product_types: ["test"]}, [{price: {cents: 100}, vat: 9, type: "test"}]);
67+
const price = calculatePrices({prices_include_taxes: true}, null, "USA", "USD", {percentage: 10, product_types: ["test"]}, [{price: {cents: 100}, vat: 9, type: "test"}]);
6868
expect(price.subtotal).toBe(92);
6969
expect(price.taxes).toBe(8);
7070
expect(price.discount).toBe(10);
@@ -83,7 +83,7 @@ test('pricing items', () => {
8383
countries: ["DE"]
8484
}]
8585
};
86-
const price = calculatePrices(settings, "DE", "EUR", null, [{
86+
const price = calculatePrices(settings, null, "DE", "EUR", null, [{
8787
price: {cents: 100, items: [{cents: 80, type: "book"}, {cents: 20, type: "ebook"}]},
8888
type: "book"
8989
}]);
@@ -94,9 +94,31 @@ test('pricing items', () => {
9494
});
9595

9696
test('quantity', () => {
97-
const price = calculatePrices(null, "USA", "USD", {percentage: 10, product_types: ["test"]}, [{price: {cents: 100}, quantity: 2, vat: 9, type: "test"}]);
97+
const price = calculatePrices(null, null, "USA", "USD", {percentage: 10, product_types: ["test"]}, [{price: {cents: 100}, quantity: 2, vat: 9, type: "test"}]);
9898
expect(price.subtotal).toBe(200);
9999
expect(price.taxes).toBe(18);
100100
expect(price.discount).toBe(20);
101101
expect(price.total).toBe(198);
102-
})
102+
});
103+
104+
test('member discounts', () => {
105+
const settings = {
106+
"member_discounts": [
107+
{
108+
"claims": {"app_metadata.subscriptions.members": "supporter"},
109+
"percentage": 10
110+
}
111+
]
112+
};
113+
const price = calculatePrices(
114+
settings,
115+
{app_metadata: {subscriptions: {members: "supporter"}}},
116+
"USA", "USD", null,
117+
[{price: {cents: 100}, type: "test"}]
118+
);
119+
expect(price.subtotal).toBe(100);
120+
expect(price.taxes).toBe(0);
121+
expect(price.discount).toBe(10);
122+
expect(price.total).toBe(90);
123+
124+
});

src/claims.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
export function checkClaims(claims, requiredClaims) {
2+
if (!requiredClaims) {
3+
return true;
4+
}
5+
if (!claims) {
6+
return false;
7+
}
8+
for (const key in requiredClaims) {
9+
const parts = key.split(".");
10+
let obj = claims;
11+
for (let i=0; i < parts.length; i++) {
12+
const part = parts[i];
13+
let newObj = obj[part];
14+
if (!newObj) {
15+
return false;
16+
}
17+
if (i === parts.length - 1) {
18+
return newObj === requiredClaims[key];
19+
}
20+
obj = newObj;
21+
}
22+
}
23+
return false;
24+
}

src/index.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
import API from "micro-api-client";
22
import {calculatePrices} from "./calculator";
3+
import {checkClaims} from './claims';
34

45
const HTTPRegexp = /^http:\/\//;
56
const cartKey = "gocommerce.shopping-cart";
67
const vatnumbers = {};
78

8-
function checkRole(user, role) {
9-
return user && user.roles && user.roles.filter((r) => r == role)[0];
10-
}
119

1210
function getPrice(prices, currency, user) {
1311
return prices
1412
.filter((price) => currency == (price.currency || "USD").toUpperCase())
15-
.filter((price) => price.role ? checkRole(user) : true)
13+
.filter((price) => price.claims ? checkClaims(user && user.claims && user.claims(), price.claims) : true)
1614
.map((price) => {
1715
price.cents = price.cents || parseInt(parseFloat(price.amount) * 100);
1816
return price;
@@ -158,8 +156,8 @@ export default class GoCommerce {
158156
}
159157
}
160158

161-
const price = calculatePrices(this.settings, this.billing_country, this.currency, this.coupon, items);
162-
console.log('price %o',price);
159+
const claims = this.user && this.user.claims && this.user.claims();
160+
const price = calculatePrices(this.settings, claims, this.billing_country, this.currency, this.coupon, items);
163161

164162
cart.subtotal = priceObject(price.subtotal, this.currency);
165163
cart.discount = priceObject(price.discount, this.currency);

0 commit comments

Comments
 (0)