Paystack支付集成成功支付但从nextjs中的put api返回404错误

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

我有一个正在运行的电子商务网站,其他支付平台的集成运行良好。然而,尝试集成 paystack 时遇到了一些错误,即使经过大量故障排除,我似乎也找不到问题出在哪里。

我需要 paystack 与其他网站一样功能,因为这个电子商务网站主要是针对尼日利亚的客户而设置的,我们需要能够使用他们的本地卡接受付款。付款的 onSuccess 组件在 paystack-public-key 设置下工作得很好,但它不会更新订单数据库,表明付款成功,并且还会返回带有标头的 404 错误

Request URL: http://localhost:3000/api/order/6626ea44b7683aa864d92837/pay
Request Method: PUT
Status Code: 404 Not Found

我在单页reactjs电子商务中使用了相同的付款方式,效果非常好,但我不知道为什么它在这个nextjs项目中没有做同样的事情。以下是为此设置的相关代码页。请查看并帮助谢谢。

/pages/order/[id].js

import styles from "@/styles/order.module.scss";
import Header from "@/components/header";
import Order from "@/models/Order";
import User from "@/models/user";
import { IoIosArrowForward } from "react-icons/io";
import db from "@/utils/db";
import { PayPalButtons, usePayPalScriptReducer } from "@paypal/react-paypal-js";
import { useReducer, useEffect } from "react";
import axios from "axios";
import { PaystackButton } from "react-paystack";
import { toast } from "react-toastify";

