diff --git a/migrations/add-unit-cost.sql b/migrations/add-unit-cost.sql new file mode 100644 index 0000000..7c9da8b --- /dev/null +++ b/migrations/add-unit-cost.sql @@ -0,0 +1 @@ +ALTER TABLE invoice_items ADD COLUMN unit_cost character varying(50); diff --git a/public/js/utils/item-editor.js b/public/js/utils/item-editor.js index 78334dd..ded144e 100644 --- a/public/js/utils/item-editor.js +++ b/public/js/utils/item-editor.js @@ -101,7 +101,11 @@ export function addItem(containerId, { item = null, type = 'invoice', laborRate -
+
+ + +
+
@@ -209,7 +213,6 @@ export function handleTypeChange(selectEl, prefix, itemId) { const rateInput = itemDiv.querySelector('[data-field="rate"]'); if (rateInput && (!rateInput.value || rateInput.value === '0')) { rateInput.value = laborRate; - // Recalculate amount const qtyInput = itemDiv.querySelector('[data-field="quantity"]'); const amountInput = itemDiv.querySelector('[data-field="amount"]'); if (qtyInput.value) { @@ -219,6 +222,11 @@ export function handleTypeChange(selectEl, prefix, itemId) { } } + const costField = itemDiv.querySelector('.cost-field'); + if (costField) { + costField.style.display = (selectEl.value === '9') ? '' : 'none'; + } + updateItemPreview(itemDiv); onUpdate(); } @@ -236,11 +244,15 @@ export function getItems(containerId) { ? descEditor.quillInstance.root.innerHTML : ''; + const qboItemId = div.querySelector('[data-field="qbo_item_id"]').value; + const unitCostInput = div.querySelector('[data-field="unit_cost"]'); + items.push({ quantity: div.querySelector('[data-field="quantity"]').value, - qbo_item_id: div.querySelector('[data-field="qbo_item_id"]').value, + qbo_item_id: qboItemId, description: descriptionHTML, rate: div.querySelector('[data-field="rate"]').value, + unit_cost: (qboItemId === '9' && unitCostInput) ? unitCostInput.value : '', amount: div.querySelector('[data-field="amount"]').value }); }); diff --git a/schema.sql b/schema.sql index 73156ca..238bb95 100644 --- a/schema.sql +++ b/schema.sql @@ -88,10 +88,10 @@ CREATE TABLE public.invoice_items ( amount character varying(50) NOT NULL, item_order integer NOT NULL, created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP, - qbo_item_id character varying(10) DEFAULT '9'::character varying + qbo_item_id character varying(10) DEFAULT '9'::character varying, + unit_cost character varying(50) ); - ALTER TABLE public.invoice_items OWNER TO quoteuser; -- diff --git a/src/routes/invoices.js b/src/routes/invoices.js index 191c8bc..855f094 100644 --- a/src/routes/invoices.js +++ b/src/routes/invoices.js @@ -192,8 +192,8 @@ router.post('/', async (req, res) => { for (let i = 0; i < items.length; i++) { await client.query( - 'INSERT INTO invoice_items (invoice_id, quantity, description, rate, amount, item_order, qbo_item_id) VALUES ($1, $2, $3, $4, $5, $6, $7)', - [invoiceId, items[i].quantity, items[i].description, items[i].rate, items[i].amount, i, items[i].qbo_item_id || '9'] + 'INSERT INTO invoice_items (invoice_id, quantity, description, rate, amount, item_order, qbo_item_id, unit_cost) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)', + [invoiceId, items[i].quantity, items[i].description, items[i].rate, items[i].amount, i, items[i].qbo_item_id || '9', items[i].unit_cost || null] ); } @@ -333,8 +333,8 @@ router.put('/:id', async (req, res) => { await client.query('DELETE FROM invoice_items WHERE invoice_id = $1', [id]); for (let i = 0; i < items.length; i++) { await client.query( - 'INSERT INTO invoice_items (invoice_id, quantity, description, rate, amount, item_order, qbo_item_id) VALUES ($1, $2, $3, $4, $5, $6, $7)', - [id, items[i].quantity, items[i].description, items[i].rate, items[i].amount, i, items[i].qbo_item_id || '9'] + 'INSERT INTO invoice_items (invoice_id, quantity, description, rate, amount, item_order, qbo_item_id, unit_cost) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)', + [id, items[i].quantity, items[i].description, items[i].rate, items[i].amount, i, items[i].qbo_item_id || '9', items[i].unit_cost || null] ); }