diff --git a/api/src/api/companies/[id]/fetch.ts b/api/src/api/companies/[id]/fetch.ts index 4d2bfba..7ba2ae4 100644 --- a/api/src/api/companies/[id]/fetch.ts +++ b/api/src/api/companies/[id]/fetch.ts @@ -20,8 +20,6 @@ export default createRoute( const includeAllContacts = c.req.query("includeAllContacts") === "true"; const includeAllAddresses = c.req.query("includeAllAddresses") === "true"; - console.log(company.toJson({ includeAddress, includePrimaryContact, includeAllContacts })); - // Check for address-specific permission if includeAddress is requested if (includeAddress) { const user = c.get("user"); diff --git a/api/src/api/credential-types/create.ts b/api/src/api/credential-types/create.ts index 46db160..5d347d2 100644 --- a/api/src/api/credential-types/create.ts +++ b/api/src/api/credential-types/create.ts @@ -35,8 +35,6 @@ export default createRoute( const data = schema.parse(body); - console.log("Creating Credential Type with data:", data); - const credentialType = await credentialTypes.create(data as any); const response = apiResponse.created( diff --git a/api/src/api/sales/[id]/fetch.ts b/api/src/api/sales/[id]/fetch.ts index 037666f..892767d 100644 --- a/api/src/api/sales/[id]/fetch.ts +++ b/api/src/api/sales/[id]/fetch.ts @@ -36,7 +36,10 @@ export default createRoute( if (includes.has("products")) { subResourcePromises.products = item .fetchProducts() - .then((products) => products.map((p) => p.toJson())); + .then((products) => { + const json = products.map((p) => p.toJson()); + return json; + }); } if (includes.has("quotes")) { subResourcePromises.quotes = generatedQuotes diff --git a/api/src/api/sales/opportunities/[id]/fetch.ts b/api/src/api/sales/opportunities/[id]/fetch.ts index fbbfa26..9a20168 100644 --- a/api/src/api/sales/opportunities/[id]/fetch.ts +++ b/api/src/api/sales/opportunities/[id]/fetch.ts @@ -39,7 +39,11 @@ export default createRoute( if (includes.has("products")) { subResourcePromises.products = item .fetchProducts() - .then((products) => products.map((p) => p.toJson())); + .then((products) => { + const json = products.map((p) => p.toJson()); + console.log(`[PRODUCTS_DEBUG] cwOpportunityId=${item.cwOpportunityId} count=${json.length}`, JSON.stringify(json, null, 2)); + return json; + }); } if (includes.has("quotes")) { const includeRegenData = c.req.query("includeRegenData") === "true"; diff --git a/api/src/api/sales/opportunities/[id]/workflow/dispatch.ts b/api/src/api/sales/opportunities/[id]/workflow/dispatch.ts index 5f26a15..5ad9532 100644 --- a/api/src/api/sales/opportunities/[id]/workflow/dispatch.ts +++ b/api/src/api/sales/opportunities/[id]/workflow/dispatch.ts @@ -116,15 +116,7 @@ export default createRoute( try { const identifier = c.req.param("identifier"); const body = await c.req.json(); - console.log( - "[Workflow Dispatch] Raw request body:", - JSON.stringify(body, null, 2), - ); const parsed = dispatchSchema.parse(body); - console.log( - "[Workflow Dispatch] Parsed payload:", - JSON.stringify(parsed.payload, null, 2), - ); const user = c.get("user"); // ── Resolve opportunity ──────────────────────────────────────────── diff --git a/api/src/api/sales/opportunities/[id]/workflow/history.ts b/api/src/api/sales/opportunities/[id]/workflow/history.ts index 1564596..1f809aa 100644 --- a/api/src/api/sales/opportunities/[id]/workflow/history.ts +++ b/api/src/api/sales/opportunities/[id]/workflow/history.ts @@ -182,9 +182,9 @@ export default createRoute( const memberRecords = allMemberIds.length ? await prisma.cwMember.findMany({ - where: { identifier: { in: allMemberIds } }, - select: { identifier: true, firstName: true, lastName: true, officeEmail: true }, - }) + where: { identifier: { in: allMemberIds } }, + select: { identifier: true, firstName: true, lastName: true, officeEmail: true }, + }) : []; const memberMap = new Map( diff --git a/api/src/controllers/OpportunityController.ts b/api/src/controllers/OpportunityController.ts index e4b5195..82c8d26 100644 --- a/api/src/controllers/OpportunityController.ts +++ b/api/src/controllers/OpportunityController.ts @@ -37,11 +37,11 @@ async function resolveMember(identifier: string | null | undefined) { }); return member ? { - id: member.id, - identifier: member.identifier, - name: `${member.firstName} ${member.lastName}`.trim(), - cwMemberId: member.cwMemberId, - } + id: member.id, + identifier: member.identifier, + name: `${member.firstName} ${member.lastName}`.trim(), + cwMemberId: member.cwMemberId, + } : { id: null, identifier, name: identifier, cwMemberId: null }; } @@ -193,8 +193,8 @@ export class OpportunityController { }); const resolvedName = user ? `${user.firstName ?? ""} ${user.lastName ?? ""}`.trim() || - user.login || - user.email + user.login || + user.email : null; const name = resolvedName ?? @@ -209,8 +209,8 @@ export class OpportunityController { constructor( data: Opportunity & { company?: - | (Company & { contacts?: any[]; companyAddresses?: any[] }) - | null; + | (Company & { contacts?: any[]; companyAddresses?: any[] }) + | null; primarySalesRep?: (User & { roles: Role[] }) | null; secondarySalesRep?: (User & { roles: Role[] }) | null; }, @@ -222,8 +222,6 @@ export class OpportunityController { activities?: ActivityController[]; } ) { - console.log(data.primarySalesRep); - // New schema: uid is the internal PK (string), id is the CW opportunity ID (Int) this.id = data.uid; this.cwOpportunityId = data.id; @@ -515,8 +513,8 @@ export class OpportunityController { const hasCwPatch = Object.keys(cwPatch).length > 0; const cwMapped = hasCwPatch ? OpportunityController.mapCwToDb( - await opportunityCw.update(this.cwOpportunityId, cwPatch) - ) + await opportunityCw.update(this.cwOpportunityId, cwPatch) + ) : {}; const mapped = @@ -692,10 +690,10 @@ export class OpportunityController { }, company: contact.company ? { - id: contact.company.id, - identifier: null, - name: contact.company.name, - } + id: contact.company.id, + identifier: null, + name: contact.company.name, + } : null, role: null, notes: null, @@ -711,10 +709,10 @@ export class OpportunityController { contact: ct.contact ? { id: ct.contact.id, name: ct.contact.name } : null, company: ct.company ? { - id: ct.company.id, - identifier: ct.company.identifier, - name: ct.company.name, - } + id: ct.company.id, + identifier: ct.company.identifier, + name: ct.company.name, + } : null, role: ct.role ? { id: ct.role.id, name: ct.role.name } : null, notes: ct.notes, @@ -827,6 +825,8 @@ export class OpportunityController { }, }); + console.log("[ROWS_DEBUG]", rows) + let ordered = rows; if (this.productSequence.length > 0) { const byId = new Map(rows.map((row) => [row.id, row])); @@ -1056,7 +1056,7 @@ export class OpportunityController { const quoteNarrativeField = options.includeQuoteNarrative ? this._customFields?.find((f) => f.id === 35)?.value?.toString() || - undefined + undefined : undefined; // Fall back to the customerDescription of a QUO-Narrative product @@ -1068,8 +1068,6 @@ export class OpportunityController { quoNarrativeProduct?.customerDescription ?? undefined; - console.log("[generateQuote] quoteNarrative:", quoteNarrative); - const companyLine = this.companyName ?? company?.name ?? "Customer Company"; // Only show attention if it differs from the customer name @@ -1264,11 +1262,11 @@ export class OpportunityController { companyName: this.companyName ?? company?.name ?? null, primaryContact: companyJson?.cw_Data?.primaryContact ? { - firstName: companyJson.cw_Data.primaryContact.firstName ?? null, - lastName: companyJson.cw_Data.primaryContact.lastName ?? null, - email: companyJson.cw_Data.primaryContact.email ?? null, - phone: companyJson.cw_Data.primaryContact.phone ?? null, - } + firstName: companyJson.cw_Data.primaryContact.firstName ?? null, + lastName: companyJson.cw_Data.primaryContact.lastName ?? null, + email: companyJson.cw_Data.primaryContact.email ?? null, + phone: companyJson.cw_Data.primaryContact.phone ?? null, + } : null, siteAddress: siteAddress.length > 0 ? siteAddress : null, companyAddress: companyAddress.length > 0 ? companyAddress : null, @@ -1820,13 +1818,13 @@ export class OpportunityController { const defaultAddr = this._company?.getDefaultAddress(); const companyAddress = defaultAddr ? { - line1: defaultAddr.addressLine1, - line2: defaultAddr.addressLine2, - city: defaultAddr.city, - state: defaultAddr.state, - zip: defaultAddr.zipCode, - country: defaultAddr.country ?? null, - } + line1: defaultAddr.addressLine1, + line2: defaultAddr.addressLine2, + city: defaultAddr.city, + state: defaultAddr.state, + zip: defaultAddr.zipCode, + country: defaultAddr.country ?? null, + } : null; return { @@ -1853,52 +1851,52 @@ export class OpportunityController { primarySalesRep: this.primarySalesRepIdentifier || this._primarySalesRep ? { - id: this.primarySalesRepCwId, - identifier: this.primarySalesRepIdentifier, - name: - this._primarySalesRep?.name ?? - this.primarySalesRepName ?? - this.primarySalesRepIdentifier, - ...(this._primarySalesRep - ? { user: this._primarySalesRep.toJson({ safeReturn: true }) } - : {}), - } + id: this.primarySalesRepCwId, + identifier: this.primarySalesRepIdentifier, + name: + this._primarySalesRep?.name ?? + this.primarySalesRepName ?? + this.primarySalesRepIdentifier, + ...(this._primarySalesRep + ? { user: this._primarySalesRep.toJson({ safeReturn: true }) } + : {}), + } : null, secondarySalesRep: this.secondarySalesRepIdentifier || this._secondarySalesRep ? { - id: this.secondarySalesRepCwId, - identifier: this.secondarySalesRepIdentifier, - name: - this._secondarySalesRep?.name ?? - this.secondarySalesRepName ?? - this.secondarySalesRepIdentifier, - ...(this._secondarySalesRep - ? { - user: this._secondarySalesRep.toJson({ - safeReturn: true, - }), - } - : {}), - } + id: this.secondarySalesRepCwId, + identifier: this.secondarySalesRepIdentifier, + name: + this._secondarySalesRep?.name ?? + this.secondarySalesRepName ?? + this.secondarySalesRepIdentifier, + ...(this._secondarySalesRep + ? { + user: this._secondarySalesRep.toJson({ + safeReturn: true, + }), + } + : {}), + } : null, company: this._company ? this._company.toJson({ - includeAllContacts: true, - includeAddress: true, - includePrimaryContact: false, - }) + includeAllContacts: true, + includeAddress: true, + includePrimaryContact: false, + }) : this.companyCwId - ? { id: this.companyCwId, name: this.companyName } - : null, + ? { id: this.companyCwId, name: this.companyName } + : null, contact: this.contactCwId ? { id: this.contactCwId, name: this.contactName } : null, site: this._siteData ? this._siteData : this.siteCwId - ? { id: this.siteCwId, name: this.siteName } - : null, + ? { id: this.siteCwId, name: this.siteName } + : null, customerPO: this.customerPO, totalSalesTax: this.totalSalesTax, expectedSalesTaxRate: diff --git a/api/src/modules/cw-utils/opportunities/cwProbabilityCache.ts b/api/src/modules/cw-utils/opportunities/cwProbabilityCache.ts index 3ac8c5a..7acf91e 100644 --- a/api/src/modules/cw-utils/opportunities/cwProbabilityCache.ts +++ b/api/src/modules/cw-utils/opportunities/cwProbabilityCache.ts @@ -12,20 +12,20 @@ import { connectWiseApi } from "../../../constants"; interface CWProbability { - id: number; - probability: number; + id: number; + probability: number; } let _cache: CWProbability[] | null = null; async function fetchProbabilities(): Promise { - if (_cache) return _cache; - const response = await connectWiseApi.get( - "/sales/probabilities", - { params: { pageSize: 1000 } } - ); - _cache = response.data; - return _cache; + if (_cache) return _cache; + const response = await connectWiseApi.get( + "/sales/probabilities", + { params: { pageSize: 1000 } } + ); + _cache = response.data; + return _cache; } /** @@ -35,29 +35,29 @@ async function fetchProbabilities(): Promise { * Returns null if the probabilities list is empty. */ export async function resolveCwProbabilityId( - percent: number + percent: number ): Promise { - const list = await fetchProbabilities(); - if (list.length === 0) return null; + const list = await fetchProbabilities(); + if (list.length === 0) return null; - // Exact match - const exact = list.find((p) => p.probability === percent); - if (exact) return exact.id; + // Exact match + const exact = list.find((p) => p.probability === percent); + if (exact) return exact.id; - // Closest match - let closest = list[0]!; - let minDiff = Math.abs(closest.probability - percent); - for (const option of list) { - const diff = Math.abs(option.probability - percent); - if (diff < minDiff) { - minDiff = diff; - closest = option; + // Closest match + let closest = list[0]!; + let minDiff = Math.abs(closest.probability - percent); + for (const option of list) { + const diff = Math.abs(option.probability - percent); + if (diff < minDiff) { + minDiff = diff; + closest = option; + } } - } - return closest.id; + return closest.id; } /** Clear the cache (useful for tests or forced refresh). */ export function clearCwProbabilityCache(): void { - _cache = null; + _cache = null; } diff --git a/ui/src/components/InventoryPopover.svelte b/ui/src/components/InventoryPopover.svelte index 638c348..381dd82 100644 --- a/ui/src/components/InventoryPopover.svelte +++ b/ui/src/components/InventoryPopover.svelte @@ -6,7 +6,8 @@ export let onHand: number | undefined; // Warehouse IDs for the fixed locations - const MURRAY_ID = 1; + // Murray = Andrus 301 (1) + Andrus-205C (26) + Andrus 205D (27) + const MURRAY_IDS = new Set([1, 26, 27]); const UNION_CITY_ID = 6; const LONDON_ID = 30; @@ -56,7 +57,7 @@ for (const row of rows) { const wId = row.warehouseId; const wName = row.warehouse?.name ?? ""; - if (wId === MURRAY_ID) { + if (wId != null && MURRAY_IDS.has(wId)) { result.murray += row.qtyOnHand; } else if (wId === UNION_CITY_ID) { result.unionCity += row.qtyOnHand; diff --git a/ui/src/components/NoResultsMonkey.svelte b/ui/src/components/NoResultsMonkey.svelte index 8c02c1d..b6ea76d 100644 --- a/ui/src/components/NoResultsMonkey.svelte +++ b/ui/src/components/NoResultsMonkey.svelte @@ -3,64 +3,15 @@ export let size: number = 160; -
- -
{message}
+
+

{message}

diff --git a/ui/src/routes/sales/opportunity/[id]/components/ProductsTab.svelte b/ui/src/routes/sales/opportunity/[id]/components/ProductsTab.svelte index c15d2f5..15a1706 100644 --- a/ui/src/routes/sales/opportunity/[id]/components/ProductsTab.svelte +++ b/ui/src/routes/sales/opportunity/[id]/components/ProductsTab.svelte @@ -8,7 +8,6 @@ import { optima } from "$lib"; import NoResultsMonkey from "../../../../../components/NoResultsMonkey.svelte"; import AddProductModal from "../../../../../components/AddProductModal.svelte"; - import InventoryPopover from "../../../../../components/InventoryPopover.svelte"; import type { CatalogItem } from "$lib/optima-api/modules/procurement"; import type { AddProductBody, @@ -2557,12 +2556,7 @@
On Hand - {#if selectedProduct.catalogItem} - - {:else if selectedProduct.onHand != null} + {#if selectedProduct.onHand != null}