- Add Swedish rounding (nearest nickel) for cash payments at locations with cash_rounding enabled - Add rounding_adjustment column to transactions, cash_rounding to locations - Add POS schema to database plugin for relational query support - Complete/void routes now return full transaction with line items via getById - Test harness killPort falls back to fuser when lsof unavailable (fixes stale process bug) - Add 35-test POS API suite covering discounts, drawer, transactions, tax, rounding, e2e flow - Add unit tests for tax service and POS Zod schemas Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
120 lines
3.2 KiB
TypeScript
120 lines
3.2 KiB
TypeScript
import { describe, it, expect } from 'bun:test'
|
|
import { TaxService } from '../../src/services/tax.service.js'
|
|
|
|
describe('TaxService.calculateTax', () => {
|
|
it('calculates tax on a simple amount', () => {
|
|
// 8.25% on $100
|
|
expect(TaxService.calculateTax(100, 0.0825)).toBe(8.25)
|
|
})
|
|
|
|
it('rounds to 2 decimal places', () => {
|
|
// 8.25% on $10.01 = 0.825825 → 0.83
|
|
expect(TaxService.calculateTax(10.01, 0.0825)).toBe(0.83)
|
|
})
|
|
|
|
it('returns 0 for zero rate', () => {
|
|
expect(TaxService.calculateTax(100, 0)).toBe(0)
|
|
})
|
|
|
|
it('returns 0 for zero amount', () => {
|
|
expect(TaxService.calculateTax(0, 0.0825)).toBe(0)
|
|
})
|
|
|
|
it('handles small amounts', () => {
|
|
// 8.25% on $0.99 = 0.081675 → 0.08
|
|
expect(TaxService.calculateTax(0.99, 0.0825)).toBe(0.08)
|
|
})
|
|
|
|
it('handles large amounts', () => {
|
|
// 8.25% on $9999.99 = 824.999175 → 825.00
|
|
expect(TaxService.calculateTax(9999.99, 0.0825)).toBe(825)
|
|
})
|
|
|
|
it('handles 5% service tax rate', () => {
|
|
// 5% on $60 = 3.00
|
|
expect(TaxService.calculateTax(60, 0.05)).toBe(3)
|
|
})
|
|
|
|
it('handles fractional cent rounding down', () => {
|
|
// 7% on $1.01 = 0.0707 → 0.07
|
|
expect(TaxService.calculateTax(1.01, 0.07)).toBe(0.07)
|
|
})
|
|
|
|
it('handles fractional cent rounding up', () => {
|
|
// 7% on $1.05 = 0.0735 → 0.07
|
|
expect(TaxService.calculateTax(1.05, 0.07)).toBe(0.07)
|
|
})
|
|
})
|
|
|
|
describe('TaxService.roundToNickel', () => {
|
|
it('rounds .01 down to .00', () => {
|
|
expect(TaxService.roundToNickel(10.01)).toBe(10.00)
|
|
})
|
|
|
|
it('rounds .02 down to .00', () => {
|
|
expect(TaxService.roundToNickel(10.02)).toBe(10.00)
|
|
})
|
|
|
|
it('rounds .03 up to .05', () => {
|
|
expect(TaxService.roundToNickel(10.03)).toBe(10.05)
|
|
})
|
|
|
|
it('rounds .04 up to .05', () => {
|
|
expect(TaxService.roundToNickel(10.04)).toBe(10.05)
|
|
})
|
|
|
|
it('keeps .05 as is', () => {
|
|
expect(TaxService.roundToNickel(10.05)).toBe(10.05)
|
|
})
|
|
|
|
it('rounds .06 down to .05', () => {
|
|
expect(TaxService.roundToNickel(10.06)).toBe(10.05)
|
|
})
|
|
|
|
it('rounds .07 down to .05', () => {
|
|
expect(TaxService.roundToNickel(10.07)).toBe(10.05)
|
|
})
|
|
|
|
it('rounds .08 up to .10', () => {
|
|
expect(TaxService.roundToNickel(10.08)).toBe(10.10)
|
|
})
|
|
|
|
it('rounds .09 up to .10', () => {
|
|
expect(TaxService.roundToNickel(10.09)).toBe(10.10)
|
|
})
|
|
|
|
it('keeps .00 as is', () => {
|
|
expect(TaxService.roundToNickel(10.00)).toBe(10.00)
|
|
})
|
|
|
|
it('keeps .10 as is', () => {
|
|
expect(TaxService.roundToNickel(10.10)).toBe(10.10)
|
|
})
|
|
|
|
it('handles zero', () => {
|
|
expect(TaxService.roundToNickel(0)).toBe(0)
|
|
})
|
|
})
|
|
|
|
describe('TaxService.repairItemTypeToTaxCategory', () => {
|
|
it('maps labor to service', () => {
|
|
expect(TaxService.repairItemTypeToTaxCategory('labor')).toBe('service')
|
|
})
|
|
|
|
it('maps part to goods', () => {
|
|
expect(TaxService.repairItemTypeToTaxCategory('part')).toBe('goods')
|
|
})
|
|
|
|
it('maps flat_rate to goods', () => {
|
|
expect(TaxService.repairItemTypeToTaxCategory('flat_rate')).toBe('goods')
|
|
})
|
|
|
|
it('maps misc to goods', () => {
|
|
expect(TaxService.repairItemTypeToTaxCategory('misc')).toBe('goods')
|
|
})
|
|
|
|
it('maps unknown type to goods (default)', () => {
|
|
expect(TaxService.repairItemTypeToTaxCategory('something_else')).toBe('goods')
|
|
})
|
|
})
|