"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.listByCompany = listByCompany; exports.listByReservation = listByReservation; exports.handleAmanpayWebhook = handleAmanpayWebhook; exports.handlePaypalWebhook = handlePaypalWebhook; exports.initCharge = initCharge; exports.capturePaypal = capturePaypal; exports.recordManualPayment = recordManualPayment; exports.refundPayment = refundPayment; const errors_1 = require("../../http/errors"); const amanpay = __importStar(require("../../services/amanpayService")); const paypal = __importStar(require("../../services/paypalService")); const repo = __importStar(require("./payment.repo")); const webhookIdempotency_1 = require("../../security/webhookIdempotency"); function listByCompany(companyId) { return repo.findByCompany(companyId); } function listByReservation(reservationId, companyId) { return repo.findByReservation(reservationId, companyId); } async function applyAmanpayWebhook(event) { const transactionId = event.transaction_id ?? event.id; const status = event.status?.toUpperCase(); if (status === 'PAID' || status === 'SUCCEEDED') { const payment = await repo.findByAmanpay(transactionId); if (payment && payment.status !== 'SUCCEEDED') { await repo.markPaymentSucceeded(payment.id); await repo.incrementReservationPaid(payment.reservationId, payment.amount); } } else if (status === 'FAILED') { await repo.markPaymentFailed({ amanpayTransactionId: transactionId }); } } async function applyPaypalWebhook(event) { const eventType = event.event_type; if (eventType === 'PAYMENT.CAPTURE.COMPLETED') { const captureId = event.resource?.id; const payment = await repo.findByPaypal(captureId); if (payment && payment.status !== 'SUCCEEDED') { await repo.markPaymentSucceeded(payment.id); await repo.incrementReservationPaid(payment.reservationId, payment.amount); } } else if (eventType === 'PAYMENT.CAPTURE.DENIED') { await repo.markPaymentFailed({ paypalCaptureId: event.resource?.id }); } } async function handleAmanpayWebhook(event, rawBody = JSON.stringify(event)) { return (0, webhookIdempotency_1.processWebhookOnce)({ provider: 'amanpay:payments', providerEventId: (0, webhookIdempotency_1.getWebhookEventId)('amanpay', event), eventType: String(event.status ?? 'unknown'), rawBody, handle: () => applyAmanpayWebhook(event), }); } async function handlePaypalWebhook(event, rawBody = JSON.stringify(event)) { return (0, webhookIdempotency_1.processWebhookOnce)({ provider: 'paypal:payments', providerEventId: (0, webhookIdempotency_1.getWebhookEventId)('paypal', event), eventType: String(event.event_type ?? 'unknown'), rawBody, handle: () => applyPaypalWebhook(event), }); } async function initCharge(reservationId, companyId, body) { const reservation = await repo.findReservationOrThrow(reservationId, companyId); if (reservation.paymentStatus === 'PAID') throw new errors_1.ConflictError('Reservation is already fully paid'); const amount = body.type === 'DEPOSIT' ? reservation.depositAmount : reservation.totalAmount; const description = `${body.type === 'DEPOSIT' ? 'Deposit' : 'Rental'}: ${reservation.vehicle.make} ${reservation.vehicle.model}`; const orderId = `${reservationId}-${body.type}-${Date.now()}`; const webhookBase = process.env.API_URL ?? 'http://localhost:4000'; let checkoutUrl; let amanpayTransactionId = null; let paypalCaptureId = null; if (body.provider === 'AMANPAY') { if (!amanpay.isConfigured()) throw new errors_1.ValidationError('AmanPay is not configured'); const result = await amanpay.createCheckout({ amount, currency: body.currency, orderId, description, customerEmail: reservation.customer.email, customerName: `${reservation.customer.firstName} ${reservation.customer.lastName}`, successUrl: body.successUrl, failureUrl: body.failureUrl, webhookUrl: `${webhookBase}/api/v1/payments/webhooks/amanpay`, }); checkoutUrl = result.checkoutUrl; amanpayTransactionId = result.transactionId; } else { if (!paypal.isConfigured()) throw new errors_1.ValidationError('PayPal is not configured'); const result = await paypal.createOrder({ amount, currency: body.currency, orderId, description, returnUrl: body.successUrl, cancelUrl: body.failureUrl }); checkoutUrl = result.approveUrl; paypalCaptureId = result.orderId; } const payment = await repo.createPayment({ companyId, reservationId, amount, currency: body.currency, status: 'PENDING', type: body.type, paymentProvider: body.provider, amanpayTransactionId, paypalCaptureId }); return { payment, checkoutUrl }; } async function capturePaypal(reservationId, companyId, paypalOrderId) { const payment = await repo.findByPaypalForCompany(paypalOrderId, companyId); const capture = await paypal.captureOrder(paypalOrderId); const captureId = capture.purchase_units?.[0]?.payments?.captures?.[0]?.id ?? paypalOrderId; const updated = await repo.updatePaypalCapture(payment.id, captureId); await repo.incrementReservationPaid(payment.reservationId, payment.amount); return updated; } async function recordManualPayment(reservationId, companyId, body) { const reservation = await repo.findReservation(reservationId, companyId); const remaining = Math.max(reservation.totalAmount - reservation.paidAmount, 0); if (remaining <= 0) throw new errors_1.ConflictError('Reservation is already fully paid'); if (body.amount > remaining) throw new errors_1.ValidationError('Payment amount exceeds remaining balance'); const payment = await repo.createPayment({ companyId, reservationId, amount: body.amount, currency: body.currency, status: 'SUCCEEDED', type: body.type, paymentProvider: body.paymentMethod === 'PAYPAL' ? 'PAYPAL' : 'AMANPAY', paymentMethod: body.paymentMethod, paidAt: new Date() }); const newPaidAmount = reservation.paidAmount + body.amount; await repo.setReservationPaidAmount(reservationId, newPaidAmount, newPaidAmount >= reservation.totalAmount ? 'PAID' : 'PARTIAL'); return payment; } async function refundPayment(reservationId, paymentId, companyId, amount, reason) { const payment = await repo.findPaymentOrThrow(paymentId, companyId, reservationId); if (payment.status !== 'SUCCEEDED') throw new errors_1.ValidationError('Only succeeded payments can be refunded'); if (!payment.amanpayTransactionId && !payment.paypalCaptureId) throw new errors_1.ValidationError('Manual payments must be refunded outside the online gateway flow'); const refundAmount = amount ?? payment.amount; if (payment.paymentProvider === 'AMANPAY') { if (!payment.amanpayTransactionId) throw new Error('No AmanPay transaction ID'); await amanpay.refundTransaction(payment.amanpayTransactionId, refundAmount, reason); } else { if (!payment.paypalCaptureId) throw new Error('No PayPal capture ID'); await paypal.refundCapture(payment.paypalCaptureId, refundAmount, payment.currency, reason); } const isPartial = refundAmount < payment.amount; const updated = await repo.setPaymentRefunded(payment.id, isPartial); if (!isPartial) await repo.setReservationRefunded(payment.reservationId); return updated; } //# sourceMappingURL=payment.service.js.map