React Paypal 按钮实现问题

问题描述 投票:0回答:1

我是新手,我正在为我的宠物项目购买咖啡功能。我设法让它发挥作用。虽然只有一个小问题,但是没有它,所有的东西都是无用的。我无法向服务器发送动态数据来更改金额。

所以基本来说,父组件发送donationID,并且在服务器中存在将id与金额匹配的对象。

const [donationID, setDonationID] = React.useState(4)

 <PayPalBtn donationID={donationID} />

子组件使用 createOrder={createOrder} 创建 PayPal 按钮,该按钮采用初始捐赠 ID,仅此而已。 当父组件中的donationID发生变化时,子组件会收到它,但createOrder仍然具有初始的donationID。

-----------------------------------------------------------------------------
//client, react
-----------------------------------------------------------------------------
import React from 'react'
import { PayPalScriptProvider, PayPalButtons } from "@paypal/react-paypal-js";
import axios from 'axios'

const PayPalBtn = ({ donationID }) => {

    
    
    const initialOptions = {
        clientId: 'AXixNLXOMPeVQGE-n6UhHwbwJADrQcqbDNcSvsemWs3egX876DDUL1BEiqoNeo9NFlXySo0juLrV1lAxA'
    }

    const createOrder = async () => {
        
        try {
            const response = await axios.post("http://localhost:4000/api/orders", {
                cart: [
                    {
                        id: donationID,
                        quantity: 1,
                    },
                ],
            }, {
                headers: {
                    "Content-Type": "application/json",
                },
            });

            const orderData = response.data;

            if (orderData.id) {
                return orderData.id;
            } else {
                const errorDetail = orderData?.details?.[0];
                const errorMessage = errorDetail
                    ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})`
                    : JSON.stringify(orderData);

                throw new Error(errorMessage);
            }
        } catch (error) {
            console.error(error);
            resultMessage(`Could not initiate PayPal Checkout...<br><br>${error}`);
        }
    }

    const onApprove = async (data, actions) => {
        try {
            const response = await axios.post(`http://localhost:4000/api/orders/${data.orderID}/capture`, {}, {
                headers: {
                    "Content-Type": "application/json",
                },
            });

            const orderData = response.data;

            const errorDetail = orderData?.details?.[0];

            if (errorDetail?.issue === "INSTRUMENT_DECLINED") {
                
                return actions.restart();
            } else if (errorDetail) {
                
                throw new Error(`${errorDetail.description} (${orderData.debug_id})`);
            } else if (!orderData.purchase_units) {
                throw new Error(JSON.stringify(orderData));
            } else {
                
                const transaction =
                    orderData?.purchase_units?.[0]?.payments?.captures?.[0] ||
                    orderData?.purchase_units?.[0]?.payments?.authorizations?.[0];

                    if (transaction.status === 'COMPLETED') {
                        
                        console.log(transaction)
                        
                    } else {
                        console.log(
                            `Problem. Status transakcije: ${transaction.status}. Broj transakcije: ${transaction.id}.`,
                        );
                    }


                
                console.log(
                    "Capture result",
                    orderData,
                    JSON.stringify(orderData, null, 2),
                );
            }
        } catch (error) {
            console.error(error);
            console.log(
                `Oprostite, Vaša transakcija ne može biti procesirana... ${error}`,
            );
        }
    }

    return (
        <div>
           
            <PayPalScriptProvider options={initialOptions}>
                <PayPalButtons
                    style={{ layout: "horizontal" }}
                    createOrder={createOrder}
                    onApprove={(data, actions) => { onApprove(data, actions) }}
                />
            </PayPalScriptProvider>
        </div>
    )
}

export default PayPalBtn

也许createOrder必须是这样的:createOrder={() => {createOrder()}}而不是createOrder={createOrder}来获取“新鲜”的donationID,但是当我这样构造它时:createOrder={() => { createOrder()}} 我在控制台中收到错误:

“未捕获错误:期望传递订单 ID 在 https://www.sandbox.paypal.com/smart/buttons?style.layout=horizontal&style.color=gold&style.shape=rect&style.tagline=true&style.menuPlacement=below&sdkVersion=5.0.397&components.0=buttons&locale.lang= en&locale.country=US&sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwY..."

请指教。我真的能找到解决方案。

这是服务器端代码:

-----------------------------------------------------------------------------
//server, node
-----------------------------------------------------------------------------
const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT } = process.env;
const base = "https://api-m.sandbox.paypal.com";

