fix(sales): wire missing berth-rule triggers + portal company-billed invoices
- G-C4: deposit_received in invoices.ts - G-C4 + G-I2: interest_archived + notifyNextInLine in archiveInterest - G-C4: interest_completed in setInterestOutcome - G-C4: berth_unlinked in removeInterestBerth - G-I5: portal invoices include billingEntityType='company' when client is the director Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { and, eq, count, inArray, isNull, desc, sql } from 'drizzle-orm';
|
||||
import { and, eq, count, inArray, isNull, desc, or, sql } from 'drizzle-orm';
|
||||
|
||||
import { db } from '@/lib/db';
|
||||
import { clients } from '@/lib/db/schema/clients';
|
||||
@@ -248,22 +248,58 @@ export async function getClientInvoices(
|
||||
.filter((c) => c.channel === 'email')
|
||||
.map((c) => c.value.toLowerCase());
|
||||
|
||||
if (emailContacts.length === 0) return [];
|
||||
// G-I5: the most common B2B pattern is "individual client buys through their
|
||||
// company" — those invoices ship with billingEntityType='company' and the
|
||||
// portal user (client) is just a director of that company. Filtering on
|
||||
// billingEmail alone hides these invoices. Resolve director memberships
|
||||
// through company_memberships (role='director', active = endDate IS NULL)
|
||||
// and OR them into the predicate.
|
||||
const directorMemberships = await db
|
||||
.select({ companyId: companyMemberships.companyId })
|
||||
.from(companyMemberships)
|
||||
.innerJoin(companies, eq(companyMemberships.companyId, companies.id))
|
||||
.where(
|
||||
and(
|
||||
eq(companyMemberships.clientId, clientId),
|
||||
eq(companyMemberships.role, 'director'),
|
||||
isNull(companyMemberships.endDate),
|
||||
eq(companies.portId, portId),
|
||||
),
|
||||
);
|
||||
const directorCompanyIds = directorMemberships.map((m) => m.companyId);
|
||||
|
||||
// Fetch only the invoices matching any of the client's email addresses.
|
||||
// Without the inArray push-down here every portal invoice page-load
|
||||
// full-scanned the invoices table and filtered in JS — by 12mo it would
|
||||
// have been the worst portal endpoint in the platform. Defensive limit
|
||||
// 100 caps the upper bound for clients with abnormally many invoices.
|
||||
// If the portal user has neither billing emails on file nor any active
|
||||
// director memberships, there's nothing this query could return.
|
||||
if (emailContacts.length === 0 && directorCompanyIds.length === 0) return [];
|
||||
|
||||
// Build the OR predicate: (billingEmail ∈ client emails) OR
|
||||
// (billingEntityType='company' AND billingEntityId ∈ director company ids).
|
||||
const emailPredicate =
|
||||
emailContacts.length > 0
|
||||
? inArray(sql`lower(${invoices.billingEmail})`, emailContacts)
|
||||
: undefined;
|
||||
const companyPredicate =
|
||||
directorCompanyIds.length > 0
|
||||
? and(
|
||||
eq(invoices.billingEntityType, 'company'),
|
||||
inArray(invoices.billingEntityId, directorCompanyIds),
|
||||
)
|
||||
: undefined;
|
||||
const matchPredicate =
|
||||
emailPredicate && companyPredicate
|
||||
? or(emailPredicate, companyPredicate)
|
||||
: (emailPredicate ?? companyPredicate);
|
||||
|
||||
// Fetch only the invoices matching any of the client's email addresses or
|
||||
// company memberships. Without the predicate push-down here every portal
|
||||
// invoice page-load full-scanned the invoices table and filtered in JS —
|
||||
// by 12mo it would have been the worst portal endpoint in the platform.
|
||||
// Defensive limit 100 caps the upper bound for clients with abnormally many
|
||||
// invoices.
|
||||
const clientInvoices = await db
|
||||
.select()
|
||||
.from(invoices)
|
||||
.where(
|
||||
and(
|
||||
eq(invoices.portId, portId),
|
||||
inArray(sql`lower(${invoices.billingEmail})`, emailContacts),
|
||||
),
|
||||
)
|
||||
.where(and(eq(invoices.portId, portId), matchPredicate))
|
||||
.orderBy(invoices.createdAt)
|
||||
.limit(100);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user