Commit graph

173 commits

Author SHA1 Message Date
f80e572c08 chore(deploy): retrigger deploy for the PO price fix (2682eeb)
No code change - the price fix is already committed and pushed. The
deploy for 2682eeb had not started on the live site, so this pushes a
new commit to re-fire the build webhook.
2026-10-23 12:31:37 +02:00
2682eeb360 fix(po): store the price from the form so POs stop printing £0.00
Every purchase order created from a stock item printed a £0.00 unit
price, even though a cost price was on the record and the form showed
the right number.

Cause: the PO snapshot took costPriceGBP from the stock item's stored
cost_price_gbp instead of from the form. The price the user sees (and
types) into the "Unit Price (£ GBP)" field landed in snapshot.costPrice,
which nothing renders, while the PO PDF renders snapshot.costPriceGBP
(pdf.ts: `£${item.costPriceGBP}`). So a price typed into the form was
discarded and the stock item's cached value was printed instead.

Because the stock item's cost_price_gbp was only written back to the
database AFTER the PO was created, the first PO of an item always showed
£0.00 and only the next one showed the price. Verified in production:
PO-20261023-002 stored costPrice 333.78 / costPriceGBP 0 and printed
£0.00, while the linked stock item's cost_price_gbp was 0 at the time
and was updated to 333.78 by the sync step three minutes later.

Fixes:
- PurchaseOrderForm: snapshot.costPriceGBP is now the price from the
  form; snapshot.costPrice is the stock item's ZAR landed cost.
- PurchaseOrderForm: selecting a stock item with no GBP cost price
  leaves the price field blank instead of showing £0.00, with a hint
  that the supplier's GBP price still has to be entered. Most stock
  items only carry a ZAR cost price, so £0.00 looked like a real price.
- EditPurchaseOrderDialog: preserve the ZAR cost price per row instead
  of zeroing it when a PO is edited.
2026-10-23 12:08:03 +02:00
2b56053e1c fix(po): stop PocketBase auto-cancellation from killing PO creation
The Purchase Order form never reached the server. Creating a PO with two
or more "Manual Entry" rows fired N parallel POSTs to
/api/collections/stock_items/records via Promise.all. The PocketBase JS
SDK auto-cancels any in-flight request whose method + path match a newer
one, so the first POST was aborted with:

  ClientResponseError 0: The request was autocancelled.

Promise.all then rejected before the PO create ever ran, so the PO was
never created - only an orphan stock item per attempt. Confirmed against
the production PB logs: two stock_items POSTs today, zero
purchase_orders POSTs, and two orphan stock_items rows with no PO.

