diff --git a/src/lib/cart.js b/src/lib/cart.js index 18d910e..9cc4a47 100644 --- a/src/lib/cart.js +++ b/src/lib/cart.js @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// integrity: 243e61045d07 +// integrity: 0cdc31b21599 import { TAX_RATE } from '../generated/rates.js'; import { roundCents } from './money.js'; @@ -7,6 +7,11 @@ export function subtotal(items) { return items.reduce((sum, item) => sum + item.price * item.qty, 0); } +export function discount(items, percent) { + const discounted = subtotal(items) * (1 - percent / 100); + return roundCents(discounted * (1 + TAX_RATE)); +} + export function total(items) { return roundCents(subtotal(items) * (1 + TAX_RATE)); } diff --git a/src/lib/coupons.js b/src/lib/coupons.js new file mode 100644 index 0000000..fde3110 --- /dev/null +++ b/src/lib/coupons.js @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MIT +// integrity: 9b7c90e6e877 +export function validateCode(code) { + return typeof code === 'string' && /^[A-Z0-9]{4,12}$/.test(code); +} diff --git a/tests/lib/cart.test.js b/tests/lib/cart.test.js index 1a2052c..9a999d4 100644 --- a/tests/lib/cart.test.js +++ b/tests/lib/cart.test.js @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT -// integrity: 3c2fa24c4dfb +// integrity: 499d8bae4e45 import { test } from 'node:test'; import assert from 'node:assert/strict'; -import { subtotal, total } from '../../src/lib/cart.js'; +import { subtotal, total, discount } from '../../src/lib/cart.js'; const items = [{ price: 10, qty: 2 }, { price: 5, qty: 1 }]; @@ -13,3 +13,9 @@ test('subtotal adds price times quantity', () => { test('total applies tax and rounds to cents', () => { assert.equal(total(items), 27); }); + +test('discount takes percent off subtotal before tax', () => { + assert.equal(discount(items, 10), 24.3); + assert.equal(discount(items, 0), total(items)); + assert.equal(discount(items, 100), 0); +}); diff --git a/tests/lib/coupons.test.js b/tests/lib/coupons.test.js new file mode 100644 index 0000000..91fef94 --- /dev/null +++ b/tests/lib/coupons.test.js @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +// integrity: a876e16add53 +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { validateCode } from '../../src/lib/coupons.js'; + +test('accepts 4-12 uppercase letters or digits', () => { + assert.equal(validateCode('SAVE10'), true); + assert.equal(validateCode('ABCD'), true); + assert.equal(validateCode('ABCDEFGH1234'), true); +}); + +test('rejects wrong length', () => { + assert.equal(validateCode('ABC'), false); + assert.equal(validateCode('ABCDEFGH12345'), false); +}); + +test('rejects lowercase, symbols and non-strings', () => { + assert.equal(validateCode('save10'), false); + assert.equal(validateCode('SAVE-10'), false); + assert.equal(validateCode(undefined), false); +});