Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js react和paypal rest sdk:如何将数据从支付页面传递回应用程序_Node.js_Reactjs_Paypal_Axios - Fatal编程技术网

Node.js react和paypal rest sdk:如何将数据从支付页面传递回应用程序

Node.js react和paypal rest sdk:如何将数据从支付页面传递回应用程序,node.js,reactjs,paypal,axios,Node.js,Reactjs,Paypal,Axios,我有一个React单页应用程序,允许用户通过paypal rest sdk(文档)购买保存的产品。我希望这样做的方式是让登录用户能够订购有库存的产品。用户输入他们想要的产品数量,然后创建包含产品和数量的订单,并将其存储为“created”。然后,用户将被重定向到Paypal购买页面,在那里他们确认或取消付款。在确认之前创建的订单后,将再次找到并设置为“已完成”,并创建一个用于存储贝宝支付信息的交易。目前,我可以在沙箱环境中成功完成付款、订单和交易 我现在的问题是,我用来进出Paypal支付页面的

我有一个React单页应用程序,允许用户通过paypal rest sdk(文档)购买保存的产品。我希望这样做的方式是让登录用户能够订购有库存的产品。用户输入他们想要的产品数量,然后创建包含产品和数量的订单,并将其存储为“created”。然后,用户将被重定向到Paypal购买页面,在那里他们确认或取消付款。在确认之前创建的订单后,将再次找到并设置为“已完成”,并创建一个用于存储贝宝支付信息的交易。目前,我可以在沙箱环境中成功完成付款、订单和交易

我现在的问题是,我用来进出Paypal支付页面的重定向导致我的应用程序忘记了登录的用户,因此我无法在成功支付后获得用户的“创建”订单。我必须在postOrder()函数中使用window.location,否则会出现交叉引用错误,正如用户在回答我的问题时所解释的那样。我需要记住用户,否则任何标记为“已创建”的订单都可能被抓取并设置为“已完成”,不用说,这将在我的应用程序中造成大量问题。我应该如何解决这个问题,还是应该尝试另一种方法

前端逻辑:

import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { useID, useUserName, useAdmin } from "../../context/auth";
import { Button, Accordion, Card, ListGroup, Form, Col } from "react-bootstrap";
import axios from "axios";

function ProductDetails(props) {
    const [isError, setIsError] = useState(false);
    const [id, setID] = useState("");
    const [name, setName] = useState("");
    const [description, setDescription] = useState("");
    const [price, setPrice] = useState(0);
    const [stock, setStock] = useState(0);
    const [amount, setAmount] = useState(0);
    const [messages, setMessages] = useState([]);
    const { IDTokens } = useID();
    const { userNameTokens } = useUserName();
    const { adminTokens } = useAdmin();

    const Message = props => (
        <Card>
            <Card.Body>
                <Card.Title>
                    {props.message.owner.username === "(User removed)" ? (
                        <span>{props.message.owner.username}</span>
                    ) : (
                        <Link to={`/users/${props.message.owner.id}`}>{props.message.owner.username}</Link>                        
                    )}
                </Card.Title>
                <Card.Text>
                    {props.message.content}
                </Card.Text>
                {IDTokens === props.message.owner.id || adminTokens ? (
                    <span>
                        <Link  to={`/products/list/${id}/messages/${props.message._id}/edit/`} style={{ marginRight: 10, marginLeft: 10 }}>
                            Edit
                        </Link>
                        <Link to={`/products/list/${id}/messages/${props.message._id}/delete/`}>Delete</Link>
                    </span>
                ) : (
                    <span></span>
                )}
            </Card.Body>
        </Card>
    )

    useEffect(() => {
        axios.get(`http://localhost:4000/products/${props.match.params.id}`)
        .then(res => {
            setID(res.data.product._id);
            setName(res.data.product.name);
            setDescription(res.data.product.description);
            setPrice(res.data.product.price);
            setStock(res.data.product.stock);
            setMessages(res.data.messages);
        }).catch(function(err) {
            setIsError(true);
        })
    }, [props, IDTokens]);

    function messageList() {
        return messages.map(function(currentMessage, i) {
            return <Message message={currentMessage} key={i} />;
        })
    }

    function postOrder() {
        if(amount <= stock) {
            let productInfo = {
                id,
                name,
                description,
                price,
                amount
            };

            let orderInfo = {
                owner: {
                    id: IDTokens,
                    username: userNameTokens
                },
                status: "Created"
            };

            axios.post("http://localhost:4000/orders/pay",
                {productInfo, orderInfo}
            ).then((res) => {
                if(res.status === 200) {
                    window.location = res.data.forwardLink;
                } else {
                    setIsError(true);
                }
            }).catch((err) => {
                setIsError(true);
            })
        }
    }

    return (
        <div className="text-center">
            <h2>Products Details</h2>
            <Accordion>
                <Card>
                    <Card.Header>
                        <Accordion.Toggle as={Button} variant="link" eventKey="0">
                            Product Info
                        </Accordion.Toggle>
                    </Card.Header>
                    <Accordion.Collapse eventKey="0">
                        <Card.Body>
                            <ListGroup>
                                <ListGroup.Item>Name: {name}</ListGroup.Item>
                                <ListGroup.Item>Description: {description}</ListGroup.Item>
                                <ListGroup.Item>Price: ${price.toFixed(2)}</ListGroup.Item>
                                <ListGroup.Item>Stock: {stock}</ListGroup.Item>
                            </ListGroup>
                            {stock > 0 && IDTokens ? (
                                <Form>
                                    <h2>Order This Product</h2>
                                    <Form.Row>
                                        <Form.Group as={Col} sm={{ span: 6, offset: 3 }}>
                                            <Form.Label htmlFor="formAmount">Amount</Form.Label>
                                            <Form.Control
                                                        controlid="formAmount"
                                                        type="number"
                                                        min="1"
                                                        max="5"
                                                        step="1"
                                                        onChange={e => {
                                                            setAmount(e.target.value);
                                                        }}
                                                        placeholder="Enter amount to order (max 5)"
                                                        />
                                        </Form.Group>
                                    </Form.Row>
                                    <Button onClick={postOrder} variant="success">Order Now</Button>
                                    { isError &&<p>Something went wrong with making the order!</p> }
                                </Form>
                            ) : (
                                "Cannot order, currently out of stock or user is not currently logged in"
                            )}
                        </Card.Body>
                    </Accordion.Collapse>
                </Card>
            </Accordion>
            <Link to={`/products/list/${id}/messages/new`}>Questions or Comments Regarding this Product? Leave a Message.</Link>
            <h3>Messages: </h3>
            {messages.length > 0 ? (
                messageList()
            ) : (
                <p>(No messages)</p>
            )}
            { isError &&<p>Something went wrong with getting the product!</p> }
        </div>
    )
}

