Commit graph

36 commits

Author SHA1 Message Date
7713601be7 Merge pull request 'fix: PO details: show all attachments, grouped by type' (#27) from claude/issue-10 into master
Reviewed-on: https://git.pelagiamarine.com/shad0w/pelagia-portal/pulls/27
2026-06-19 06:57:08 +00:00
b592358db0 feat(app): env-gated banner (EnvBanner) for non-prod environments
Renders a thin fixed banner only when NEXT_PUBLIC_ENV_LABEL is set; production
leaves it unset so nothing shows. Used to mark the staging instance.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:56:34 +05:30
Claude (auto-fix)
4e6175153d fix(po): show all attachments grouped by type on PO details
All PO attachments are stored as PODocument rows whose lifecycle stage
(submission vs delivery) is encoded in the storageKey prefix. The PO
details screen previously listed them in a single flat "Attachments"
block, giving no indication of which were submission documents (invoice,
quotation) versus delivery receipts.

Add lib/attachments.ts to derive a user-facing group from the storageKey
prefix (submission / payment / delivery / other) and render each
non-empty group as a labelled subsection on the PO details screen, in
lifecycle order. Unknown prefixes fall back to an "Other" group so
nothing is ever hidden.

Fixes #10
2026-06-19 04:43:44 +05:30
080dafb473 feat(automation): add triage phase to issue watcher
Portal issues now file with only the 'portal' label. The watcher runs two phases:
  1. Triage — Claude reads each untriaged 'portal' issue (analysis only), posts a
     requirements-breakdown comment, and routes it to 'claude-queue' (auto-fixable)
     or 'interactive' (needs human steering).
  2. Fix — unchanged; processes 'claude-queue' issues into PRs.

The triage breakdown is posted without the bot marker so the fix stage reads it
back as refined requirements.

PS 5.1 fixes found while validating:
  - Send API bodies as UTF-8 bytes (Invoke-RestMethod mangled non-ASCII, e.g. the
    em-dash in Claude's breakdown, so Forgejo rejected the JSON)
  - Build the labels array body by hand (ConvertTo-Json unwraps a single-element
    array to a scalar, which Forgejo rejects)
  - Triage output via two plain files (label + markdown) instead of one JSON blob
    (embedded-newline markdown broke ConvertFrom-Json)
  - Read triage files as UTF-8; additive label POST + a guard so Set-IssueLabels
    can never wipe an issue's labels

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 04:20:21 +05:30
Claude (auto-fix)
5d3b45a3a4 fix(po-detail): show approval date as PO date on detail screen
The PO date field was only displayed when a submitter explicitly set it.
For approved POs without an explicit date, the approval date is now shown.
Precedence: submitter-set poDate → approvedAt → createdAt (matches the
export route which already used this logic).

Fixes #5
2026-06-19 03:39:19 +05:30
Claude (auto-fix)
25d1164d34 feat(po): allow submitter to set an optional PO date
Add an optional PO Date field to the create and edit PO forms.
Submitters can pick any date (back-dated or forward-dated). If left
blank, the exported PO document falls back to the approved date, then
to the creation date.

Changes:
- Prisma schema: add `poDate DateTime?` to PurchaseOrder
- Migration 20260616000000_add_po_date: ALTER TABLE to add the column
- createPoSchema: add optional `poDate` string field
- new-po-form, edit-po-form: add PO Date picker in Order Information
- create/edit actions: persist poDate to DB
- edit action resubmit snapshot: track poDate changes for manager diff
- po-detail: show PO Date in Order Details; include in resubmit diff banner
- export route: use poDate ?? approvedAt ?? createdAt as the date on
  the exported PDF/XLSX document
- validations.test: fix pre-existing costCentreRef→vesselId mismatch
  and add poDate test cases

Fixes #4

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 13:06:12 +05:30
8b6d4e8ea6 feat(automation): issue-to-deploy pipeline — Report Issue button, Claude watcher, tag-triggered deploy
- Report Issue button in portal header files a Forgejo issue (portal + claude-queue labels)
- Windows scheduled watcher runs headless Claude Code on queued issues and opens a PR
- .forgejo/workflows/deploy.yml deploys v* release tags via the pms1 host runner (pm2 restart ppms)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 16:39:43 +05:30
add0f3c19c feat(payments): compulsory payment date when Accounts records payment
- New PurchaseOrder.paymentDate field (migration 20260531000002)
- Backfill: existing POs use paidAt, else the earliest payment action date
- Accounts must enter a payment date with the payment reference
- Date input pre-selected to today, max=today (no future dates)
- Validated server-side (required + not in future) in processPaymentSchema
- paymentDate stored on both full and partial payments; paidAt set from it
- Shown on PO detail (Payment Date) and payment history (prefers paymentDate)
- Integration tests updated; added future-date rejection test

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 08:59:25 +05:30
b5a5097ab5 feat(sidebar): add Sites to Administration section for admin
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 08:49:58 +05:30
025b932f70 feat(sidebar): no Purchasing section for admin; Cost Centres in Administration
PURCHASING_MGMT roles narrowed to MANAGER only, so the entire Purchasing
section disappears for ADMIN (they never needed the /inventory/ browse links).
Cost Centres (/admin/vessels) added to the top of ADMIN_ITEMS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 08:46:19 +05:30
2c912caedb fix(searchable-select): reposition portal on scroll/resize
Adds scroll (capture) and resize listeners so the fixed-position dropdown
tracks its trigger as the page scrolls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 06:49:49 +05:30
982a114eb5 feat(products): edit support on /admin/products; Purchasing Items -> /inventory/items
- updateProduct server action (name + description, code locked)
- EditProductButton dialog in product-form.tsx
- Edit entry wired into ProductActionsMenu
- Sidebar Purchasing Items for Manager/Admin now points to /inventory/items (cart view)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 06:14:15 +05:30
9bbc97b9bd feat(sidebar): add Items (/admin/products) to Administration for Manager
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 06:10:42 +05:30
0d6df57a88 fix(sidebar): purchasing Vendors links to /inventory, admin to /admin
No mirroring: the two vendor links serve different purposes.
Purchasing -> /inventory/vendors (site selector, distance sort)
Administration -> /admin/vendors (CRUD registry)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 03:08:25 +05:30
cc9c7b7e1f feat(sidebar): add Vendors to Purchasing section for Manager/Admin
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 03:01:48 +05:30
e3851a1799 feat(sidebar+vessels): Purchasing section, split Administration, Cost Centre rename
Sidebar:
- Inventory section renamed to Purchasing
- Manager gets separate Administration section for Vendors only
- Admin gets full Administration (Vendors + Users + Accounting Codes + Companies)
- Sites hidden from Manager when NEXT_PUBLIC_INVENTORY_ENABLED=false
- Cost Centres replaces Vessels in the Purchasing nav link

Admin vessel pages:
- All headings, titles, dialogs, breadcrumbs: Vessels -> Cost Centre
- Error messages updated accordingly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 02:53:33 +05:30
ce24539640 fix(line-items): portal dropdown to escape overflow, hide scrollbar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 02:23:39 +05:30
a9c125c21c fix(searchable-select): compact mode dropdown positioning and group labels
- Compact dropdown is now right-anchored at fixed 380px width so it
  extends leftward from the trigger and doesn't overflow the table edge
- Group headers in compact mode show only the sub-category (strip the
  top-level breadcrumb before the arrow) and are single-line truncated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 02:19:32 +05:30
56b0490229 feat: structured PO numbers, import closed, auto-vendor/product, company code, inventory flag
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:56:33 +05:30
e308d86e93 feat: Companies — multi-company PO support with admin CRUD and export integration
Schema:
- New Company model (name, gstNumber, address, telephone, mobile, email, invoiceAddress, isActive)
- PurchaseOrder.companyId FK (optional, SET NULL on company delete)
- Migration: 20260530000003_add_company

Admin:
- /admin/companies page with full CRUD (create, edit, deactivate, delete)
- Companies table shows name, GST, contact details, status
- Companies link added to Admin section of sidebar (Briefcase icon)

PO forms (new / edit / import / manager-edit):
- Company dropdown appears at the top of Order Information when companies exist
- Pre-populated with first active company; selection persisted to DB via companyId

Import form:
- parseSheet() now extracts companyName from Excel row 1 (col A)
- Import preview auto-matches detected company name against known companies
- Shows detected name as a hint; user can override before saving

Export (PDF + XLSX):
- Company constants (CO_NAME, CO_ADDR, CO_TEL, INV_ADDR, INV_GST) are now
  derived from the linked Company record when present, falling back to the
  original Pelagia Marine hardcoded defaults when no company is set

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 19:31:34 +05:30
280966a369 refactor: revert cost centre to vessels only, remove vessel-site link
Cost Centre on PO forms now shows only Vessels (plain vesselId field).
Sites are a separate concept and not selectable as cost centres.

- PurchaseOrder.vesselId is required again (NOT NULL restored)
- Vessel.siteId and vessel->site relation removed from schema
- DB migration: drops Vessel.siteId column, restores PO.vesselId NOT NULL
- All PO forms (new/edit/import/manager-edit): plain vessel <select> with
  code-prefixed labels (e.g. "HNR1 — HNR 1")
- History, approvals, dashboard, my-orders, payments: back to vesselId
  filter params and po.vessel.name display
- Admin vessels: removed Site column and site-assignment dropdown
- Admin sites detail page: removed "Assigned Vessels" section
- Sites table: removed Vessels count column (no longer linked)
- seed-prod.ts and seed.ts: vessels created without siteId
- SearchableSelect accounting code picker retained from previous commit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 18:14:24 +05:30
565f9d5833 feat: searchable accounting code picker + cost centres grouped by site
Accounting Code search (new/edit/import/manager-edit PO forms):
- New SearchableSelect component (components/ui/searchable-select.tsx):
  type-to-filter by code or name, results grouped by sub-category with
  sticky headers, highlighted selected item, clear button, Escape/outside-click
  to dismiss
- Replaces the plain <select> for the main Accounting Code field on all PO forms
- LineItemsEditor per-row account column also uses SearchableSelect (compact size)
  when multi-account mode is active

Cost Centre dropdown reorganised by site:
- New type CostCentreGroup replaces flat CostCentreOption
- Each site becomes an <optgroup> label (unselectable); the site itself is the
  first selectable option inside ("Haldia (Site)"), followed by its vessels
- Vessels with no site assigned appear under an "Unassigned Vessels" group
- Shared helpers buildCostCentreGroups() and buildAccountGroups() in
  lib/cost-centre-groups.ts — used by all four PO form pages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 17:54:43 +05:30
cc7251e6b7 feat: Cost Centre covers vessels and sites, vessel codes, Accounting Code rename, vessel-site assignment
- Undo Vessel→Cost Centre rename in admin (admin shows "Vessel Management" again)
- Sidebar: "Cost Centres"→"Vessels", "Accounts"→"Accounting Codes"
- PO forms (new/edit/import/manager-edit) now show both Vessels (with code) and Sites in the
  Cost Centre dropdown, encoded as v:<id> / s:<id> via a costCentreRef field
- vesselId on PurchaseOrder is now nullable; siteId is set when a site is the cost centre
- History, approvals, dashboard, my-orders, payments display vessel.name ?? site.name as Cost Centre
- History and approvals cost centre filters use costCentreRef URL param supporting both types
- Admin vessel form: adds Site assignment dropdown
- Admin accounts: renamed to "Accounting Code" throughout (pages, forms, sidebar)
- PO detail and exports: "Account" label renamed to "Accounting Code"
- Site detail: "Assigned Vessels (Cost Centres)" heading; vessel detail breadcrumb fixed
- Create PO links from vessel/site detail use ?costCentreRef= param
- Export routes handle costCentreRef filter param (with legacy vesselId fallback)
- DB migration: ALTER TABLE PurchaseOrder ALTER COLUMN vesselId DROP NOT NULL
- CLAUDE.md updated with Cost Centre Model documentation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 03:04:29 +05:30
3f3e1e6423 feat(admin): confirm activate/deactivate via modal popup across all tables
Replace immediate server action calls with ConfirmDialog modals for
activate/deactivate on all 6 admin tables (users, vendors, vessels,
sites, accounts, products). Delete already used DeleteConfirmDialog;
this adds the same pattern for reversible toggle actions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 03:07:04 +05:30
d27ec9152c feat(admin): collapse row actions into ⋯ dropdown menu
Replace per-row inline action buttons (Edit, Activate/Deactivate, Delete,
Grant SuperUser) across all six admin tables with a Radix DropdownMenu
triggered by a ⋯ button. Introduces RowActionsMenu/Item/DestructiveItem/
Separator primitives and a DeleteConfirmDialog modal. Each Edit*Button
gains controlled open/onOpenChange props so the dialog can be driven from
the table's per-row ActionsMenu sub-component. Toggle and delete actions
use useTransition + router.refresh() directly in the table.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 02:58:54 +05:30
9758dcd8ab feat(admin): add client-side search, sort, and filter chips to all admin tables
Adds a reusable useTableControls hook and TableControls/SortableTh
components, then wires them into all six admin table pages (users,
vendors, vessels, sites, accounts, products). Each page now supports
a global search bar, clickable sortable column headers with ↑/↓/⇅
indicators, and role/status filter chips — all purely client-side with
no URL params or server round-trips. Server pages continue to fetch the
full list and pass it as props to a new *-table.tsx Client Component.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 02:46:52 +05:30
b31fe7374c fix(ui): remove PMS taglines from login and mobile pages
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 15:23:23 +05:30
49ba6e8be5 fix(ui): use defined theme colors for danger/warning buttons
The theme only defines danger/warning/success as flat colors plus -50/-100/-700
shades. bg-danger-600 and bg-warning-600 don't exist so those buttons rendered
with a transparent background, making white text invisible until hover revealed
bg-danger-700. Replaced with bg-danger / bg-warning which are defined.
Also fixed border-danger-200/400 and text-danger-600 (undefined) on the
Delete and Confirm Delete buttons.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 13:11:10 +05:30
3e5d11c4ae feat(po): show note author name on manager note banners
Derives the author from the most recent EDITS_REQUESTED / REJECTED /
APPROVED action that carries a note. PO detail banner now shows 'Note from
[name]', edit-page banner shows 'Edits requested by [name]', and the
closed-orders list prefixes the truncated note with the author's name.
No schema changes required - uses the already-fetched actions with actor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 04:41:53 +05:30
d4007ee222 feat(my-orders): rename to Closed Purchase Orders, show only closed POs
Open POs are already visible on the dashboard. The /my-orders page now
fetches and displays only completed/closed statuses (MGR_APPROVED through
REJECTED) and is labelled 'Closed Purchase Orders' throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 04:21:53 +05:30
cf9ff40262 feat(payments): partial/advance payment support
Allow accounts to record partial/advance payments against a PO before
full delivery. A new PARTIALLY_PAID status tracks in-progress payment;
paidAmount accumulates across multiple markPaid calls. PO only closes
when both paidAmount >= totalAmount AND all line items are delivered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 04:17:19 +05:30
a8e3b5d69b fix(diff): show GST rate strikethrough when submitter changes it on edit
qtyChanged/priceChanged/nameChanged were tracked for the diff view but
gstChanged was missing, so an edited GST % showed only the new value
with no strikethrough of the old one. Added gstChanged detection and
two-line rendering (old % struck through, new % in amber) to match the
other diff columns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 03:34:54 +05:30
987b0aedfa fix(mobile): prevent notification dropdown overflow on small screens
The dropdown was w-96 (384 px) anchored right-0 to the bell button.
On phones the bell sits left of the logout icon so the panel bled off
the left viewport edge. Changed to w-80/sm:w-96 with a 100vw safety cap.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 03:32:37 +05:30
1c5727850a fix(gst): 0% GST rate no longer falls back to 18%
parseFloat('0') is falsy in JS so `|| 0.18` silently discarded the user's
explicit 0% selection. Replaced with an explicit empty-string guard.
Adds e2e spec gst-rate.spec.ts covering all five GST rates (0/5/12/18/28%).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 00:00:51 +05:30
32ea27331c fix(po): tighten filters and export data 2026-05-22 17:15:03 +05:30
19029a5a77 chore: restructure repo — flatten App/pelagia-portal to App, rename Prototype→Wireframe and Spec→Design
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 23:18:58 +05:30