Edits history of script submission #22313 for ' Convert Lead (salesforce)'

  • bun
    One script reply has been approved by the moderators
    Ap­pro­ved
    //native
    
    export type DynSelect_converted_status = string
    
    // Dropdown of the org's "converted" lead statuses (LeadStatus where IsConverted = true).
    export async function converted_status(auth: RT.Salesforce) {
      const apiVersion = auth.api_version || "v60.0"
      const url = new URL(`${auth.instance_url}/services/data/${apiVersion}/query`)
      url.searchParams.append(
        "q",
        "SELECT MasterLabel FROM LeadStatus WHERE IsConverted = true"
      )
      const response = await fetch(url, {
        headers: {
          Authorization: `Bearer ${auth.token}`,
          Accept: "application/json",
        },
      })
      if (!response.ok) {
        throw new Error(`${response.status} ${await response.text()}`)
      }
      const { records } = (await response.json()) as {
        records: { MasterLabel: string }[]
      }
      return records.map((r) => ({ value: r.MasterLabel, label: r.MasterLabel }))
    }
    
    function xmlEscape(s: string) {
      return s
        .replace(/&/g, "&")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&apos;")
    }
    
    /**
     * Convert Lead
     * Convert a lead into an account, contact, and (optionally) an opportunity. Salesforce has no REST endpoint for this, so it uses the SOAP convertLead call with the same OAuth token. converted_status must be a lead status marked as converted.
     */
    export async function main(
      auth: RT.Salesforce,
      lead_id: string,
      converted_status: DynSelect_converted_status,
      options:
        | {
            accountId?: string
            contactId?: string
            opportunityName?: string
            doNotCreateOpportunity?: boolean
            ownerId?: string
            overwriteLeadSource?: boolean
            sendNotificationEmail?: boolean
          }
        | undefined
    ) {
      const soapVersion = (auth.api_version || "v60.0").replace(/^v/, "")
      const o = options ?? {}
      const optional = [
        o.accountId !== undefined
          ? `<urn:accountId>${xmlEscape(o.accountId)}</urn:accountId>`
          : "",
        o.contactId !== undefined
          ? `<urn:contactId>${xmlEscape(o.contactId)}</urn:contactId>`
          : "",
        o.opportunityName !== undefined
          ? `<urn:opportunityName>${xmlEscape(o.opportunityName)}</urn:opportunityName>`
          : "",
        o.doNotCreateOpportunity !== undefined
          ? `<urn:doNotCreateOpportunity>${o.doNotCreateOpportunity}</urn:doNotCreateOpportunity>`
          : "",
        o.ownerId !== undefined
          ? `<urn:ownerId>${xmlEscape(o.ownerId)}</urn:ownerId>`
          : "",
        o.overwriteLeadSource !== undefined
          ? `<urn:overwriteLeadSource>${o.overwriteLeadSource}</urn:overwriteLeadSource>`
          : "",
        o.sendNotificationEmail !== undefined
          ? `<urn:sendNotificationEmail>${o.sendNotificationEmail}</urn:sendNotificationEmail>`
          : "",
      ].join("")
    
      const envelope = `<?xml version="1.0" encoding="UTF-8"?>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com">
      <soapenv:Header><urn:SessionHeader><urn:sessionId>${auth.token}</urn:sessionId></urn:SessionHeader></soapenv:Header>
      <soapenv:Body><urn:convertLead><urn:leadConverts>
        <urn:leadId>${xmlEscape(lead_id)}</urn:leadId>
        <urn:convertedStatus>${xmlEscape(converted_status)}</urn:convertedStatus>
        ${optional}
      </urn:leadConverts></urn:convertLead></soapenv:Body>
    </soapenv:Envelope>`
    
      const response = await fetch(
        `${auth.instance_url}/services/Soap/u/${soapVersion}`,
        {
          method: "POST",
          headers: { "Content-Type": "text/xml; charset=UTF-8", SOAPAction: '""' },
          body: envelope,
        }
      )
      const text = await response.text()
      if (!response.ok) {
        throw new Error(`${response.status} ${text}`)
      }
    
      const pick = (tag: string) =>
        text.match(new RegExp(`<(?:\\w+:)?${tag}>(.*?)</(?:\\w+:)?${tag}>`))?.[1]
      if (pick("success") !== "true") {
        const message =
          text.match(/<faultstring>(.*?)<\/faultstring>/)?.[1] ??
          text.match(
            /<(?:\w+:)?errors>[\s\S]*?<(?:\w+:)?message>(.*?)<\/(?:\w+:)?message>/
          )?.[1] ??
          text
        throw new Error(`convertLead failed: ${message}`)
      }
    
      return {
        success: true,
        leadId: pick("leadId"),
        accountId: pick("accountId"),
        contactId: pick("contactId"),
        opportunityId: pick("opportunityId"),
      }
    }
    

    Submitted by hugo989 9 days ago