Fixes:
- src/lib/pocketbase.ts: pb.autoCancellation(false) on the browser
  client. Every server-side client in this repo already did this
  (scripts/*.mjs, server/po-api.mjs) - the browser client was the one
  place it was missing.
- PurchaseOrderForm: resolve rows sequentially instead of Promise.all,
  and build the snapshot in the same pass so manual rows carry the real
  stock item id instead of "".
- PurchaseOrderForm: disable the submit button while submitting, so a
  double click cannot create two POs.
- PurchaseOrderForm: compare SKUs trimmed, so a stray trailing space
  does not create a duplicate stock item.
- po-photo-ingest.mjs, jei_skill.ts, setup-users.js: same
  autoCancellation(false) guard.
2026-10-22 07:56:30 +02:00
a30270e77f fix(quotes): wrap item descriptions on the quote PDF
Item descriptions were cut off with an ellipsis. Long names like
"PRO132T-C24 - CARBON BRUSH EACH, PRO152T" lost their tail, which on a
quotation reads as a mistake.

Descriptions now wrap onto as many lines as they need and the row grows
to fit, so the full name is always printed. SKU, quantity, price and
total stay on the first line of the row.

While wrapping, the quote PDF gained the page handling the purchase
order PDF already had: a row that no longer fits moves to a new page
with the column headers repeated, and the totals and notes blocks
break to a new page rather than running off the bottom. Before this
the quote PDF had no page breaks at all, so a long quote simply ran
off the page.

Addresses also keep their line breaks now instead of being flattened
into one line.

The two quote PDF builders - "Download PDF" and the copy stored in
PocketBase - were near-identical copies of ~275 lines. They now share
one builder (quotePdf.ts), so a layout fix can no longer land in one
and miss the other.
2026-10-21 08:40:39 +02:00
9d2ba5a430 feat(quotes): delete quotes from the app, add customer inline with full details
Two things that meant going into PocketBase by hand or jumping between
screens.

Deleting a quote
- Quotes had no delete action - a test quote could only be removed
  through the PocketBase admin UI. Purchase orders already soft delete
  by flipping a `deleted` flag, so quotes now do the same: the Delete
  action confirms first, then hides the quote from the list while the
  record and its PDF stay in PocketBase for audit.
- The quotes list filters out soft-deleted quotes, so a deleted quote
  is out of the way but recoverable by clearing the flag.

Adding a customer while writing a quote
- Typing a customer name that was not in the list used to create a
  name-only stub, which then had to be edited from the Customers screen
  before the quote could show an address or VAT number.
- The picker now opens the full customer form right there - address,
  VAT number, email and phone - with the name pre-filled. The new
  customer is created, added to the list and selected, so the quote
  carries on and the PDF has the details.
2026-10-21 05:09:11 +02:00
99e9d947cf feat(quotes,customers): address + VAT on quotes, 30-day validity, searchable customer
A quote should look like a document from a real company, so this adds
the customer details a quote needs, gives every quote a valid-until
date, and makes the customer picker usable once there are 20+ of them.

Customer details on quotes
- The `customers` collection only had a name, so the quote PDF's
  "Customer Information" block could only ever print a name. Added
  optional address, VAT number, email and phone fields.
- The PDF block now grows to fit whatever is on file and prints the
  VAT number and contact line, so a filled-in customer produces a
  professional quote.
- The quote details dialog shows the same details.
- The customer form gained the new fields, and "Edit customer" now
  works - it was a menu item that did nothing, so there was no way
  to add a VAT number to an existing customer.
- The customers table shows Address and VAT Number columns.

Valid until
- Quotes were created with an empty validUntil, so the PDF printed
  "Valid Until: N/A". The form now defaults it to 30 days after the
  quote date and keeps it in step when the date moves. The three
  existing quotes without one were backfilled the same way.

Searchable customer picker
- The customer dropdown listed every customer in a plain select with
  no way to add one that was missing. It is now a searchable combobox
  (by name, address or VAT number) that offers to create the customer
  when nothing matches, and creates it inline.

Sidebar
- Settings moved to a gear in the corner next to the app name, and
  Logs moved into Settings as a tab. The nav is now eight items with
  no grouping - grouping them would add a layer for no gain at this
  size. The old /logs link still lands on the logs tab.

Also fixes a real PDF bug: item descriptions were cut to 40 characters,
which is wider than the description column, so long names printed on
top of the SKU column. Descriptions and SKUs are now measured against
the real column width and truncated with an ellipsis.

Live PocketBase changes (see scripts/add-customer-fields.mjs):
- customers update and delete rules were null (superusers only), so a
  member could not edit the customer they had just added. They now
  match the other collections.
2026-10-21 04:45:58 +02:00
edc9f3da74 feat(settings): add user management, fix totals and mobile layout
Adds a Settings > Users screen where members can be added, turned off
and removed, and fixes three defects found while auditing the app on
a phone.

User management
- Settings is a real page with a Users section: add a member (name,
  email, password), flip "Can sign in" to block or restore access
  without deleting their history, or remove them outright.
- The app has no roles - membership is just the active flag - so the
  Settings route no longer requires the "admin" role, which left it
  unreachable for every real member. Settings is now in the sidebar.
- New members are created with active: true. AuthContext refuses to
  sign in a user whose active flag is false, and the field had no
  default, so previously created users were locked out of the app.

Live PocketBase rules for the `users` collection (see
scripts/fix-users-collection.mjs):
- createRule was "" which means PUBLIC - any anonymous visitor could
  create an account on the instance. It now requires an authenticated
  member.
- listRule was "id = @request.auth.id", so a member could only ever
  see their own record and no member list could be rendered. It now
  matches every other collection in the app: @request.auth.id != "".

Totals always showed R0.00
- form.watch("items") returns the same array instance that
  react-hook-form mutates in place, so the useMemo keyed on it never
  recomputed. Both the quote and purchase order totals stayed at zero
  however many items were added. Switched to useWatch with compute,
  which re-runs whenever the watched field really changes.

Mobile layout
- The page was zoomed out on phones: flex items default to
  min-width:auto, so a wide table stretched the layout past the
  viewport. Added min-w-0 to the layout chain.
- The sr-only labels inside the tables are position:absolute with no
  positioned ancestor, so they escaped the table's overflow-x-auto
  clip and stretched the document. Made the scroll containers
  relative.
- DialogContent was w-full plus an mx-4 gutter, which overflowed the
  viewport by 16px and clipped the right edge of every form. The
  component now owns the gutter itself.

Verified at 390x844: all pages and the quote, purchase order and add
user dialogs fit the viewport with no horizontal overflow.
2026-10-21 03:13:01 +02:00
d606345de4 fix(quotes,po): repair item storage, totals and PDF line items
Quotes and purchase orders were silently losing their line items.

Quote items field was a multi-relation to stock_items, but PocketBase
stored only the last id as a plain string no matter how it was sent
(JSON string via FormData, raw array, or repeated FormData entries).
Every quote created through the UI had `items: ""` or `items: "<id>"`.
Recreated the field as JSON so an array of stock_item ids round-trips
(companion fields quantities/unitPrices already line up with it).

PO snapshot_items had the same class of bug from the other direction:
String(obj) coerced the snapshot array to "[object Object]", which
PocketBase stored verbatim, rendering the PO as N rows of
"Unknown / £0.00". The form now sends JSON-stringified arrays, and
the reader only trusts a snapshot whose rows actually carry a name.

Also fixes:
- Quote item lines are hydrated from stock_items; the parallel
  quantities/unitPrices arrays are the source of truth, so quotes
  written before the schema fix still render and total correctly.
- Quote form rejects stock rows where no item was actually picked
  from the dropdown, instead of saving an empty stockItemId.
- PO PDF filename is now the plain order number (PO-20261015-001.pdf).

Adds the quotes.items schema migration plus three dev scripts for
creating a quote, re-applying the field fix and rendering a test PDF.
2026-10-20 20:13:46 +02:00
0b8f003f87 feat(po): add MCP server, agent-friendly PO API, and PDF rendering
- server/pb-mcp.mjs: 15-tool MCP server for purchase-order workflow
  (CRUD, suppliers, stock, customers, customer POs, validate_draft,
  generate_order_number)
- src/lib/api/purchaseOrders.ts: typed helpers shared by UI + MCP + n8n
- src/components/purchase-orders/pdf.ts: jsPDF PO generator
- src/components/purchase-orders/ViewOrderDialog.tsx: read-only dialog
- src/components/purchase-orders/AttachmentsDialog.tsx: attachment mgmt
- src/components/purchase-orders/NumberInput.tsx: numeric input
- scripts/mcp-create-po.mjs: end-to-end driver (MCP stdio smoke test)
- pocketbase/pb_migrations/1786200007_*: schema migration
- docs/MCP_AND_N8N.md: MCP + n8n integration guide

Verified end-to-end via MCP: generate_order_number → create_purchase_order
with snapshot_items for an actual quote (DRILL-19042 / 161053).
2026-09-07 11:12:13 +02:00
c272526d67 feat(automation): add PO-to-invoice pipeline
- 6 new PocketBase migrations: customer_pos, customer_po_lines, invoices,
  invoice_items, email_inbox, workflow_runs
- n8N workflow JSON: 01-customer-po-to-parsed.json + 02-parsed-po-to-invoice.json
- MCP server config (.cursor/mcp.json + .mcp.json) for AI agent PB access
- .env.example template with all required credentials documented
- n8n/README.md with deployment, testing, and customization notes
2026-09-06 23:40:33 +02:00
642548295e chore: untrack .env and pb_data, update gitignore 2026-09-01 07:45:02 +02:00
SJCoetz
d4be480ecb Add PO snapshot_items and edit/order handling
Add a PocketBase migration and store snapshot_items on purchase order creation so POs keep item details even if stock items change or are deleted. Wire snapshot_items through the UI: PurchaseOrders list prefers snapshot data when present; EditPurchaseOrderDialog supports snapshot fallback, SKU, entryMode (stock/manual), add/remove rows, and updates stock item GBP prices for stock-mode items. BookOutForm now deducts stock quantities on booking out and surfaces precise errors. Minor UI and behavior tweaks: low-stock report filters only actual stock items, columns typing includes snapshotItems, and edit action/menu is always available with an Edit dialog integrated into the PurchaseOrders page.
2026-05-24 00:11:37 +02:00
SJCoetz
6db980b4ca UI: style polish, charts, tables, forms, PDF fix
Apply broad UI and UX polish across the app: replace hardcoded color classes with theme tokens (background/foreground), improve card hover/spacing, and standardize form/button styles and responsive wrappers. Enhance charts with custom tooltips, gradients, empty state, legend styling, and improved axes/cursor behavior. Tidy table and data-grid styles (compact spacing, hover states, nowrap), add status badges, and wire DataTable/Customer table meta to support onDelete actions. Fix PurchaseOrder PDF generation by wrapping creation in try/catch and adjust dialog sizing; other form fixes include replacing useFieldArray update calls with form.setValue in BookOutForm. Add Playwright page snapshots and multiple PNG assets (visuals/screenshots) for testing/documentation.
2026-05-16 00:07:52 +02:00
SJCoetz
7196449e19 Add quotes feature and PO attachments
Introduce a Quotes area and add comprehensive attachment support for Purchase Orders. Adds new Quote components/pages (QuoteColumns, QuoteDataTable, Quotes page) and registers the /quotes route and sidebar link. Implements AttachmentUpload and AttachmentList components, an AttachmentDialog and integrates attachments into PurchaseOrderForm and EditPurchaseOrderDialog (files uploaded to PocketBase, attachments auto-set status to "Ordered"). Enhances PO form to support manual item entry (creates stock items on-the-fly), improves PDF generation (returns blob, supports regenerate+save), and provides attachment management in the PO data table. Also includes UI/truncation fixes, stock search popover sizing, new screenshots, and several skill/metadata files.
2026-05-15 07:11:07 +02:00
davidels1
05c8981513 feat(reports): add low stock report component and integration
Add new LowStockReport component with data fetching and table display functionality. Includes threshold filtering and refresh capability. Update Reports page to include the new low stock section and modify the description text.
2026-01-14 09:04:38 +02:00
davidels1
315a9c7759 feat(purchase-orders): add edit functionality and improve form validation
- Implement EditPurchaseOrderDialog for modifying existing orders
- Enhance form validation with better number handling and error messages
- Add subtotal calculation to purchase order forms
- Improve PDF generation with logo support and better layout
- Update column definitions to include edit action
- Add className prop to StockItemSearch for better styling control
2026-01-14 09:01:49 +02:00
davidels1
e304a0a283 Merge branch 'main' of https://github.com/CyberTechDroid/JEI_STOCK_APP 2026-01-13 10:28:27 +02:00
davidels1
c253820bbc ci(vite): add allowedHosts to preview config
Configure preview server to only allow requests from jeistock.apphub.co.za domain
2026-01-13 10:28:14 +02:00
davidels1
a638ac31f0 Update nixpacks.json 2025-12-29 14:15:05 +02:00
davidels1
9f50719bef Create nixpacks.json 2025-12-29 14:12:29 +02:00
davidels1
6f12859c71 Refactor item selection to use stock item IDs
Updated BookOutForm, StockItemCombobox, PurchaseOrderForm, and StockItemSearch to use stock item IDs instead of names for selection and form state management. Improved search robustness and matching logic, normalized cost price values, and enhanced field array updates for better React Hook Form integration. Added a dialog description to the purchase order modal for improved user guidance.
2025-11-24 11:33:12 +02:00
davidels1
f7b46986c5 Add GBP cost price to stock and purchase orders
Introduces a new 'cost_price_gbp' field to the stock items schema and database migration. Updates stock item forms to support both ZAR and GBP cost prices. Purchase order forms and PDF generation now use GBP pricing, with enhanced supplier and order metadata. Adds a searchable stock item selector for purchase orders and improves type definitions and UI labels for clarity.
2025-11-05 14:55:42 +02:00
davidels1
1030dad876 Refactor data fetching to use getFullList in forms
Replaced usage of getList with getFullList for fetching records in BookOutForm, PurchaseOrderForm, AddItemForm, and EditItemForm. This change simplifies data retrieval and ensures all records are fetched without pagination.
2025-09-29 09:17:39 +02:00
davidels1
75bb145241 Refactor PurchaseOrderForm to align item submission structure with PocketBase requirements 2025-09-25 23:44:06 +02:00
davidels1
8647d3dd3e Refactor purchase order form and stock columns
Updated PurchaseOrderForm to use useFieldArray for managing items, simplifying add/remove logic and improving reactivity. Adjusted stock columns to conditionally render cells based on screen size for better responsive design, and fixed currency code casing in sellingPrice column.
2025-09-25 23:29:58 +02:00
davidels1
54d029cf14 Enhance responsiveness of PurchaseOrderForm and enable horizontal scrolling in Stock page 2025-09-25 23:18:24 +02:00
davidels1
6c4ec2c423 fixedproblems 2025-09-25 10:40:43 +02:00
davidels1
39a48e3b4b Refactor layout and styling across multiple components for improved responsiveness and consistency 2025-09-25 02:04:50 +02:00
davidels1
9f79dae941 Refactor authentication checks in useDashboardData and add collection auth rules for authenticated users 2025-09-25 01:50:01 +02:00
davidels1
7133409c04 Update PocketBase URL handling and environment type definitions 2025-09-25 01:37:21 +02:00
davidels1
bbb079f8fc Delete pnpm-lock.yaml 2025-09-25 01:13:28 +02:00
davidels1
796bac47b4 Add icon generation script and new icons for PWA and favicons
- Introduced `generate-icons.mjs` script to automate the creation of PWA icons and favicons from the provided SVG logo.
- Generated icons include:
  - PWA icons: 192x192 and 512x512
  - Maskable icon with 12% padding: 512x512
  - Favicons: 32x32, 16x16
  - Apple-touch icon: 180x180
- Added a new PNG file for the maskable icon.
2025-09-25 00:50:36 +02:00
davidels1
9ee0905d9f Chaned header and db link 2025-09-25 00:27:25 +02:00
davidels1
23198d9094 Fixed login 2025-09-25 00:15:35 +02:00
davidels1
2dc385cbdc Create 1757376600_created_logs.js 2025-09-24 23:21:13 +02:00
[dyad]
a7ef17d9bf [dyad] Enhanced stock search to filter by partial name, SKU, and category - wrote 2 file(s) + extra files edited outside of Dyad 2025-09-23 16:34:26 +02:00
[dyad]
19ae6a9f6c [dyad] Updated low stock alerts threshold to less than 3 - wrote 2 file(s) + extra files edited outside of Dyad 2025-09-23 16:32:40 +02:00
[dyad]
b4f8ac7fb4 [dyad] Fixed dashboard stats (unique items count, book out as orders) and updated chart colors - wrote 3 file(s) + extra files edited outside of Dyad 2025-09-23 16:26:56 +02:00
[dyad]
bf096abfc8 [dyad] Updated dashboard to fetch and display actual data from PocketBase collections - wrote 3 file(s) + extra files edited outside of Dyad 2025-09-23 16:24:23 +02:00
[dyad]
961604be6c [dyad] Fixed total customers calculation and added debugging logs - wrote 1 file(s) + extra files edited outside of Dyad 2025-09-23 16:19:55 +02:00
[dyad]
dbe224d67e [dyad] Fixing dashboard data fetching to display actual values - wrote 2 file(s) + extra files edited outside of Dyad 2025-09-23 16:15:30 +02:00
[dyad]
07a46da8e3 [dyad] Ensuring correct field names are used in useDashboardData hook - wrote 2 file(s) + extra files edited outside of Dyad 2025-09-23 16:14:36 +02:00
[dyad]
177c0c6af4 [dyad] Removing item limit on Stock Management screen - wrote 1 file(s) + extra files edited outside of Dyad 2025-09-23 16:10:25 +02:00
[dyad]
a57db8f58c [dyad] Improving mobile responsiveness of Reports view - wrote 2 file(s) 2025-09-21 22:06:27 +02:00
[dyad]
c289676f94 [dyad] Moving Toggle Columns button above the table - wrote 1 file(s) 2025-09-21 21:20:24 +02:00
[dyad]
21a79ca525 [dyad] Improving mobile responsiveness of Book Out Items screen - wrote 2 file(s) 2025-09-21 21:17:41 +02:00
[dyad]
36bfc1c599 [dyad] Preventing horizontal scrolling in BookOutForm on small screens - wrote 1 file(s) 2025-09-21 21:15:23 +02:00
[dyad]
7aa992fe81 [dyad] Removing Products and Orders links and improving BookOutForm responsiveness - wrote 2 file(s) + extra files edited outside of Dyad 2025-09-21 21:14:00 +02:00
[dyad]
c4545285a6 Updated src/lib/pocketbase.ts 2025-09-21 19:32:39 +02:00
[dyad]
ae24415f5a Updated AI_RULES.md 2025-09-19 12:19:47 +02:00