fix: fourge_error revisions always bill $0 to client
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>
This commit is contained in:
@@ -33,7 +33,8 @@
|
|||||||
"mcp__plugin_supabase_supabase__list_projects",
|
"mcp__plugin_supabase_supabase__list_projects",
|
||||||
"Bash(grep -rni \"task_number\\\\|task #\\\\|task#\\\\|#\\\\${\\\\|taskNumber\\\\|seq\" src/pages/Tasks.jsx src/pages/TaskDetail.jsx src/pages/ProjectDetail.jsx)",
|
"Bash(grep -rni \"task_number\\\\|task #\\\\|task#\\\\|#\\\\${\\\\|taskNumber\\\\|seq\" src/pages/Tasks.jsx src/pages/TaskDetail.jsx src/pages/ProjectDetail.jsx)",
|
||||||
"mcp__plugin_supabase_supabase__apply_migration",
|
"mcp__plugin_supabase_supabase__apply_migration",
|
||||||
"Bash(git commit -q -m 'fix: invoice picker skips review-shadow rows for service_type/pricing *)"
|
"Bash(git commit -q -m 'fix: invoice picker skips review-shadow rows for service_type/pricing *)",
|
||||||
|
"Bash(git commit -q -m 'fix: fourge_error revisions always bill $0 to client *)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ export function isInitialVersionEligible(task) {
|
|||||||
return isCompletedVersionEligible(task, 0);
|
return isCompletedVersionEligible(task, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRevisionChargeQuantity(versionNumber) {
|
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);
|
const version = Number(versionNumber || 0);
|
||||||
return version >= 2 ? 1 : 0;
|
return version >= 2 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ export default function CreateInvoice() {
|
|||||||
const serviceLabel = getRevisionServiceType(revision);
|
const serviceLabel = getRevisionServiceType(revision);
|
||||||
const description = buildRevisionItemDescription(revision);
|
const description = buildRevisionItemDescription(revision);
|
||||||
const price = priceList.find(p => p.service_type === serviceLabel && p.price_type === 'revision');
|
const price = priceList.find(p => p.service_type === serviceLabel && p.price_type === 'revision');
|
||||||
const revisionChargeQty = getRevisionChargeQuantity(revision?.version_number);
|
const revisionChargeQty = getRevisionChargeQuantity(revision?.version_number, revision?.revision_type);
|
||||||
const quantity = revisionChargeQty > 0 ? revisionChargeQty : 1;
|
const quantity = revisionChargeQty > 0 ? revisionChargeQty : 1;
|
||||||
const unitPrice = revisionChargeQty > 0 ? (price?.price || '') : 0;
|
const unitPrice = revisionChargeQty > 0 ? (price?.price || '') : 0;
|
||||||
setItems(prev => {
|
setItems(prev => {
|
||||||
@@ -436,7 +436,7 @@ export default function CreateInvoice() {
|
|||||||
{uninvoicedRevisions.map(rev => {
|
{uninvoicedRevisions.map(rev => {
|
||||||
const revServiceType = getRevisionServiceType(rev);
|
const revServiceType = getRevisionServiceType(rev);
|
||||||
const price = priceList.find(p => p.service_type === revServiceType && p.price_type === 'revision');
|
const price = priceList.find(p => p.service_type === revServiceType && p.price_type === 'revision');
|
||||||
const revisionChargeQty = getRevisionChargeQuantity(rev?.version_number);
|
const revisionChargeQty = getRevisionChargeQuantity(rev?.version_number, rev?.revision_type);
|
||||||
const alreadyAdded = items.some(i => i.submission_id === rev.id);
|
const alreadyAdded = items.some(i => i.submission_id === rev.id);
|
||||||
return (
|
return (
|
||||||
<div key={rev.id} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '8px 12px', background: 'var(--bg)', borderRadius: 4, border: '1px solid var(--border)' }}>
|
<div key={rev.id} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '8px 12px', background: 'var(--bg)', borderRadius: 4, border: '1px solid var(--border)' }}>
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ export default function Invoices() {
|
|||||||
const invAddRevision = (rev) => {
|
const invAddRevision = (rev) => {
|
||||||
const svcType = pickInitialServiceType(rev.task?.submissions, rev.service_type || rev.task?.title || 'Revision');
|
const svcType = pickInitialServiceType(rev.task?.submissions, rev.service_type || rev.task?.title || 'Revision');
|
||||||
const price = invPriceList.find(p => p.service_type === svcType && p.price_type === 'revision');
|
const price = invPriceList.find(p => p.service_type === svcType && p.price_type === 'revision');
|
||||||
const revisionChargeQty = getRevisionChargeQuantity(rev?.version_number);
|
const revisionChargeQty = getRevisionChargeQuantity(rev?.version_number, rev?.revision_type);
|
||||||
const qty = revisionChargeQty > 0 ? revisionChargeQty : 1;
|
const qty = revisionChargeQty > 0 ? revisionChargeQty : 1;
|
||||||
const unitPrice = revisionChargeQty > 0 ? (price?.price || '') : 0;
|
const unitPrice = revisionChargeQty > 0 ? (price?.price || '') : 0;
|
||||||
const desc = invBuildRevisionItemDescription(rev);
|
const desc = invBuildRevisionItemDescription(rev);
|
||||||
@@ -2017,7 +2017,7 @@ export default function Invoices() {
|
|||||||
</div>
|
</div>
|
||||||
{invUnbilledRevisions.map(r => {
|
{invUnbilledRevisions.map(r => {
|
||||||
const added = invItems.some(i => i.submission_id === r.id);
|
const added = invItems.some(i => i.submission_id === r.id);
|
||||||
const revisionQty = getRevisionChargeQuantity(r?.version_number);
|
const revisionQty = getRevisionChargeQuantity(r?.version_number, r?.revision_type);
|
||||||
const revisionServiceType = pickInitialServiceType(r.task?.submissions, r.service_type || r.task?.title || 'Revision');
|
const revisionServiceType = pickInitialServiceType(r.task?.submissions, r.service_type || r.task?.title || 'Revision');
|
||||||
const revisionPrice = invPriceList.find(p => p.service_type === revisionServiceType && p.price_type === 'revision');
|
const revisionPrice = invPriceList.find(p => p.service_type === revisionServiceType && p.price_type === 'revision');
|
||||||
const revisionLabel = revisionQty > 0 ? (revisionPrice ? `$${Number(revisionPrice.price).toFixed(2)}` : 'No price') : 'Free';
|
const revisionLabel = revisionQty > 0 ? (revisionPrice ? `$${Number(revisionPrice.price).toFixed(2)}` : 'No price') : 'Free';
|
||||||
|
|||||||
Reference in New Issue
Block a user