Spaces:
Running
Running
Download src/utils/orderConfirmation.js from AndreaNotes1/auth-app-api: direct link, hf CLI and curl.
- Browser
- Download file 3.66 kB
-
https://huggingface.co/spaces/AndreaNotes1/auth-app-api/resolve/main/src/utils/orderConfirmation.js
- Command line
-
hf download hf://spaces/AndreaNotes1/auth-app-api/src/utils/orderConfirmation.js
-
curl -L -o orderConfirmation.js https://huggingface.co/spaces/AndreaNotes1/auth-app-api/resolve/main/src/utils/orderConfirmation.js
3.66 kB
| const mongoose = require("mongoose"); | |
| const Order = require("../models/Order"); | |
| const User = require("../models/User"); | |
| const Course = require("../models/Course"); | |
| const AuditLog = require("../models/AuditLog"); | |
| const { sendPaymentConfirmedEmail } = require("./email"); | |
| const logger = require("./logger"); | |
| /** | |
| * The single source of truth for "an order has been paid — unlock the | |
| * course and tell the customer." Used by both: | |
| * - admin.controller.js's confirmOrder (a human admin manually | |
| * reviewing a bank-wire/manual payment reference), and | |
| * - webhook.controller.js's Payoneer webhook handler (an automated | |
| * Payoneer Checkout payment confirmation) | |
| * | |
| * so that access-granting and the confirmation email can never drift | |
| * out of sync between the manual and automated payment paths. | |
| * | |
| * `confirmedBy` is a User id for a manual admin confirmation, or null | |
| * for an automated one (the order's paymentMethod already records how | |
| * it was paid). | |
| * | |
| * Idempotent: safe to call more than once for the same order (a | |
| * webhook can legitimately be retried/redelivered by the provider) — | |
| * an already-confirmed order is left untouched and simply returned. | |
| */ | |
| async function confirmOrderAndGrantAccess({ orderId, confirmedBy = null, ip = null, userAgent = null }) { | |
| const session = await mongoose.startSession(); | |
| try { | |
| let resultOrder; | |
| let resultUser; | |
| let course; | |
| let alreadyConfirmed = false; | |
| await session.withTransaction(async () => { | |
| const order = await Order.findById(orderId).session(session); | |
| if (!order) throw Object.assign(new Error("Order not found."), { status: 404 }); | |
| if (order.status === "confirmed") { | |
| alreadyConfirmed = true; | |
| resultOrder = order; | |
| return; | |
| } | |
| if (!["awaiting_confirmation", "pending_payment"].includes(order.status)) { | |
| throw Object.assign(new Error("Order cannot be confirmed from its current status."), { status: 409 }); | |
| } | |
| order.status = "confirmed"; | |
| order.confirmedBy = confirmedBy; | |
| order.confirmedAt = new Date(); | |
| await order.save({ session }); | |
| const user = await User.findById(order.user).session(session); | |
| if (!user) throw Object.assign(new Error("Associated user not found."), { status: 404 }); | |
| const alreadyEnrolled = user.enrolledCourses.some((ec) => ec.course.toString() === order.course.toString()); | |
| if (!alreadyEnrolled) { | |
| user.enrolledCourses.push({ course: order.course, order: order._id, accessGrantedAt: new Date() }); | |
| await user.save({ session }); | |
| } | |
| course = await Course.findById(order.course).session(session); | |
| resultOrder = order; | |
| resultUser = user; | |
| }); | |
| if (alreadyConfirmed) { | |
| return { order: resultOrder, alreadyConfirmed: true }; | |
| } | |
| await AuditLog.create({ | |
| actor: confirmedBy, | |
| actorEmail: confirmedBy ? undefined : "system:payoneer-webhook", | |
| action: confirmedBy ? "admin.order_confirmed" : "system.order_auto_confirmed", | |
| targetType: "Order", | |
| targetId: resultOrder._id, | |
| ip, | |
| userAgent, | |
| metadata: { userId: resultUser._id.toString(), paymentMethod: resultOrder.paymentMethod }, | |
| }); | |
| sendPaymentConfirmedEmail({ | |
| to: resultUser.email, | |
| name: resultUser.name, | |
| order: resultOrder, | |
| courseTitle: course ? course.title : resultOrder.courseTitleSnapshot, | |
| }).catch((err) => logger.error("Payment-confirmed email failed", { error: err.message })); | |
| return { order: resultOrder, alreadyConfirmed: false }; | |
| } finally { | |
| session.endSession(); | |
| } | |
| } | |
| module.exports = { confirmOrderAndGrantAccess }; | |