Fix creating bill items

This commit is contained in:
2025-07-04 16:44:06 +02:00
parent 6f60993621
commit 63f3db6197
4 changed files with 39 additions and 40 deletions

View File

@@ -6,7 +6,7 @@ import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { IndBillitemRecordNoId, IndJobStatusOptions, IndJobRecordNoId, IndFacilityRecord } from '@/lib/pbtypes'; import { IndBillitemRecordNoId, IndJobStatusOptions, IndJobRecordNoId, IndFacilityRecord, IndBillitemRecord } from '@/lib/pbtypes';
import MaterialsImportExport from './MaterialsImportExport'; import MaterialsImportExport from './MaterialsImportExport';
import { IndJob } from '@/lib/types'; import { IndJob } from '@/lib/types';
// import { getFacilities } from '@/services/facilityService'; // import { getFacilities } from '@/services/facilityService';
@@ -19,8 +19,8 @@ interface JobFormProps {
const JobForm: React.FC<JobFormProps> = ({ job, onSubmit, onCancel }) => { const JobForm: React.FC<JobFormProps> = ({ job, onSubmit, onCancel }) => {
// const [facilities, setFacilities] = useState<IndFacilityRecord[]>([]); // const [facilities, setFacilities] = useState<IndFacilityRecord[]>([]);
const [billOfMaterials, setBillOfMaterials] = useState<IndBillitemRecordNoId[]>(job?.billOfMaterials || []); const [billOfMaterials, setBillOfMaterials] = useState<IndBillitemRecord[]>(job?.billOfMaterials || []);
const [consumedMaterials, setConsumedMaterials] = useState<IndBillitemRecordNoId[]>(job?.consumedMaterials || []); const [consumedMaterials, setConsumedMaterials] = useState<IndBillitemRecord[]>(job?.consumedMaterials || []);
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
outputItem: job?.outputItem || '', outputItem: job?.outputItem || '',
outputQuantity: job?.outputQuantity || 0, outputQuantity: job?.outputQuantity || 0,
@@ -209,7 +209,7 @@ const JobForm: React.FC<JobFormProps> = ({ job, onSubmit, onCancel }) => {
<TabsContent value="materials" className="space-y-4"> <TabsContent value="materials" className="space-y-4">
<MaterialsImportExport <MaterialsImportExport
jobId={job?.id || ''} job={job}
billOfMaterials={billOfMaterials} billOfMaterials={billOfMaterials}
consumedMaterials={consumedMaterials} consumedMaterials={consumedMaterials}
onBillOfMaterialsUpdate={setBillOfMaterials} onBillOfMaterialsUpdate={setBillOfMaterials}

View File

@@ -4,19 +4,21 @@ import { Button } from '@/components/ui/button';
import { Textarea } from '@/components/ui/textarea'; import { Textarea } from '@/components/ui/textarea';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import { Import, Download, FileText } from 'lucide-react'; import { Import, Download, FileText } from 'lucide-react';
import { IndBillitemRecordNoId } from '@/lib/pbtypes'; import { IndBillitemRecord } from '@/lib/pbtypes';
import { IndJob } from '@/lib/types';
import { addBillItem } from '@/services/billItemService'; import { addBillItem } from '@/services/billItemService';
import { updateJob } from '@/services/jobService';
interface MaterialsImportExportProps { interface MaterialsImportExportProps {
jobId: string; job: IndJob;
billOfMaterials: IndBillitemRecordNoId[]; billOfMaterials: IndBillitemRecord[];
consumedMaterials: IndBillitemRecordNoId[]; consumedMaterials: IndBillitemRecord[];
onBillOfMaterialsUpdate: (materials: IndBillitemRecordNoId[]) => void; onBillOfMaterialsUpdate: (billItems: IndBillitemRecord[]) => void;
onConsumedMaterialsUpdate: (materials: IndBillitemRecordNoId[]) => void; onConsumedMaterialsUpdate: (billItems: IndBillitemRecord[]) => void;
} }
const MaterialsImportExport: React.FC<MaterialsImportExportProps> = ({ const MaterialsImportExport: React.FC<MaterialsImportExportProps> = ({
jobId, job,
billOfMaterials, billOfMaterials,
consumedMaterials, consumedMaterials,
onBillOfMaterialsUpdate, onBillOfMaterialsUpdate,
@@ -25,9 +27,9 @@ const MaterialsImportExport: React.FC<MaterialsImportExportProps> = ({
const [bomInput, setBomInput] = useState(''); const [bomInput, setBomInput] = useState('');
const [consumedInput, setConsumedInput] = useState(''); const [consumedInput, setConsumedInput] = useState('');
const parseBillOfMaterials = (text: string): IndBillitemRecordNoId[] => { const parseBillOfMaterials = async (text: string): Promise<IndJob> => {
const lines = text.split('\n').filter(line => line.trim()); const lines = text.split('\n').filter(line => line.trim());
const materials: IndBillitemRecordNoId[] = []; const materials: IndBillitemRecord[] = [];
for (const line of lines) { for (const line of lines) {
const parts = line.trim().split(/\s+/); const parts = line.trim().split(/\s+/);
@@ -35,16 +37,20 @@ const MaterialsImportExport: React.FC<MaterialsImportExportProps> = ({
const name = parts.slice(0, -1).join(' '); const name = parts.slice(0, -1).join(' ');
const quantity = parseInt(parts[parts.length - 1]); const quantity = parseInt(parts[parts.length - 1]);
if (name && !isNaN(quantity)) { if (name && !isNaN(quantity)) {
materials.push({ name, quantity }); const newBillItem = await addBillItem(job.id, { name, quantity });
materials.push(newBillItem);
} }
} }
} }
return materials;
job.billOfMaterials = materials;
await updateJob(job.id, { billOfMaterials: materials.map(item => item.id) });
return job;
}; };
const parseConsumedMaterials = (text: string): IndBillitemRecordNoId[] => { const parseConsumedMaterials = async (text: string): Promise<IndJob> => {
const lines = text.split('\n').filter(line => line.trim()); const lines = text.split('\n').filter(line => line.trim());
const materials: IndBillitemRecordNoId[] = []; const materials: IndBillitemRecord[] = [];
for (const line of lines) { for (const line of lines) {
const parts = line.trim().split('\t'); const parts = line.trim().split('\t');
@@ -52,11 +58,15 @@ const MaterialsImportExport: React.FC<MaterialsImportExportProps> = ({
const name = parts[0]; const name = parts[0];
const quantity = parseInt(parts[1]); const quantity = parseInt(parts[1]);
if (name && !isNaN(quantity)) { if (name && !isNaN(quantity)) {
materials.push({ name, quantity }); const newBillItem = await addBillItem(job.id, { name, quantity });
materials.push(newBillItem);
} }
} }
} }
return materials;
job.consumedMaterials = materials;
await updateJob(job.id, { consumedMaterials: materials.map(item => item.id) });
return job;
}; };
const exportBillOfMaterials = (): string => { const exportBillOfMaterials = (): string => {
@@ -69,13 +79,13 @@ const MaterialsImportExport: React.FC<MaterialsImportExportProps> = ({
const handleImportBom = async () => { const handleImportBom = async () => {
const parsed = await parseBillOfMaterials(bomInput); const parsed = await parseBillOfMaterials(bomInput);
onBillOfMaterialsUpdate(parsed); onBillOfMaterialsUpdate(parsed.billOfMaterials);
setBomInput(''); setBomInput('');
}; };
const handleImportConsumed = async () => { const handleImportConsumed = async () => {
const parsed = await parseConsumedMaterials(consumedInput); const parsed = await parseConsumedMaterials(consumedInput);
onConsumedMaterialsUpdate(parsed); onConsumedMaterialsUpdate(parsed.consumedMaterials);
setConsumedInput(''); setConsumedInput('');
}; };

View File

@@ -2,10 +2,9 @@ import { useState, useEffect } from 'react';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Plus, Factory, TrendingUp, Briefcase } from 'lucide-react'; import { Plus, Factory, TrendingUp, Briefcase } from 'lucide-react';
import { IndTransactionResponse, IndJobRecord, IndTransactionRecord, IndTransactionRecordNoId } from '@/lib/pbtypes'; import { IndTransactionRecordNoId, IndJobRecordNoId, IndTransactionRecord } from '@/lib/pbtypes';
import * as jobService from '@/services/jobService'; import * as jobService from '@/services/jobService';
import * as transactionService from '@/services/transactionService'; import * as transactionService from '@/services/transactionService';
import * as billItemService from '@/services/billItemService';
import { formatISK } from '@/utils/priceUtils'; import { formatISK } from '@/utils/priceUtils';
import JobCard from '@/components/JobCard'; import JobCard from '@/components/JobCard';
import JobForm from '@/components/JobForm'; import JobForm from '@/components/JobForm';
@@ -14,6 +13,7 @@ import TransactionTable from '@/components/TransactionTable';
import { IndJob } from '@/lib/types'; import { IndJob } from '@/lib/types';
import { createJob } from '@/services/jobService'; import { createJob } from '@/services/jobService';
// TODO: Bill of materials just does not work currently Fix this shit
// Extended job type for UI components // Extended job type for UI components
const Index = () => { const Index = () => {
const [jobs, setJobs] = useState<IndJob[]>([]); const [jobs, setJobs] = useState<IndJob[]>([]);
@@ -36,7 +36,7 @@ const Index = () => {
} }
}; };
const handleCreateJob = async (jobData: Omit<IndJobRecord, 'id' | 'created' | 'updated'>) => { const handleCreateJob = async (jobData: IndJobRecordNoId) => {
try { try {
const newJob = await createJob(jobData); const newJob = await createJob(jobData);
const jobWithRelations: IndJob = { const jobWithRelations: IndJob = {
@@ -58,7 +58,7 @@ const Index = () => {
setShowJobForm(true); setShowJobForm(true);
}; };
const handleUpdateJob = async (jobData: Omit<IndJobRecord, 'id' | 'created' | 'updated'>) => { const handleUpdateJob = async (jobData: IndJobRecordNoId) => {
if (!editingJob) return; if (!editingJob) return;
try { try {
@@ -114,7 +114,7 @@ const Index = () => {
} }
}; };
const handleUpdateTransaction = async (transactionId: string, updates: Partial<IndTransactionResponse>) => { const handleUpdateTransaction = async (transactionId: string, updates: Partial<IndTransactionRecord>) => {
if (!selectedJob) return; if (!selectedJob) return;
try { try {

View File

@@ -1,21 +1,10 @@
import { IndBillitemRecord, IndBillitemRecordNoId } from "@/lib/pbtypes"; import { IndBillitemRecord, IndBillitemRecordNoId } from "@/lib/pbtypes";
import { IndJob } from "@/lib/types";
import pb from "@/lib/pocketbase"; import pb from "@/lib/pocketbase";
import { updateJob } from "./jobService";
export async function addBillItem( export async function addBillItem(
job: IndJob, jobId: string,
billItem: IndBillitemRecordNoId, billItem: IndBillitemRecordNoId
type: 'billOfMaterials' | 'consumedMaterials'
): Promise<IndBillitemRecord> { ): Promise<IndBillitemRecord> {
console.log('Adding bill item:', billItem); console.log('Adding bill item:', billItem);
// Create the bill item return await pb.collection<IndBillitemRecord>('ind_billItem').create(billItem);
const createdItem = await pb.collection<IndBillitemRecord>('ind_billItem').create(billItem);
const currentBillItems = job[type] || [];
await updateJob(job.id, {
[type]: [...currentBillItems, createdItem.id]
});
return createdItem;
} }