const amountToPay = {
  1: 1,
  2: 2,
  3: 3,
  4: 5,
  5: 10
}

const generateAccessToken = async () => {
  try {
    if (!PAYPAL_CLIENT_ID || !PAYPAL_CLIENT_SECRET) {
      throw new Error("MISSING_API_CREDENTIALS");
    }
    const auth = Buffer.from(
      PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET,
    ).toString("base64");
    const response = await fetch(`${base}/v1/oauth2/token`, {
      method: "POST",
      body: "grant_type=client_credentials",
      headers: {
        Authorization: `Basic ${auth}`,
      },
    });

    const data = await response.json();
    return data.access_token;
  } catch (error) {
    console.error("Failed to generate Access Token:", error);
  }
};

const createOrder = async (cart) => {
  // use the cart information passed from the front-end to calculate the purchase unit details
  console.log(
    "shopping cart information passed from the frontend createOrder() callback:",
    cart,
  );

  const accessToken = await generateAccessToken();
  const url = `${base}/v2/checkout/orders`;
  const amountToSend = `${amountToPay[cart[0].id]}.00`
  const payload = {
    intent: "CAPTURE",
    purchase_units: [
      {
        amount: {
          currency_code: "USD",
          value: amountToSend,
        },
      },
    ],
  };

  const response = await fetch(url, {
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${accessToken}`,
    },
    method: "POST",
    body: JSON.stringify(payload),
  });

  return handleResponse(response);
};


const captureOrder = async (orderID) => {
  const accessToken = await generateAccessToken();
  const url = `${base}/v2/checkout/orders/${orderID}/capture`;

  const response = await fetch(url, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${accessToken}`,
    },
  });

  return handleResponse(response);
};

async function handleResponse(response) {
  try {
    const jsonResponse = await response.json();
    return {
      jsonResponse,
      httpStatusCode: response.status,
    };
  } catch (err) {
    const errorMessage = await response.text();
    throw new Error(errorMessage);
  }
}

app.use(express.json())


app.post("/api/orders", async (req, res) => {
  try {
    const { cart } = req.body;
    const { jsonResponse, httpStatusCode } = await createOrder(cart);
    res.status(httpStatusCode).json(jsonResponse);
  } catch (error) {
    console.error("Failed to create order:", error);
    res.status(500).json({ error: "Failed to create order." });
  }
});

app.post("/api/orders/:orderID/capture", async (req, res) => {

  try {
    const { orderID } = req.params;
    const { jsonResponse, httpStatusCode } = await captureOrder(orderID);
    res.status(httpStatusCode).json(jsonResponse);
  } catch (error) {
    console.error("Failed to create order:", error);
    res.status(500).json({ error: "Failed to capture order." });
  }
});

另外,我注意到带有说明的自述文件已从 npm 包中删除,所以也许这就是它“不起作用”的原因,因为会有包更新? https://www.npmjs.com/package/@paypal/react-paypal-js

javascript node.js reactjs paypal
1个回答
0
投票

我认为您误解了如何使用

PayPalButton
@paypal/react-paypal-js
组件,您应该实际使用 Paypal 创建订单,然后它返回一个已解决的
orderId
承诺,您应该将其传回 Paypal .

createOrder
道具应该是这样的

createOrder={function (data, actions) {
    return actions.braintree
        .createPayment({
            flow: "checkout",
            amount: amount, // Here change the amount if needed
            currency: "USD", // Here change the currency if needed
            intent: "capture",
            enableShippingAddress: true,
            shippingAddressEditable: false,
            shippingAddressOverride: {
                recipientName: "Scruff McGruff",
                line1: "1234 Main St.",
                line2: "Unit 1",
                city: "Chicago",
                countryCode: "US",
                postalCode: "60652",
                state: "IL",
                phone: "123.456.7890",
            },
        })
        .then((orderId) => {
            // Your code here after create the order
            return orderId;
        });

如您所见,您需要准备好这些信息,以便在 Paypal 向您返回 Paypal 按钮之前向 Paypal 检查有效负载是否有效。

有相当多的配置需要到位,但这是如何在您的应用程序中正确实现 Paypal 的高级配置。

可以在这里查看一个非常有用的资源:https://paypal.github.io/react-paypal-js/?path=/docs/braintree-braintreepaypalbuttons--default

createOrder
的Paypal JS SDK文档解释了哪些必填字段以及如何获取它们https://developer.paypal.com/sdk/js/reference/#createorder

© www.soinside.com 2019 - 2024. All rights reserved.