Fix importing the bill of materials
This commit is contained in:
		@@ -95,23 +95,34 @@ const JobCard: React.FC<JobCardProps> = ({
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const importBillOfMaterials = async () => {
 | 
					  const importBillOfMaterials = async () => {
 | 
				
			||||||
 | 
					    if (!onImportBOM) {
 | 
				
			||||||
 | 
					      toast({
 | 
				
			||||||
 | 
					        title: "Error",
 | 
				
			||||||
 | 
					        description: "Import functionality is not available",
 | 
				
			||||||
 | 
					        variant: "destructive",
 | 
				
			||||||
 | 
					        duration: 2000,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const clipboardText = await navigator.clipboard.readText();
 | 
					      const clipboardText = await navigator.clipboard.readText();
 | 
				
			||||||
      const lines = clipboardText.split('\n').filter(line => line.trim());
 | 
					      const lines = clipboardText.split('\n').filter(line => line.trim());
 | 
				
			||||||
      const items: { name: string; quantity: number }[] = [];
 | 
					      const items: { name: string; quantity: number }[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      for (const line of lines) {
 | 
					      for (const line of lines) {
 | 
				
			||||||
        const parts = line.trim().split(/\s+/);
 | 
					        const parts = line.trim().split(/[\s\t]+/);
 | 
				
			||||||
        if (parts.length >= 2) {
 | 
					        if (parts.length >= 2) {
 | 
				
			||||||
          const name = parts.slice(0, -1).join(' ');
 | 
					          const name = parts.slice(0, -1).join(' ');
 | 
				
			||||||
          const quantity = parseInt(parts[parts.length - 1]);
 | 
					          const quantityPart = parts[parts.length - 1].replace(/,/g, '');
 | 
				
			||||||
 | 
					          const quantity = parseInt(quantityPart);
 | 
				
			||||||
          if (name && !isNaN(quantity)) {
 | 
					          if (name && !isNaN(quantity)) {
 | 
				
			||||||
            items.push({ name, quantity });
 | 
					            items.push({ name, quantity });
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (items.length > 0 && onImportBOM) {
 | 
					      if (items.length > 0) {
 | 
				
			||||||
        onImportBOM(job.id, items);
 | 
					        onImportBOM(job.id, items);
 | 
				
			||||||
        toast({
 | 
					        toast({
 | 
				
			||||||
          title: "BOM Imported",
 | 
					          title: "BOM Imported",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,3 @@
 | 
				
			|||||||
 | 
					 | 
				
			||||||
import React, { useState } from 'react';
 | 
					import React, { useState } from 'react';
 | 
				
			||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
 | 
					import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
 | 
				
			||||||
import { Button } from '@/components/ui/button';
 | 
					import { Button } from '@/components/ui/button';
 | 
				
			||||||
@@ -17,8 +16,21 @@ interface JobFormProps {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const formatDateForInput = (dateString: string | undefined | null): string => {
 | 
					const formatDateForInput = (dateString: string | undefined | null): string => {
 | 
				
			||||||
  if (!dateString) return '';
 | 
					  if (!dateString) return '';
 | 
				
			||||||
  // Convert ISO string to datetime-local format (YYYY-MM-DDTHH:MM)
 | 
					  
 | 
				
			||||||
  return new Date(dateString).toISOString().slice(0, 16);
 | 
					  // Create a date object in local timezone
 | 
				
			||||||
 | 
					  const date = new Date(dateString);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Format to YYYY-MM-DD
 | 
				
			||||||
 | 
					  const year = date.getFullYear();
 | 
				
			||||||
 | 
					  const month = String(date.getMonth() + 1).padStart(2, '0');
 | 
				
			||||||
 | 
					  const day = String(date.getDate()).padStart(2, '0');
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Format to HH:MM
 | 
				
			||||||
 | 
					  const hours = String(date.getHours()).padStart(2, '0');
 | 
				
			||||||
 | 
					  const minutes = String(date.getMinutes()).padStart(2, '0');
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Combine into format required by datetime-local (YYYY-MM-DDTHH:MM)
 | 
				
			||||||
 | 
					  return `${year}-${month}-${day}T${hours}:${minutes}`;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const JobForm: React.FC<JobFormProps> = ({ job, onSubmit, onCancel }) => {
 | 
					const JobForm: React.FC<JobFormProps> = ({ job, onSubmit, onCancel }) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,3 @@
 | 
				
			|||||||
 | 
					 | 
				
			||||||
import { useParams, useNavigate } from 'react-router-dom';
 | 
					import { useParams, useNavigate } from 'react-router-dom';
 | 
				
			||||||
import { Button } from '@/components/ui/button';
 | 
					import { Button } from '@/components/ui/button';
 | 
				
			||||||
import JobCard from '@/components/JobCard';
 | 
					import JobCard from '@/components/JobCard';
 | 
				
			||||||
@@ -21,7 +20,8 @@ const JobDetails = () => {
 | 
				
			|||||||
    updateTransaction,
 | 
					    updateTransaction,
 | 
				
			||||||
    deleteTransaction,
 | 
					    deleteTransaction,
 | 
				
			||||||
    updateJob,
 | 
					    updateJob,
 | 
				
			||||||
    deleteJob
 | 
					    deleteJob,
 | 
				
			||||||
 | 
					    createMultipleBillItems
 | 
				
			||||||
  } = useJobs();
 | 
					  } = useJobs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const job = useJob(jobId || null);
 | 
					  const job = useJob(jobId || null);
 | 
				
			||||||
@@ -99,6 +99,19 @@ const JobDetails = () => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleImportBOM = async (jobId: string, items: { name: string; quantity: number }[]) => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const billItems = items.map(item => ({
 | 
				
			||||||
 | 
					        name: item.name,
 | 
				
			||||||
 | 
					        quantity: item.quantity,
 | 
				
			||||||
 | 
					        unitPrice: 0
 | 
				
			||||||
 | 
					      }));
 | 
				
			||||||
 | 
					      await createMultipleBillItems(jobId, billItems, 'billOfMaterials');
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      console.error('Error importing BOM:', error);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (showJobForm) {
 | 
					  if (showJobForm) {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className="min-h-screen bg-gray-950 p-6">
 | 
					      <div className="min-h-screen bg-gray-950 p-6">
 | 
				
			||||||
@@ -139,6 +152,7 @@ const JobDetails = () => {
 | 
				
			|||||||
            onEdit={handleEditJob}
 | 
					            onEdit={handleEditJob}
 | 
				
			||||||
            onDelete={handleDeleteJob}
 | 
					            onDelete={handleDeleteJob}
 | 
				
			||||||
            onUpdateProduced={handleUpdateProduced}
 | 
					            onUpdateProduced={handleUpdateProduced}
 | 
				
			||||||
 | 
					            onImportBOM={handleImportBOM}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
          <TransactionForm
 | 
					          <TransactionForm
 | 
				
			||||||
            jobId={job.id}
 | 
					            jobId={job.id}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,5 +6,21 @@ export async function addBillItem(
 | 
				
			|||||||
	billItem: IndBillitemRecordNoId
 | 
						billItem: IndBillitemRecordNoId
 | 
				
			||||||
): Promise<IndBillitemRecord> {
 | 
					): Promise<IndBillitemRecord> {
 | 
				
			||||||
	console.log('Adding bill item:', billItem);
 | 
						console.log('Adding bill item:', billItem);
 | 
				
			||||||
	return await pb.collection<IndBillitemRecord>('ind_billItem').create(billItem);
 | 
						// Set the job ID in the bill item record
 | 
				
			||||||
 | 
						const billItemWithJob = {
 | 
				
			||||||
 | 
							...billItem,
 | 
				
			||||||
 | 
							job: jobId
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						return await pb.collection<IndBillitemRecord>('ind_billItem').create(billItemWithJob);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function deleteBillItem(id: string): Promise<void> {
 | 
				
			||||||
 | 
						console.log('Deleting bill item:', id);
 | 
				
			||||||
 | 
						await pb.collection('ind_billItem').delete(id);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function deleteBillItems(ids: string[]): Promise<void> {
 | 
				
			||||||
 | 
						console.log('Deleting bill items:', ids);
 | 
				
			||||||
 | 
						// Delete items in parallel for better performance
 | 
				
			||||||
 | 
						await Promise.all(ids.map(id => deleteBillItem(id)));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,3 @@
 | 
				
			|||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { IndJob } from '@/lib/types';
 | 
					import { IndJob } from '@/lib/types';
 | 
				
			||||||
import { IndJobRecord, IndJobRecordNoId, IndTransactionRecord, IndTransactionRecordNoId, IndBillitemRecord, IndBillitemRecordNoId } from '@/lib/pbtypes';
 | 
					import { IndJobRecord, IndJobRecordNoId, IndTransactionRecord, IndTransactionRecordNoId, IndBillitemRecord, IndBillitemRecordNoId } from '@/lib/pbtypes';
 | 
				
			||||||
import * as jobService from './jobService';
 | 
					import * as jobService from './jobService';
 | 
				
			||||||
@@ -219,6 +217,12 @@ export class DataService {
 | 
				
			|||||||
    const job = this.getJob(jobId);
 | 
					    const job = this.getJob(jobId);
 | 
				
			||||||
    if (!job) throw new Error(`Job with id ${jobId} not found`);
 | 
					    if (!job) throw new Error(`Job with id ${jobId} not found`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Delete existing bill items
 | 
				
			||||||
 | 
					    const existingItemIds = job[type].map(item => item.id);
 | 
				
			||||||
 | 
					    if (existingItemIds.length > 0) {
 | 
				
			||||||
 | 
					      await billItemService.deleteBillItems(existingItemIds);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const createdBillItems: IndBillitemRecord[] = [];
 | 
					    const createdBillItems: IndBillitemRecord[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Create all bill items
 | 
					    // Create all bill items
 | 
				
			||||||
@@ -227,17 +231,16 @@ export class DataService {
 | 
				
			|||||||
      createdBillItems.push(createdBillItem);
 | 
					      createdBillItems.push(createdBillItem);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Update the job's bill item references in one database call
 | 
					    // Update the job's bill item references with ONLY the new IDs
 | 
				
			||||||
    const currentIds = (job[type] || []).map(item => item.id);
 | 
					 | 
				
			||||||
    const newIds = createdBillItems.map(item => item.id);
 | 
					    const newIds = createdBillItems.map(item => item.id);
 | 
				
			||||||
    await jobService.updateJob(jobId, {
 | 
					    await jobService.updateJob(jobId, {
 | 
				
			||||||
      [type]: [...currentIds, ...newIds]
 | 
					      [type]: newIds // Replace instead of append
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Update local state
 | 
					    // Update local state
 | 
				
			||||||
    const jobIndex = this.jobs.findIndex(j => j.id === jobId);
 | 
					    const jobIndex = this.jobs.findIndex(j => j.id === jobId);
 | 
				
			||||||
    if (jobIndex !== -1) {
 | 
					    if (jobIndex !== -1) {
 | 
				
			||||||
      this.jobs[jobIndex][type].push(...createdBillItems);
 | 
					      this.jobs[jobIndex][type] = createdBillItems; // Replace instead of append
 | 
				
			||||||
      this.notifyListeners();
 | 
					      this.notifyListeners();
 | 
				
			||||||
      return this.jobs[jobIndex];
 | 
					      return this.jobs[jobIndex];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user