export default ProductDetails;
const express = require("express"),
router = express.Router(),
paypal = require("paypal-rest-sdk"),
Order = require("../database/models/order"),
Transaction = require("../database/models/transaction");

// Order pay logic route
router.post("/pay", function(req, res) {
    const productInfo = req.body.productInfo;

    const create_payment_json = {
        "intent": "sale",
        "payer": {
            "payment_method": "paypal"
        },
        "redirect_urls": {
            "return_url": "http://localhost:4000/orders/success",
            "cancel_url": "http://localhost:4000/orders/cancel"
        },
        "transactions": [{
            "item_list": {
                "items": [{
                    "name": productInfo.name,
                    "sku": "001",
                    "price": productInfo.price,
                    "currency": "USD",
                    "quantity": productInfo.amount
                }]
            },
            "amount": {
                "currency": "USD",
                "total": productInfo.price * productInfo.amount
            },
            "description": productInfo.description
        }]
    };

    paypal.payment.create(create_payment_json, function(err, payment) {
        if(err) {
            console.log(err.message);
        } else {
            let order = new Order(req.body.orderInfo);
            order.product = {
                _id: productInfo.id,
                name: productInfo.name,
                description: productInfo.description,
                price: productInfo.price,
                amount: productInfo.amount
            }
            order.total = productInfo.price * productInfo.amount;
            order.save().then(order => {
                console.log(`Order saved successfully! Created order details: ${order}`);
            }).catch(err => {
                console.log("Order create error: ", err.message);
            });

            for(let i = 0; i < payment.links.length; i++) {
              if(payment.links[i].rel === "approval_url") {
                  res.status(200).json({forwardLink: payment.links[i].href});
              } else {
                  console.log("approval_url not found");
              }
            }
        }
      });
});

router.get("/success", function(req, res) {
    const payerId = req.query.PayerID;
    const paymentId = req.query.paymentId;

    Order.findOneAndUpdate({ "owner.id": req.user, status: "Created" }).then((order) => {
        order.status = "Completed";

        const execute_payment_json = {
            "payer_id": payerId,
            "transactions": [{
                "amount": {
                    "currency": "USD",
                    "total": order.total
                }
            }]
        };

        paypal.payment.execute(paymentId, execute_payment_json, function(err, payment) {
            if(err) {
                console.log("paypal.payment.execute error: ", err.response);
            } else {
                let transaction = new Transaction();
                transaction.details = JSON.stringify(payment);
                order.transaction = transaction;
                order.save().then(order => {
                    transaction.save().then(transaction => {
                        res.status(200).json(`Payment accepted! Order details: ${order}`);
                    }).catch(err => {
                        console.log("Transaction create error: ", err.message);
                    });
                }).catch(err => {
                    console.log("Order complete error: ", err.message);
                });
            }
        });
    }).catch(err => {
        console.log("Payment error: ", err.message);
    });
});

module.exports = router;
交易模型:

const mongoose = require("mongoose"),
Schema = mongoose.Schema;

let transactionSchema = new Schema({
    details: [],
    createdAt: {
        type: Date,
        default: Date.now()
    }
});

module.exports = mongoose.model("Transaction", transactionSchema);

你为什么要重定向到贝宝和从贝宝

最好的解决方案是切换到此前端模式,而不是重定向:

这些fetch“/demo/…”需要替换为服务器上的路由,以分别创建订单、返回订单ID和捕获订单ID

这里的好处是您的站点在后台保持开放,提供“上下文”结帐体验


如果您想了解体验,请尝试客户端JS only版本,该版本不依赖于到那些“/demo/…”占位符的工作获取路由:

const mongoose = require("mongoose"),
Schema = mongoose.Schema;

let transactionSchema = new Schema({
    details: [],
    createdAt: {
        type: Date,
        default: Date.now()
    }
});

module.exports = mongoose.model("Transaction", transactionSchema);