started payouts
This commit is contained in:
@@ -2,6 +2,7 @@ const express = require("express");
|
||||
const { Op } = require("sequelize");
|
||||
const { Rental, Item, User } = require("../models"); // Import from models/index.js to get models with associations
|
||||
const { authenticateToken } = require("../middleware/auth");
|
||||
const FeeCalculator = require("../utils/feeCalculator");
|
||||
const router = express.Router();
|
||||
|
||||
// Helper function to check and update review visibility
|
||||
@@ -139,7 +140,10 @@ router.post("/", authenticateToken, async (req, res) => {
|
||||
const rentalDays = Math.ceil(
|
||||
(new Date(endDate) - new Date(startDate)) / (1000 * 60 * 60 * 24)
|
||||
);
|
||||
const totalAmount = rentalDays * (item.pricePerDay || 0);
|
||||
const baseRentalAmount = rentalDays * (item.pricePerDay || 0);
|
||||
|
||||
// Calculate fees using FeeCalculator
|
||||
const fees = FeeCalculator.calculateRentalFees(baseRentalAmount);
|
||||
|
||||
const rental = await Rental.create({
|
||||
itemId,
|
||||
@@ -149,7 +153,11 @@ router.post("/", authenticateToken, async (req, res) => {
|
||||
endDate,
|
||||
startTime,
|
||||
endTime,
|
||||
totalAmount,
|
||||
totalAmount: fees.totalChargedAmount,
|
||||
baseRentalAmount: fees.baseRentalAmount,
|
||||
platformFee: fees.platformFee,
|
||||
processingFee: fees.processingFee,
|
||||
payoutAmount: fees.payoutAmount,
|
||||
deliveryMethod,
|
||||
deliveryAddress,
|
||||
notes,
|
||||
@@ -376,4 +384,54 @@ router.post("/:id/review", authenticateToken, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Calculate fees for rental pricing display
|
||||
router.post("/calculate-fees", authenticateToken, async (req, res) => {
|
||||
try {
|
||||
const { baseAmount } = req.body;
|
||||
|
||||
if (!baseAmount || baseAmount <= 0) {
|
||||
return res.status(400).json({ error: "Valid base amount is required" });
|
||||
}
|
||||
|
||||
const fees = FeeCalculator.calculateRentalFees(baseAmount);
|
||||
const displayFees = FeeCalculator.formatFeesForDisplay(fees);
|
||||
|
||||
res.json({
|
||||
fees,
|
||||
display: displayFees,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error calculating fees:", error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Get payout status for owner's rentals
|
||||
router.get("/payouts/status", authenticateToken, async (req, res) => {
|
||||
try {
|
||||
const ownerRentals = await Rental.findAll({
|
||||
where: {
|
||||
ownerId: req.user.id,
|
||||
status: "completed",
|
||||
},
|
||||
attributes: [
|
||||
"id",
|
||||
"baseRentalAmount",
|
||||
"platformFee",
|
||||
"payoutAmount",
|
||||
"payoutStatus",
|
||||
"payoutProcessedAt",
|
||||
"stripeTransferId",
|
||||
],
|
||||
include: [{ model: Item, as: "item", attributes: ["name"] }],
|
||||
order: [["createdAt", "DESC"]],
|
||||
});
|
||||
|
||||
res.json(ownerRentals);
|
||||
} catch (error) {
|
||||
console.error("Error getting payout status:", error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -66,156 +66,100 @@ router.get("/checkout-session/:sessionId", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// // Create connected account
|
||||
// router.post("/accounts", authenticateToken, async (req, res) => {
|
||||
// try {
|
||||
// const user = await User.findByPk(req.user.id);
|
||||
// Create connected account
|
||||
router.post("/accounts", authenticateToken, async (req, res) => {
|
||||
try {
|
||||
const user = await User.findByPk(req.user.id);
|
||||
|
||||
// if (!user) {
|
||||
// return res.status(404).json({ error: "User not found" });
|
||||
// }
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: "User not found" });
|
||||
}
|
||||
|
||||
// // Check if user already has a connected account
|
||||
// if (user.stripeConnectedAccountId) {
|
||||
// return res
|
||||
// .status(400)
|
||||
// .json({ error: "User already has a connected account" });
|
||||
// }
|
||||
// Check if user already has a connected account
|
||||
if (user.stripeConnectedAccountId) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: "User already has a connected account" });
|
||||
}
|
||||
|
||||
// // Create connected account
|
||||
// const account = await StripeService.createConnectedAccount({
|
||||
// email: user.email,
|
||||
// country: "US", // You may want to make this configurable
|
||||
// });
|
||||
// Create connected account
|
||||
const account = await StripeService.createConnectedAccount({
|
||||
email: user.email,
|
||||
country: "US", // You may want to make this configurable
|
||||
});
|
||||
|
||||
// // Update user with account ID
|
||||
// await user.update({
|
||||
// stripeConnectedAccountId: account.id,
|
||||
// });
|
||||
// Update user with account ID
|
||||
await user.update({
|
||||
stripeConnectedAccountId: account.id,
|
||||
});
|
||||
|
||||
// res.json({
|
||||
// stripeConnectedAccountId: account.id,
|
||||
// success: true,
|
||||
// });
|
||||
// } catch (error) {
|
||||
// console.error("Error creating connected account:", error);
|
||||
// res.status(500).json({ error: error.message });
|
||||
// }
|
||||
// });
|
||||
res.json({
|
||||
stripeConnectedAccountId: account.id,
|
||||
success: true,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error creating connected account:", error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// // Generate onboarding link
|
||||
// router.post("/account-links", authenticateToken, async (req, res) => {
|
||||
// try {
|
||||
// const user = await User.findByPk(req.user.id);
|
||||
// Generate onboarding link
|
||||
router.post("/account-links", authenticateToken, async (req, res) => {
|
||||
try {
|
||||
const user = await User.findByPk(req.user.id);
|
||||
|
||||
// if (!user || !user.stripeConnectedAccountId) {
|
||||
// return res.status(400).json({ error: "No connected account found" });
|
||||
// }
|
||||
if (!user || !user.stripeConnectedAccountId) {
|
||||
return res.status(400).json({ error: "No connected account found" });
|
||||
}
|
||||
|
||||
// const { refreshUrl, returnUrl } = req.body;
|
||||
const { refreshUrl, returnUrl } = req.body;
|
||||
|
||||
// if (!refreshUrl || !returnUrl) {
|
||||
// return res
|
||||
// .status(400)
|
||||
// .json({ error: "refreshUrl and returnUrl are required" });
|
||||
// }
|
||||
if (!refreshUrl || !returnUrl) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: "refreshUrl and returnUrl are required" });
|
||||
}
|
||||
|
||||
// const accountLink = await StripeService.createAccountLink(
|
||||
// user.stripeConnectedAccountId,
|
||||
// refreshUrl,
|
||||
// returnUrl
|
||||
// );
|
||||
const accountLink = await StripeService.createAccountLink(
|
||||
user.stripeConnectedAccountId,
|
||||
refreshUrl,
|
||||
returnUrl
|
||||
);
|
||||
|
||||
// res.json({
|
||||
// url: accountLink.url,
|
||||
// expiresAt: accountLink.expires_at,
|
||||
// });
|
||||
// } catch (error) {
|
||||
// console.error("Error creating account link:", error);
|
||||
// res.status(500).json({ error: error.message });
|
||||
// }
|
||||
// });
|
||||
res.json({
|
||||
url: accountLink.url,
|
||||
expiresAt: accountLink.expires_at,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error creating account link:", error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// // Get account status
|
||||
// router.get("/account-status", authenticateToken, async (req, res) => {
|
||||
// try {
|
||||
// const user = await User.findByPk(req.user.id);
|
||||
// Get account status
|
||||
router.get("/account-status", authenticateToken, async (req, res) => {
|
||||
try {
|
||||
const user = await User.findByPk(req.user.id);
|
||||
|
||||
// if (!user || !user.stripeConnectedAccountId) {
|
||||
// return res.status(400).json({ error: "No connected account found" });
|
||||
// }
|
||||
if (!user || !user.stripeConnectedAccountId) {
|
||||
return res.status(400).json({ error: "No connected account found" });
|
||||
}
|
||||
|
||||
// const accountStatus = await StripeService.getAccountStatus(
|
||||
// user.stripeConnectedAccountId
|
||||
// );
|
||||
const accountStatus = await StripeService.getAccountStatus(
|
||||
user.stripeConnectedAccountId
|
||||
);
|
||||
|
||||
// res.json({
|
||||
// accountId: accountStatus.id,
|
||||
// detailsSubmitted: accountStatus.details_submitted,
|
||||
// payoutsEnabled: accountStatus.payouts_enabled,
|
||||
// capabilities: accountStatus.capabilities,
|
||||
// requirements: accountStatus.requirements,
|
||||
// });
|
||||
// } catch (error) {
|
||||
// console.error("Error getting account status:", error);
|
||||
// res.status(500).json({ error: error.message });
|
||||
// }
|
||||
// });
|
||||
|
||||
// // Create payment intent for rental
|
||||
// router.post("/payment-intents", authenticateToken, async (req, res) => {
|
||||
// try {
|
||||
// const { rentalId, amount } = req.body;
|
||||
|
||||
// if (!rentalId || !amount) {
|
||||
// return res
|
||||
// .status(400)
|
||||
// .json({ error: "rentalId and amount are required" });
|
||||
// }
|
||||
|
||||
// // Get rental details to find owner's connected account
|
||||
// const rental = await Rental.findByPk(rentalId, {
|
||||
// include: [{ model: Item, as: "item" }],
|
||||
// });
|
||||
|
||||
// if (!rental) {
|
||||
// return res.status(404).json({ error: "Rental not found" });
|
||||
// }
|
||||
|
||||
// if (rental.ownerId !== req.user.id) {
|
||||
// return res.status(403).json({ error: "Unauthorized" });
|
||||
// }
|
||||
|
||||
// // Get owner's connected account
|
||||
// const owner = await User.findByPk(rental.ownerId);
|
||||
// if (!owner || !owner.stripeConnectedAccountId) {
|
||||
// return res
|
||||
// .status(400)
|
||||
// .json({ error: "Owner does not have a connected account" });
|
||||
// }
|
||||
|
||||
// const applicationFeeAmount = Math.round(amount * platformFee);
|
||||
|
||||
// const paymentIntent = await StripeService.createPaymentIntent({
|
||||
// amount: Math.round(amount * 100), // Convert to cents
|
||||
// currency: "usd",
|
||||
// connectedAccountId: owner.stripeConnectedAccountId,
|
||||
// applicationFeeAmount: applicationFeeAmount * 100, // Convert to cents
|
||||
// metadata: {
|
||||
// rentalId: rental.id,
|
||||
// renterId: rental.renterId,
|
||||
// ownerId: owner.id,
|
||||
// },
|
||||
// });
|
||||
|
||||
// res.json({
|
||||
// clientSecret: paymentIntent.client_secret,
|
||||
// paymentIntentId: paymentIntent.id,
|
||||
// });
|
||||
// } catch (error) {
|
||||
// console.error("Error creating payment intent:", error);
|
||||
// res.status(500).json({ error: error.message });
|
||||
// }
|
||||
// });
|
||||
res.json({
|
||||
accountId: accountStatus.id,
|
||||
detailsSubmitted: accountStatus.details_submitted,
|
||||
payoutsEnabled: accountStatus.payouts_enabled,
|
||||
capabilities: accountStatus.capabilities,
|
||||
requirements: accountStatus.requirements,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error getting account status:", error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
Reference in New Issue
Block a user