'use strict'; // price-with-vat-or-sales-tax.cjs -- METHOD DECK (X063), adds or removes a stated tax rate. // Standard inclusive/exclusive tax arithmetic: inclusive = exclusive * (1 + rate); exclusive = inclusive / (1 + rate). function fmt(x, decimals) { return x.toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals }); } const DIRECTIONS = ['add', 'remove']; module.exports = { slug: 'price-with-vat-or-sales-tax', title: 'Price with VAT or sales tax', deck_category: 'currency', description: 'Adds a tax rate to an exclusive price, or removes a tax rate from an inclusive price, given a stated tax percentage.', inputs: [ { name: 'price', type: 'number', required: true, description: 'The starting price', min: 0 }, { name: 'tax_rate_percent', type: 'number', required: true, description: 'The tax (VAT or sales tax) rate as a percent', min: 0 }, { name: 'direction', type: 'string', required: true, description: '"add" treats price as tax-exclusive and adds the tax; "remove" treats price as tax-inclusive and strips the tax out', enum: DIRECTIONS }, ], outputs: [ { name: 'result', description: 'The resulting price after adding or removing tax' } ], steps: [ 'Convert the tax rate to a decimal: r = tax_rate_percent / 100.', 'If direction is "add": result = price * (1 + r) (price is treated as the tax-exclusive amount).', 'If direction is "remove": result = price / (1 + r) (price is treated as the tax-inclusive amount).', 'Round result to 2 decimal places.', ], constants: [], sources: [ { kind: 'url', value: 'https://www.investopedia.com/terms/v/valueaddedtax.asp', title: 'Value-Added Tax (VAT)', publisher: 'Investopedia', retrieved_utc: '2026-09-30T19:29:48Z', note: 'General inclusive/exclusive tax arithmetic: tax-inclusive price = tax-exclusive price * (1 + tax rate); the inverse divides instead of multiplies.' }, ], disclaimer: null, questionText(inputs) { return inputs.direction === 'add' ? `What is ${inputs.price} plus ${inputs.tax_rate_percent}% tax?` : `What is ${inputs.price} with ${inputs.tax_rate_percent}% tax removed?`; }, run(inputs) { const { price, tax_rate_percent, direction } = inputs || {}; if (typeof price !== 'number' || !isFinite(price) || price < 0) throw new Error('price must be a nonnegative finite number'); if (typeof tax_rate_percent !== 'number' || !isFinite(tax_rate_percent) || tax_rate_percent < 0) throw new Error('tax_rate_percent must be a nonnegative finite number'); if (!DIRECTIONS.includes(direction)) throw new Error('direction must be one of: ' + DIRECTIONS.join(', ')); const r = tax_rate_percent / 100; const raw = direction === 'add' ? price * (1 + r) : price / (1 + r); const result = Math.round(raw * 100) / 100; return { answer: `${fmt(result, 2)}`, values: { result } }; }, examples: [ { name: 'worked example', inputs: { price: 100, tax_rate_percent: 20, direction: 'add' }, expected: { answer: '120.00' }, check: 'By hand: 100 * (1 + 0.20) = 100 * 1.20 = 120 exactly.' }, { name: 'test vector: remove tax recovers the exclusive price', inputs: { price: 120, tax_rate_percent: 20, direction: 'remove' }, expected: { answer: '100.00' }, check: 'By hand: 120 / 1.20 = 100 exactly, recovering the worked example\'s starting price.' }, { name: 'test vector: fractional tax rate', inputs: { price: 50, tax_rate_percent: 8.25, direction: 'add' }, expected: { answer: '54.13' }, check: 'By hand: 50 * 1.0825 = 54.125, which rounds to 54.13 at 2 decimal places (round-half-up).' }, ], };