feat(settings): configurable default share-link expiry (owner, audited)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>feat/client-detail-redesign
parent
d28bca5cf0
commit
8861b46afd
@ -0,0 +1,69 @@
|
|||||||
|
// apps/hq/test/settings-sharing.test.ts
|
||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
import { openDb } from '../src/db'
|
||||||
|
import { createClient } from '../src/repos-clients'
|
||||||
|
import { createModule, setPrice } from '../src/repos-modules'
|
||||||
|
import { createDraft } from '../src/repos-documents'
|
||||||
|
import { mintShare } from '../src/repos-shares'
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
const db = openDb(':memory:')
|
||||||
|
db.prepare(`INSERT INTO setting (key, value) VALUES ('company.state_code','32')`).run()
|
||||||
|
db.prepare(`INSERT INTO tax_class (class_code, rate_pct_bp, effective_from) VALUES ('GST18', 1800, '2017-07-01')`).run()
|
||||||
|
const c = createClient(db, 'u1', { name: 'Acme', stateCode: '32' })
|
||||||
|
const m = createModule(db, 'u1', { code: 'POS', name: 'POS Billing' })
|
||||||
|
setPrice(db, 'u1', { moduleId: m.id, kind: 'yearly', pricePaise: 10_000_00, effectiveFrom: '2026-04-01' })
|
||||||
|
const doc = createDraft(db, 'u1', { docType: 'QUOTATION', clientId: c.id,
|
||||||
|
lines: [{ moduleId: m.id, qty: 1, kind: 'yearly' }] })
|
||||||
|
return { db, c, m, doc }
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('mintShare default expiry (share.default_expiry_days setting)', () => {
|
||||||
|
it('no setting row: defaults to +30d', () => {
|
||||||
|
const { db, doc } = setup()
|
||||||
|
const s = mintShare(db, 'u1', doc.id)
|
||||||
|
expect(s.expiresAt).not.toBeNull()
|
||||||
|
const days = (new Date(s.expiresAt!).getTime() - Date.now()) / 86_400_000
|
||||||
|
expect(days).toBeGreaterThan(29)
|
||||||
|
expect(days).toBeLessThan(31)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("setting '7': defaults to +7d", () => {
|
||||||
|
const { db, doc } = setup()
|
||||||
|
db.prepare(`INSERT INTO setting (key, value) VALUES ('share.default_expiry_days', '7')`).run()
|
||||||
|
const s = mintShare(db, 'u1', doc.id)
|
||||||
|
expect(s.expiresAt).not.toBeNull()
|
||||||
|
const days = (new Date(s.expiresAt!).getTime() - Date.now()) / 86_400_000
|
||||||
|
expect(days).toBeGreaterThan(6)
|
||||||
|
expect(days).toBeLessThan(8)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("setting 'never': expiresAt is null", () => {
|
||||||
|
const { db, doc } = setup()
|
||||||
|
db.prepare(`INSERT INTO setting (key, value) VALUES ('share.default_expiry_days', 'never')`).run()
|
||||||
|
const s = mintShare(db, 'u1', doc.id)
|
||||||
|
expect(s.expiresAt).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('explicit opts.expiresDays always wins over the setting (including explicit null)', () => {
|
||||||
|
const { db, doc } = setup()
|
||||||
|
db.prepare(`INSERT INTO setting (key, value) VALUES ('share.default_expiry_days', '7')`).run()
|
||||||
|
const s1 = mintShare(db, 'u1', doc.id, { expiresDays: 3 })
|
||||||
|
expect(s1.expiresAt).not.toBeNull()
|
||||||
|
const days1 = (new Date(s1.expiresAt!).getTime() - Date.now()) / 86_400_000
|
||||||
|
expect(days1).toBeGreaterThan(2)
|
||||||
|
expect(days1).toBeLessThan(4)
|
||||||
|
const s2 = mintShare(db, 'u1', doc.id, { expiresDays: null })
|
||||||
|
expect(s2.expiresAt).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("garbage setting 'abc': falls back to +30d", () => {
|
||||||
|
const { db, doc } = setup()
|
||||||
|
db.prepare(`INSERT INTO setting (key, value) VALUES ('share.default_expiry_days', 'abc')`).run()
|
||||||
|
const s = mintShare(db, 'u1', doc.id)
|
||||||
|
expect(s.expiresAt).not.toBeNull()
|
||||||
|
const days = (new Date(s.expiresAt!).getTime() - Date.now()) / 86_400_000
|
||||||
|
expect(days).toBeGreaterThan(29)
|
||||||
|
expect(days).toBeLessThan(31)
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Reference in New Issue