function reducer(state, action) {
  switch (action.type) {
    case "PAY_REQUEST":
      return { ...state, loading: true };
    case "PAY_SUCCESS":
      return { ...state, loading: false, success: true };
    case "PAY_FAIL":
      return { ...state, loading: false, error: action.payload };
    case "PAY_RESET":
      return { ...state, loading: false, success: false, error: false };
  }
}
export default function order({
  orderData,
  paypal_client_id,
  country,
}) {
  const [{ isPending }, paypalDispatch] = usePayPalScriptReducer();
  const [dispatch] = useReducer(reducer, {
    loading: true,
    error: "",
    success: "",
  });
  console.log({ orderData });

  useEffect(() => {
    if (!orderData._id) {
      dispatch({
        type: "PAY_RESET",
      });
    } else {
      paypalDispatch({
        type: "resetOptions",
        value: {
          "client-id": paypal_client_id,
          currency: "USD",
        },
      });
      paypalDispatch({
        type: "setLoadingStatus",
        value: "pending",
      });
    }
  }, [order]);
  function createOrderHanlder(data, actions) {
    return actions.order
      .create({
        purchase_units: [
          {
            amount: {
              value: orderData.total / 550,
            },
          },
        ],
      })
      .then((order_id) => {
        return order_id;
      });
  }
  function onApproveHandler(data, actions) {
    return actions.order.capture().then(async function (details) {
      try {
        dispatch({ type: "PAY_REQUEST" });
        const { data } = await axios.put(
          `/api/order/${orderData._id}/pay`,
          details
        );
        dispatch({ type: "PAY_SUCCESS", payload: data });
      } catch (error) {
        dispatch({ type: "PAY_ERROR", payload: error });
      }
    });
  }
  function onErroHandler(error) {
    console.log(error);
  }
  const componentProps = {
    reference: new Date().getTime().toString(),
    email: orderData.user.email,
    amount: orderData.total * 100, //Amount is in the country's lowest currency. E.g Kobo, so 20000 kobo = N200
    currency: "NGN",
    publicKey: process.env.PAYSTACK_PUBLIC_KEY,
    text: "Proceed To Pay",
    onSuccess: () => {
      try {
        const { data } = axios.put(`/api/order/${orderData._id}/pay`, {
          orderData,
        });
        console.log(data, "paid successfully");
        window.location.reload(false);
        toast.success("Order is paid");
      } catch (err) {
        toast.error(getError(err));
      }
    },
    onClose: () =>
      toast.error("We are sorry you have to leave, come back soon!"),
  };
  return (
    <>
      <Header country={country} />
      <div className={styles.order}>
        <div className={styles.container}>
          <div className={styles.order__infos}>
            <div className={styles.order__header}>
              <div className={styles.order__header_head}>
                Home <IoIosArrowForward /> Orders <IoIosArrowForward /> ID{" "}
                {orderData._id}
              </div>
              <div className={styles.order__header_status}>
                Payment Status :{" "}
                {orderData.isPaid ? (
                  <img src="/images/verified.png" alt="paid" />
                ) : (
                  <img src="/images/unverified.png" alt="not-paid" />
                )}
              </div>
              <div className={styles.order__header_status}>
                Order Status :
                <span
                  className={
                    orderData.status == "Not Processed"
                      ? styles.not_processed
                      : orderData.status == "Processing"
                      ? styles.processing
                      : orderData.status == "Dispatched"
                      ? styles.dispatched
                      : orderData.status == "Cancelled"
                      ? styles.cancelled
                      : orderData.status == "Completed"
                      ? styles.completed
                      : ""
                  }
                >
                  {orderData.status}
                </span>
              </div>
            </div>
            <div className={styles.order__products}>
              {orderData.products.map((product) => (
                <div className={styles.product} key={product._id}>
                  <div className={styles.product__img}>
                    <img src={product.image} alt={product.name} />
                  </div>
                  <div className={styles.product__infos}>
                    <h1 className={styles.product__infos_name}>
                      {product.name.length > 30
                        ? `${product.name.substring(0, 30)}...`
                        : product.name}
                    </h1>
                    <div className={styles.product__infos_style}>
                      <img src={product.color.image} alt="" /> / {product.size}
                    </div>
                    <div className={styles.product__infos_priceQty}>
                      {product.price}₦ x {product.qty}
                    </div>
                    <div className={styles.product__infos_total}>
                      {product.price * product.qty}₦
                    </div>
                  </div>
                </div>
              ))}
              <div className={styles.order__products_total}>
                {orderData.couponApplied ? (
                  <>
                    <div className={styles.order__products_total_sub}>
                      <span>Subtotal</span>
                      <span>{orderData.totalBeforeDiscount}₦</span>
                    </div>
                    <div className={styles.order__products_total_sub}>
                      <span>
                        Coupon Applied <em>({orderData.couponApplied})</em>{" "}
                      </span>
                      <span>
                        -
                        {(
                          orderData.totalBeforeDiscount - orderData.total
                        ).toFixed(2)}
                        ₦
                      </span>
                    </div>
                    <div className={styles.order__products_total_sub}>
                      <span>Tax price</span>
                      <span>+{orderData.taxPrice}₦</span>
                    </div>
                    <div
                      className={`${styles.order__products_total_sub} ${styles.bordertop}`}
                    >
                      <span>TOTAL TO PAY</span>
                      <b>{orderData.total}₦</b>
                    </div>
                  </>
                ) : (
                  <>
                    <div className={styles.order__products_total_sub}>
                      <span>Tax price</span>
                      <span>+ {orderData.taxPrice}₦</span>
                    </div>
                    <div
                      className={`${styles.order__products_total_sub} ${styles.bordertop}`}
                    >
                      <span>TOTAL TO PAY</span>
                      <b>{orderData.total}₦</b>
                    </div>
                  </>
                )}
              </div>
            </div>
          </div>
          <div className={styles.order__actions}>
            <div className={styles.order__address}>
              <h1>Customer's Info</h1>
              <div className={styles.order__address_user}>
                <div className={styles.order__address_user_infos}>
                  <img src={orderData.user.image} alt="" />
                  <div>
                    <span>{orderData.user.name}</span>
                    <span>{orderData.user.email}</span>
                  </div>
                </div>
              </div>
              <div className={styles.order__address_shipping}>
                <h2>Shipping Address</h2>
                <span>
                  {orderData.shippingAddress.firstName}{" "}
                  {orderData.shippingAddress.lastName}
                </span>
                <span>{orderData.shippingAddress.address1}</span>
                <span>{orderData.shippingAddress.address2}</span>
                <span>
                  {orderData.shippingAddress.state},
                  {orderData.shippingAddress.city}
                </span>
                <span>{orderData.shippingAddress.zipCode}</span>
                <span>{orderData.shippingAddress.country}</span>
              </div>
              <div className={styles.order__address_shipping}>
                <h2>Billing Address</h2>
                <span>
                  {orderData.shippingAddress.firstName}{" "}
                  {orderData.shippingAddress.lastName}
                </span>
                <span>{orderData.shippingAddress.address1}</span>
                <span>{orderData.shippingAddress.address2}</span>
                <span>
                  {orderData.shippingAddress.state},
                  {orderData.shippingAddress.city}
                </span>
                <span>{orderData.shippingAddress.zipCode}</span>
                <span>{orderData.shippingAddress.country}</span>
              </div>
            </div>
            {!orderData.isPaid && (
              <div className={styles.order__payment}>
                {orderData.paymentMethod == "paypal" && (
                  <div>
                    {isPending ? (
                      <span>loading...</span>
                    ) : (
                      <PayPalButtons
                        createOrder={createOrderHanlder}
                        onApprove={onApproveHandler}
                        onError={onErroHandler}
                      ></PayPalButtons>
                    )}
                  </div>
                )}
                {orderData.paymentMethod == "credit_card" && (
                  <PaystackButton
                    {...componentProps}
                    className="bg-[#441617] w-full text-center text-white h-16 rounded"
                  />
                )}
                {orderData.paymentMethod == "cash" && (
                  <div className={styles.cash}>cash</div>
                )}
              </div>
            )}
          </div>
        </div>
      </div>
    </>
  );
}

