fix: customer history query, seed transactions tied to accounts
- Fix customerHistoryOptions closure bug (historySearch was inaccessible) - Pass itemSearch as parameter instead of capturing from outer scope - Seed 5 completed transactions tied to accounts (Smith, Johnson, Garcia, Chen) - Seed admin user with employee number 1001 and PIN 1234 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -46,15 +46,15 @@ function accountSearchOptions(search: string) {
|
||||
})
|
||||
}
|
||||
|
||||
function customerHistoryOptions(accountId: string | null) {
|
||||
function customerHistoryOptions(accountId: string | null, itemSearch?: string) {
|
||||
return queryOptions({
|
||||
queryKey: ['pos', 'customer-history', accountId],
|
||||
queryKey: ['pos', 'customer-history', accountId, itemSearch ?? ''],
|
||||
queryFn: () => api.get<{ data: Transaction[] }>('/v1/transactions', {
|
||||
accountId,
|
||||
limit: 10,
|
||||
sort: 'created_at',
|
||||
order: 'desc',
|
||||
...(historySearch ? { itemSearch: historySearch } : {}),
|
||||
...(itemSearch ? { itemSearch } : {}),
|
||||
}),
|
||||
enabled: !!accountId,
|
||||
})
|
||||
@@ -74,7 +74,7 @@ export function POSCustomerDialog({ open, onOpenChange }: POSCustomerDialogProps
|
||||
const { data: searchData, isLoading } = useQuery(accountSearchOptions(search))
|
||||
const accounts = searchData?.data ?? []
|
||||
|
||||
const { data: historyData } = useQuery(customerHistoryOptions(showHistory ? accountId : null))
|
||||
const { data: historyData } = useQuery(customerHistoryOptions(showHistory ? accountId : null, historySearch || undefined))
|
||||
const history = historyData?.data ?? []
|
||||
|
||||
function handleSelect(account: Account) {
|
||||
|
||||
@@ -44,7 +44,8 @@ async function seed() {
|
||||
if (!adminUser) {
|
||||
const bcrypt = await import('bcryptjs')
|
||||
const hashedPw = await bcrypt.hash(adminPassword, 10)
|
||||
const [user] = await sql`INSERT INTO "user" (email, password_hash, first_name, last_name, role) VALUES ('admin@lunarfront.dev', ${hashedPw}, 'Admin', 'User', 'admin') RETURNING id`
|
||||
const pinHash = await bcrypt.hash('1234', 10)
|
||||
const [user] = await sql`INSERT INTO "user" (email, password_hash, first_name, last_name, role, employee_number, pin_hash) VALUES ('admin@lunarfront.dev', ${hashedPw}, 'Admin', 'User', 'admin', '1001', ${pinHash}) RETURNING id`
|
||||
const [adminRole] = await sql`SELECT id FROM role WHERE slug = 'admin' LIMIT 1`
|
||||
if (adminRole) {
|
||||
await sql`INSERT INTO user_role_assignment (user_id, role_id) VALUES (${user.id}, ${adminRole.id}) ON CONFLICT DO NOTHING`
|
||||
@@ -171,6 +172,64 @@ async function seed() {
|
||||
console.log(` Batch: Lincoln High School — 5 items`)
|
||||
}
|
||||
|
||||
// --- Sample POS Transactions tied to accounts ---
|
||||
const [adminUsr] = await sql`SELECT id FROM "user" WHERE email = 'admin@lunarfront.dev'`
|
||||
const [mainLoc] = await sql`SELECT id FROM location WHERE name = 'Main Store'`
|
||||
if (adminUsr && mainLoc) {
|
||||
const existingTxns = await sql`SELECT id FROM transaction WHERE account_id IS NOT NULL LIMIT 1`
|
||||
if (existingTxns.length === 0) {
|
||||
const salesData = [
|
||||
{ account: 'Smith Family', items: [
|
||||
{ desc: 'Violin Strings — Dominant 4/4 Set', qty: 1, price: '59.99', tax: '4.95' },
|
||||
{ desc: 'Rosin — Pirastro Goldflex', qty: 1, price: '12.00', tax: '0.99' },
|
||||
]},
|
||||
{ account: 'Smith Family', items: [
|
||||
{ desc: 'Shoulder Rest — Kun Original 4/4', qty: 1, price: '35.00', tax: '2.89' },
|
||||
]},
|
||||
{ account: 'Johnson Family', items: [
|
||||
{ desc: 'Cello Strings — Jargar Superior Set', qty: 1, price: '89.99', tax: '7.42' },
|
||||
{ desc: 'Bow Grip — Leather Cello/Bass', qty: 2, price: '6.00', tax: '0.99' },
|
||||
]},
|
||||
{ account: 'Garcia Workshop', items: [
|
||||
{ desc: 'Bridge — Violin 4/4 Blank', qty: 3, price: '18.00', tax: '4.46' },
|
||||
{ desc: 'Bow Hair — Mongolian White (hank)', qty: 2, price: '18.00', tax: '2.97' },
|
||||
{ desc: 'Bow Tip Plate — Violin Ivory-Style', qty: 5, price: '7.00', tax: '2.89' },
|
||||
]},
|
||||
{ account: 'Emily Chen', items: [
|
||||
{ desc: 'Violin Strings — Dominant 4/4 Set', qty: 1, price: '59.99', tax: '4.95' },
|
||||
{ desc: 'Chin Rest — Guarneri Ebony 4/4', qty: 1, price: '28.00', tax: '2.31' },
|
||||
]},
|
||||
]
|
||||
|
||||
for (const sale of salesData) {
|
||||
const acctId = acctIds[sale.account]
|
||||
if (!acctId) continue
|
||||
const subtotal = sale.items.reduce((s, i) => s + parseFloat(i.price) * i.qty, 0)
|
||||
const taxTotal = sale.items.reduce((s, i) => s + parseFloat(i.tax), 0)
|
||||
const total = Math.round((subtotal + taxTotal) * 100) / 100
|
||||
const txnNum = `TXN-SEED-${String(Math.floor(1000 + Math.random() * 9000))}`
|
||||
|
||||
const [txn] = await sql`INSERT INTO transaction (
|
||||
transaction_number, transaction_type, status, location_id, account_id, processed_by,
|
||||
subtotal, discount_total, tax_total, total, payment_method, completed_at
|
||||
) VALUES (
|
||||
${txnNum}, 'sale', 'completed', ${mainLoc.id}, ${acctId}, ${adminUsr.id},
|
||||
${subtotal.toFixed(2)}, '0.00', ${taxTotal.toFixed(2)}, ${total.toFixed(2)}, 'card_present', NOW()
|
||||
) RETURNING id`
|
||||
|
||||
for (const item of sale.items) {
|
||||
const lineTotal = Math.round((parseFloat(item.price) * item.qty + parseFloat(item.tax)) * 100) / 100
|
||||
await sql`INSERT INTO transaction_line_item (
|
||||
transaction_id, description, qty, unit_price, tax_rate, tax_amount, line_total
|
||||
) VALUES (
|
||||
${txn.id}, ${item.desc}, ${item.qty}, ${item.price}, '0.0825', ${item.tax}, ${lineTotal.toFixed(2)}
|
||||
)`
|
||||
}
|
||||
console.log(` Transaction: ${txnNum} — ${sale.account} — $${total.toFixed(2)}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\nDev seed complete!')
|
||||
await sql.end()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user