Edits history of script submission #23752 for ' Refund Order (shopify)'

  • bunnative
    One script reply has been approved by the moderators
    Ap­pro­ved
    //native
    
    /**
     * Refund Order
     * Refund line items and/or shipping on an order. The amount is computed from the chosen items (plus shipping) and refunded to the original payment method. restock_type is RETURN (back to stock at location_id), CANCEL (unfulfilled items) or NO_RESTOCK.
     */
    export async function main(
      auth: RT.Shopify,
      order_id: string,
      line_items:
        | {
            line_item_id: string
            quantity: number
            restock_type?: "RETURN" | "CANCEL" | "NO_RESTOCK"
            location_id?: string
          }[]
        | undefined,
      full_shipping_refund: boolean | undefined,
      shipping_amount: number | undefined,
      note: string | undefined,
      notify: boolean | undefined
    ) {
      const orderId = order_id.startsWith("gid://")
        ? order_id
        : `gid://shopify/Order/${order_id}`
      const gid = (value: string, type: string) =>
        value.startsWith("gid://") ? value : `gid://shopify/${type}/${value}`
    
      const endpoint = `https://${auth.store_name}.myshopify.com/admin/api/2026-10/graphql.json`
      const headers = {
        "X-Shopify-Access-Token": auth.token,
        "Content-Type": "application/json",
        Accept: "application/json",
      }
      const refundLineItems = line_items?.length
        ? line_items.map((item) => ({
            lineItemId: gid(item.line_item_id, "LineItem"),
            quantity: item.quantity,
            restockType: item.restock_type || "NO_RESTOCK",
            locationId: item.location_id
              ? gid(item.location_id, "Location")
              : undefined,
          }))
        : undefined
      const shipping = full_shipping_refund
        ? { fullRefund: true }
        : shipping_amount
          ? { amount: shipping_amount }
          : undefined
    
      // Let Shopify compute the refundable amount and the parent transactions to refund against.
      const suggestedResponse = await fetch(endpoint, {
        method: "POST",
        headers,
        body: JSON.stringify({
          query: `query ($id: ID!, $refundLineItems: [RefundLineItemInput!], $shippingAmount: Money, $refundShipping: Boolean) { order(id: $id) { suggestedRefund(refundLineItems: $refundLineItems, shippingAmount: $shippingAmount, refundShipping: $refundShipping) { suggestedTransactions { gateway kind amountSet { shopMoney { amount } } parentTransaction { id } } } } }`,
          variables: {
            id: orderId,
            refundLineItems,
            shippingAmount: shipping?.amount,
            refundShipping: shipping?.fullRefund,
          },
        }),
      })
      if (!suggestedResponse.ok) {
        throw new Error(
          `${suggestedResponse.status} ${await suggestedResponse.text()}`
        )
      }
      const suggested = await suggestedResponse.json()
      if (suggested.errors) {
        throw new Error(JSON.stringify(suggested.errors))
      }
      const transactions =
        suggested.data.order.suggestedRefund.suggestedTransactions.map(
          (t: any) => ({
            orderId,
            parentId: t.parentTransaction?.id,
            gateway: t.gateway,
            kind: "REFUND",
            amount: t.amountSet.shopMoney.amount,
          })
        )
    
      const response = await fetch(endpoint, {
        method: "POST",
        headers,
        body: JSON.stringify({
          query: `mutation ($input: RefundInput!, $idempotencyKey: String!) { refundCreate(input: $input) @idempotent(key: $idempotencyKey) { refund { id legacyResourceId createdAt note totalRefundedSet { shopMoney { amount currencyCode } } } order { id name displayFinancialStatus totalRefundedSet { shopMoney { amount currencyCode } } } userErrors { field message } } }`,
          variables: {
            input: {
              orderId,
              refundLineItems,
              shipping,
              transactions,
              note: note || undefined,
              notify: notify || false,
            },
            // Required on refundCreate since 2026-04; a fresh key per run (no automatic retries here).
            idempotencyKey: crypto.randomUUID(),
          },
        }),
      })
    
      if (!response.ok) {
        throw new Error(`${response.status} ${await response.text()}`)
      }
    
      const { data, errors } = await response.json()
      if (errors) {
        throw new Error(JSON.stringify(errors))
      }
    
      if (data.refundCreate.userErrors.length) {
        throw new Error(JSON.stringify(data.refundCreate.userErrors))
      }
    
      return data.refundCreate
    }
    

    Submitted by hugo989 3 hours ago