- Add sync_project_status trigger so projects flip active<->completed with their tasks; backfill existing rows.
- handleSubmitReject now aborts (and alerts) if the rejection-reason submission fails to save, instead of silently flipping status to in_progress and logging a reason-less rejection.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Invoice numbers now come from DB function next_invoice_number()
(max+1 per year under advisory lock) with a unique index; the old
row-count method reused numbers after deletes and raced concurrent
creates, which broke public pay links
- Remove dead standalone TeamCreateInvoice page; the TeamInvoices
modal is the single create path (page had already drifted)
- Invoice delete now asks for confirmation and only un-bills tasks/
submissions not billed on another invoice
- Created invoice shows correct "sent" status in list without reload
- Invoice/due dates computed at save time, not module load
- Reopening a paid invoice clears stale stripe_fee
- Stripe webhook markPaid is idempotent (no double receipts)
- subcontractor_invoice_items.version_number column stores billing
version explicitly; description parsing kept as legacy fallback
- Drop unused buildInvoiceStatusByKey/deriveVersionStatus
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fourge's own error revisions should never be charged to the client.
getRevisionChargeQuantity now returns 0 for revision_type=fourge_error
regardless of version number. Applied at all 4 invoice picker call sites.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review-shadow submissions are type=initial with blank service_type; the
picker grabbed the first initial found, hitting a shadow -> null service ->
$0 price. New pickInitialServiceType() skips shadows and prefers a real
service_type. Fixes Harlingen sites showing $0 on invoice.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tasks/projects page: reverted back to one row per task (work status only,
no billing state on that page). Per-version R## tracking lives in invoicing
only (invoice_items, sub invoice form).
DB fix: 7 Public Storage tasks had pending revision versions (R01/R02)
with no delivery but were stuck as 'paid' from old invoice lifecycle sync.
Reset to 'not_started' so they appear in the Revisions tab for work:
68664, 68666, 68721 (R02), 68808, 68809 (R02), 68810 (R02), 68811 (R02)
Removed unused invoiceItems state/fetch from Tasks + ProjectDetail.
invoiceVersionRules helpers retained for invoicing use.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each revision (R00, R01, R02) is now an independent trackable unit:
invoiceVersionRules: add deriveVersionStatus, buildInvoiceStatusByKey,
parseVersionFromItemDescription for per-version status derivation
Tasks.jsx + ProjectDetail.jsx:
- Fetch invoice_items joined with invoice.status (team only)
- allRows/rows now flatMap per version (one row per R##)
- Status derived from: invoice_items > past version > task.status
- R00 paid shows as paid; R01 in_progress shows separately
- tr keys use rowKey (taskId:version) to avoid duplicate key warnings
Invoice lifecycle (TeamInvoiceDetail, TeamInvoices, TeamCreateInvoice):
- Remove task.status sync on invoice paid/sent/created
- Keep invoiced:true flag for double-billing prevention
- Task work status (not_started → client_approved) stays work-flow only
ProjectDetail completion bar uses task.status === client_approved only
(no longer polluted by invoiced/paid status from invoice sync)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevent overwriting task status when task has moved to a new revision
cycle after being invoiced. Now uses .eq('status', guardStatus) to only
update tasks still at the expected prior state:
- invoice creation: only update tasks at client_approved → invoiced
- mark sent: only client_approved → invoiced
- mark paid: only invoiced → paid
- reopen: only paid → client_approved
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
rgba(255,255,255,0.06) with backdrop blur renders lighter in Chrome.
rgba(0,0,0,0.35) gives consistent dark panel across all browsers.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 'PURCHASE ORDER' → 'SUBCONTRACTOR INVOICE'
- Items loop now calls addPage() when hitting safeBottom (792-80pt)
- Continuation pages get header with invoice number + '(continued)'
- Summary/Notes sections also page-break if needed
- Footer text updated to match invoice context
- Footer line position dynamic (tracks y), not hardcoded at 704
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Company dropdown and Email To input only editable on draft invoices.
Sent and paid invoices show read-only text values instead.
Applied to both popup (embedded) and standalone page views.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace SubcontractorInvoiceDetailView (card-based) with flat layout
matching the original sub-invoice popup: meta strip + raw table + notes.
- InvoiceDetailPopup: add metaContent/metaActions/metaCols props + export POPUP_FIELD_LABEL
- New InvoicePopupTable: flat sortable 5-col table, no card wrapper
- All 4 popups (client, team invoice, team sub-invoice, external): use
flat meta strip (4-col grid, borderBottom) and InvoicePopupTable
- Sub-invoice + external: Submitted | Paid/Created | Items | Total
- Client invoice: Date | Due | Status | Total
- Team invoice: Date | Due | Company | Email | Total (+ stripe if paid)
with Edit Dates button in metaActions slot
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Team performance: count each delivery record individually (sent_by + version_number), not per task — R00/R01/R02 by different people all count separately
- Performance uses deliveries table directly, EST timezone bucketing, month-gated tabs
- TaskDetail Submissions tab: reads from deliveries table, shows R## version, sent_by, sent_at
- Submit for Review: writes to deliveries + delivery_files (deliveries bucket), stores version_number
- Revision request popup: uses FileAttachment drag-drop component
- Task table: only Name and Project columns highlight on hover
- deliveries.version_number column added and backfilled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Expense detail popup: 80vw×80vh, inline editing, save gated on dirty state, Download Receipt in footer
- Add expense form: same layout with FileAttachment drag-drop on right
- New invoice popup: 80vw×80vh inline form replacing navigate-away page
- Tasks table: suppress row hover background, only Name/Project table-links highlight
- TaskDetail Submissions tab: reads from deliveries table, shows R## version, sent_by, message
- Submit for Review: writes to deliveries + delivery_files (deliveries bucket)
- deliveries.version_number column added and backfilled from revision history
- Port 4173 for dev server
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- FileSharing: rootPath for clients strips /Clients/ prefix — API resolveClientPath expects /{company} not /Clients/{company}
- Tasks: default to To Do tab (not_started) instead of All Tasks
- Projects: default to Active tab instead of All Projects
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Overview tab: 3 donut pie charts (expenses by category, sub payments, invoiced) each with independent month navigation arrows
- Expenses tab: big red total in category sidebar, left-aligned category column, white text
- Subcontractors tab: big gold total in sidebar, pending/paid breakdown with gold highlight
- Invoices tab: big green total in companies sidebar, dashboard-inline-link for invoice# and company, StatusBadge with Invoiced/Paid labels, column widths tuned
- StatusBadge: add optional label prop for custom display text
- Layout/style polish across tabs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>