Entirely rework job service

This commit is contained in:
2025-07-04 16:08:18 +02:00
parent da2538ded5
commit a7db2bc89a

View File

@@ -1,99 +1,109 @@
import type { IndJobRecord, IndJobResponse, IndTransactionRecord, IndTransactionResponse, IndBillitemRecord, IndBillitemResponse } from '../lib/pbtypes';
import { IndJob } from '@/lib/types';
import type { IndJobRecord, IndTransactionRecord, IndBillitemRecord, IndJobRecordNoId } from '../lib/pbtypes';
import pb from '../lib/pocketbase';
export type { IndJobRecord as Job } from '../lib/pbtypes';
export type { IndTransactionRecord as Transaction } from '../lib/pbtypes';
export type { IndBillitemRecord as BillItem } from '../lib/pbtypes';
export async function createJob(job: Omit<IndJobRecord, 'id' | 'created' | 'updated'>): Promise<IndJobResponse> {
return await pb.collection('ind_job').create(job) as IndJobResponse;
export async function createJob(job: IndJobRecordNoId): Promise<IndJobRecord> {
return await pb.collection<IndJobRecord>('ind_job').create(job);
}
export async function getJobs(): Promise<IndJobResponse[]> {
const result = await pb.collection('ind_job').getFullList();
return result as IndJobResponse[];
export async function getJobs(): Promise<IndJobRecord[]> {
const result = await pb.collection<IndJobRecord>('ind_job').getFullList();
return result;
}
export async function getJobsFull(): Promise<IndJob[]> {
const jobs = await getJobs();
return await Promise.all(jobs.map(toFullJob));
}
export async function getJob(id: string): Promise<IndJobResponse | null> {
export async function getJob(id: string): Promise<IndJobRecord | null> {
try {
return await pb.collection('ind_job').getOne(id) as IndJobResponse;
return await pb.collection<IndJobRecord>('ind_job').getOne(id);
} catch (e) {
if (e.status === 404) return null;
throw e;
}
}
export async function getJobFull(id: string): Promise<IndJob | null> {
const job = await getJob(id);
if (!job) return null;
return await toFullJob(job);
}
export async function updateJob(id: string, updates: Partial<IndJobRecord>): Promise<IndJobResponse> {
return await pb.collection('ind_job').update(id, updates) as IndJobResponse;
export async function updateJob(id: string, updates: Partial<IndJobRecord>): Promise<IndJobRecord> {
return await pb.collection<IndJobRecord>('ind_job').update(id, updates);
}
export async function deleteJob(id: string): Promise<void> {
await pb.collection('ind_job').delete(id);
await pb.collection<IndJobRecord>('ind_job').delete(id);
}
export async function addTransaction(
jobId: string,
transaction: Omit<IndTransactionRecord, 'id' | 'created' | 'updated'>,
type: 'expenditure' | 'income'
): Promise<void> {
// Create the transaction
const createdTransaction = await pb.collection('ind_transaction').create({
...transaction,
job: jobId
}) as IndTransactionResponse;
async function toFullJob(job: IndJobRecord): Promise<IndJob> {
const fullJob = {
...job,
expenditures: [],
income: [],
billOfMaterials: [],
consumedMaterials: []
};
// Update the job to include the new transaction
const job = await getJob(jobId);
if (!job) throw new Error('Job not found');
if (job.expenditures) {
for (const txId of job.expenditures) {
try {
const tx = await pb.collection('ind_transaction').getOne(txId);
fullJob.expenditures.push(tx as IndTransactionRecord);
} catch (e) {
console.warn('Failed to fetch expenditure transaction:', txId);
}
}
}
const field = type === 'expenditure' ? 'expenditures' : 'income';
const currentIds = job[field] || [];
if (job.income) {
for (const txId of job.income) {
try {
const tx = await pb.collection('ind_transaction').getOne(txId);
fullJob.income.push(tx as IndTransactionRecord);
} catch (e) {
console.warn('Failed to fetch income transaction:', txId);
}
}
}
await updateJob(jobId, {
[field]: [...currentIds, createdTransaction.id]
});
if (job.billOfMaterials) {
for (const itemId of job.billOfMaterials) {
try {
const item = await pb.collection('ind_billItem').getOne(itemId);
fullJob.billOfMaterials.push(item as IndBillitemRecord);
} catch (e) {
console.warn('Failed to fetch bill item:', itemId);
}
}
}
if (job.consumedMaterials) {
for (const itemId of job.consumedMaterials) {
try {
const item = await pb.collection('ind_billItem').getOne(itemId);
fullJob.consumedMaterials.push(item as IndBillitemRecord);
} catch (e) {
console.warn('Failed to fetch consumed material:', itemId);
}
}
}
return fullJob;
}
export async function updateTransaction(
jobId: string,
transactionId: string,
updates: Partial<IndTransactionRecord>
): Promise<void> {
await pb.collection('ind_transaction').update(transactionId, updates);
}
export async function deleteTransaction(jobId: string, transactionId: string): Promise<void> {
// Delete the transaction
await pb.collection('ind_transaction').delete(transactionId);
// Update the job to remove the transaction reference
const job = await getJob(jobId);
if (!job) return;
// Remove from both expenditures and income arrays
const expenditures = (job.expenditures || []).filter(id => id !== transactionId);
const income = (job.income || []).filter(id => id !== transactionId);
await updateJob(jobId, {
expenditures,
income
});
}
export async function addBillItem(
jobId: string,
billItem: Omit<IndBillitemRecord, 'id' | 'created' | 'updated'>
): Promise<void> {
// Create the bill item
const createdItem = await pb.collection('ind_billItem').create(billItem) as IndBillitemResponse;
// Update the job to include the new bill item
const job = await getJob(jobId);
if (!job) throw new Error('Job not found');
const currentBillItems = job.billOfMaterials || [];
await updateJob(jobId, {
billOfMaterials: [...currentBillItems, createdItem.id]
});
async function toHollowJob(job: IndJob): Promise<IndJobRecord> {
return {
...job,
expenditures: job.expenditures.map(tx => tx.id),
income: job.income.map(tx => tx.id),
billOfMaterials: job.billOfMaterials.map(item => item.id),
consumedMaterials: job.consumedMaterials.map(item => item.id)
};
}