export async function getServerSideProps(context) {
  await db.connectDb();
  const { query } = context;
  const id = query.id;
  const order = await Order.findById(id)
    .populate({ path: "user", model: User })
    .lean();
  let paypal_client_id = process.env.PAYPAL_CLIENT_ID;
  let stripe_public_key = process.env.STRIPE_PUBLIC_KEY;
  await db.disconnectDb();
  return {
    props: {
      orderData: JSON.parse(JSON.stringify(order)),
      paypal_client_id,
      country: {
        name: "Nigeria",
        flag: "https://cdn.ipregistry.co/flags/emojitwo/ng.svg",
        code: "NG",
      },
    },
  };
}

/pages/api/order/[id].js

import nc from "next-connect";
import auth from "@/middleware/auth";
import Order from "@/models/Order";
import db from "@/utils/db";
import User from "@/models/user";

const handler = nc().use(auth);

handler.put(async (req, res) => {
  try {
    await db.connectDb();
    const orderId = req.query.id; // Ensure this is the correct way to extract the ID
    console.log("Order ID:", orderId);

    const order = await Order.findById(orderId).populate({
      path: "user",
      model: User,
    });
    if (order) {
      order.isPaid = true;
      order.paidAt = Date.now();
      order.paymentResult = {
        id: "12345",
        status: "processed",
        email: "[email protected]",
      };
      const newOrder = await order.save();
      await db.disconnectDb();
      console.log("Order updated:", newOrder);
      res.json({ message: "Order is paid.", order: newOrder });
    } else {
      await db.disconnectDb();
      console.log("Order not found");
      res.status(404).json({ message: "Order is not found." });
    }
  } catch (error) {
    console.error("Error processing payment:", error);
    await db.disconnectDb();
    return res.status(500).json({ message: "Internal server error." });
  }
});

export default handler;

/models/Order.js

import mongoose from "mongoose";

const { ObjectId } = mongoose.Schema;

const orderSchema = new mongoose.Schema(
  {
    user: {
      type: ObjectId,
      ref: "User",
      required: true,
    },
    products: [
      {
        product: {
          type: ObjectId,
          ref: "Product",
        },
        name: {
          type: String,
        },
        image: {
          type: String,
        },
        size: {
          type: String,
        },
        qty: {
          type: Number,
        },
        color: {
          color: String,
          image: String,
        },
        price: {
          type: Number,
        },
      },
    ],
    shippingAddress: {
      firstName: {
        type: String,
      },
      lastName: {
        type: String,
      },
      phoneNumber: {
        type: String,
      },
      address1: {
        type: String,
      },
      address2: {
        type: String,
      },
      city: {
        type: String,
      },
      state: {
        type: String,
      },
      zipCode: {
        type: String,
      },
      country: {
        type: String,
      },
    },
    paymentMethod: {
      type: String,
    },
    paymentResult: {
      id: String,
      status: String,
      email: String,
    },
    total: {
      type: Number,
      required: true,
    },
    totalBeforeDiscount: {
      type: Number,
    },
    couponApplied: {
      type: String,
    },
    shippingPrice: {
      type: Number,
      required: true,
      default: 0,
    },
    taxPrice: {
      type: Number,
      default: 0,
    },
    isPaid: {
      type: Boolean,
      required: true,
      default: false,
    },
    status: {
      type: String,
      default: "Not Processed",
      enum: [
        "Not Processed",
        "Processing",
        "Dispatched",
        "Cancelled",
        "Completed",
      ],
    },
    paidAt: {
      type: Date,
    },
    deliveredAt: {
      type: Date,
    },
  },
  {
    timestamps: true,
  }
);

const Order = mongoose.models.Order || mongoose.model("Order", orderSchema);

export default Order;
javascript mongodb mongoose next.js paystack
1个回答
0
投票

请求网址: http://localhost:3000/api/order/6626ea44b7683aa864d92837/支付请求 方法:PUT 状态代码:404 Not Found

  1. 404 表示类似于上述请求 URL 结构的端点不存在。

  2. 另外,我看到你正在这样做=>

    const orderId = req.query.id;

但是我在请求 URL 中找不到查询。包含查询的请求 URL 的修改版本将是

http://localhost:3000/api/pay?orderId=6626ea44b7683aa864d92837
  1. 我不使用nextjs,而是检查你做了什么;如果您的路由器的文件名是 /pages/api/order/[id].js,您可能需要修改该文件中的 put 请求以包含“/pay”。可能是这样的

    handler.put('/pay', async (req, res) => {

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