我是新手,我正在为我的宠物项目购买咖啡功能。我设法让它发挥作用。虽然只有一个小问题,但是没有它,所有的东西都是无用的。我无法向服务器发送动态数据来更改金额。
所以基本来说,父组件发送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()}} 我在控制台中收到错误:
请指教。我真的能找到解决方案。
这是服务器端代码:
-----------------------------------------------------------------------------
//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
我认为您误解了如何使用
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