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]
);
}