165 lines
4.4 KiB
TypeScript
165 lines
4.4 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { ref } from 'vue'
|
|
import { invoke } from '@tauri-apps/api/core'
|
|
import { handleInvokeError } from '../utils/errorHandler'
|
|
|
|
export interface Invoice {
|
|
id?: number
|
|
client_id: number
|
|
invoice_number: string
|
|
date: string
|
|
due_date?: string
|
|
subtotal: number
|
|
tax_rate: number
|
|
tax_amount: number
|
|
discount: number
|
|
total: number
|
|
notes?: string
|
|
status: string
|
|
template_id?: string
|
|
}
|
|
|
|
export interface InvoiceItem {
|
|
id?: number
|
|
invoice_id: number
|
|
description: string
|
|
quantity: number
|
|
rate: number
|
|
amount: number
|
|
time_entry_id?: number
|
|
}
|
|
|
|
export const useInvoicesStore = defineStore('invoices', () => {
|
|
const invoices = ref<Invoice[]>([])
|
|
const loading = ref(false)
|
|
|
|
async function fetchInvoices() {
|
|
loading.value = true
|
|
try {
|
|
invoices.value = await invoke<Invoice[]>('get_invoices')
|
|
} catch (error) {
|
|
handleInvokeError(error, 'Failed to fetch invoices', () => fetchInvoices())
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function createInvoice(invoice: Invoice): Promise<number | null> {
|
|
try {
|
|
const id = await invoke<number>('create_invoice', { invoice })
|
|
invoices.value.unshift({ ...invoice, id: Number(id) })
|
|
return Number(id)
|
|
} catch (error) {
|
|
handleInvokeError(error, 'Failed to create invoice')
|
|
return null
|
|
}
|
|
}
|
|
|
|
async function updateInvoice(invoice: Invoice): Promise<boolean> {
|
|
try {
|
|
await invoke('update_invoice', { invoice })
|
|
const index = invoices.value.findIndex(i => i.id === invoice.id)
|
|
if (index !== -1) {
|
|
invoices.value[index] = invoice
|
|
}
|
|
return true
|
|
} catch (error) {
|
|
handleInvokeError(error, 'Failed to update invoice')
|
|
return false
|
|
}
|
|
}
|
|
|
|
async function updateInvoiceTemplate(id: number, templateId: string): Promise<boolean> {
|
|
try {
|
|
await invoke('update_invoice_template', { id, templateId })
|
|
const index = invoices.value.findIndex(i => i.id === id)
|
|
if (index !== -1) {
|
|
invoices.value[index].template_id = templateId
|
|
}
|
|
return true
|
|
} catch (error) {
|
|
handleInvokeError(error, 'Failed to update invoice template')
|
|
return false
|
|
}
|
|
}
|
|
|
|
async function deleteInvoice(id: number): Promise<boolean> {
|
|
try {
|
|
await invoke('delete_invoice', { id })
|
|
invoices.value = invoices.value.filter(i => i.id !== id)
|
|
return true
|
|
} catch (error) {
|
|
handleInvokeError(error, 'Failed to delete invoice')
|
|
return false
|
|
}
|
|
}
|
|
|
|
async function getInvoiceItems(invoiceId: number): Promise<InvoiceItem[]> {
|
|
try {
|
|
return await invoke<InvoiceItem[]>('get_invoice_items', { invoiceId })
|
|
} catch (error) {
|
|
handleInvokeError(error, 'Failed to fetch invoice items')
|
|
return []
|
|
}
|
|
}
|
|
|
|
async function createInvoiceItem(item: InvoiceItem): Promise<number | null> {
|
|
try {
|
|
return await invoke<number>('create_invoice_item', { item })
|
|
} catch (error) {
|
|
handleInvokeError(error, 'Failed to create invoice item')
|
|
return null
|
|
}
|
|
}
|
|
|
|
async function saveInvoiceItems(invoiceId: number, items: { description: string; quantity: number; unit_price: number }[]): Promise<void> {
|
|
for (const item of items) {
|
|
await createInvoiceItem({
|
|
invoice_id: invoiceId,
|
|
description: item.description,
|
|
quantity: item.quantity,
|
|
rate: item.unit_price,
|
|
amount: item.quantity * item.unit_price,
|
|
})
|
|
}
|
|
}
|
|
|
|
async function updateStatus(id: number, status: string): Promise<boolean> {
|
|
try {
|
|
await invoke('update_invoice_status', { id, status })
|
|
const idx = invoices.value.findIndex(i => i.id === id)
|
|
if (idx !== -1) invoices.value[idx].status = status
|
|
return true
|
|
} catch (error) {
|
|
handleInvokeError(error, 'Failed to update invoice status')
|
|
return false
|
|
}
|
|
}
|
|
|
|
async function checkOverdue(): Promise<number> {
|
|
try {
|
|
const today = new Date().toISOString().split('T')[0]
|
|
const count = await invoke<number>('check_overdue_invoices', { today })
|
|
if (count > 0) await fetchInvoices()
|
|
return count
|
|
} catch {
|
|
return 0
|
|
}
|
|
}
|
|
|
|
return {
|
|
invoices,
|
|
loading,
|
|
fetchInvoices,
|
|
createInvoice,
|
|
updateInvoice,
|
|
updateInvoiceTemplate,
|
|
deleteInvoice,
|
|
getInvoiceItems,
|
|
createInvoiceItem,
|
|
saveInvoiceItems,
|
|
updateStatus,
|
|
checkOverdue
|
|
}
|
|
})
|