8eacd86b04
- 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>
28 lines
1.1 KiB
JavaScript
28 lines
1.1 KiB
JavaScript
export const CLIENT_APPROVED_OR_BETTER = new Set(['client_approved', 'invoiced', 'paid']);
|
||
|
||
export function isCompletedVersionEligible(task, versionNumber) {
|
||
const taskVersion = Number(task?.current_version || 0);
|
||
const version = Number(versionNumber || 0);
|
||
if (version < taskVersion) return true;
|
||
return version === taskVersion && CLIENT_APPROVED_OR_BETTER.has(task?.status);
|
||
}
|
||
|
||
export function isInitialVersionEligible(task) {
|
||
if (!task || task.invoiced) return false;
|
||
return isCompletedVersionEligible(task, 0);
|
||
}
|
||
|
||
export function getRevisionChargeQuantity(versionNumber, revisionType) {
|
||
// Fourge's own error revisions are never billed to the client.
|
||
if (revisionType === 'fourge_error') return 0;
|
||
const version = Number(versionNumber || 0);
|
||
return version >= 2 ? 1 : 0;
|
||
}
|
||
|
||
// Parses version number from a subcontractor invoice item description like
|
||
// "Project • Task – R01". Legacy fallback only — new rows store version_number directly.
|
||
export function parseVersionFromItemDescription(description = '') {
|
||
const match = String(description).match(/[–\-]\s*R(\d{2})\b/i);
|
||
return match ? Number(match[1]) : 0;
|
||
}
|