"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var BillingController_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.BillingController = void 0; const common_1 = require("@nestjs/common"); const billing_service_1 = require("./billing.service"); const paymob_provider_1 = require("./providers/paymob.provider"); const binance_provider_1 = require("./providers/binance.provider"); const firebase_auth_guard_1 = require("../auth/guards/firebase-auth.guard"); const swagger_1 = require("@nestjs/swagger"); const transaction_entity_1 = require("./entities/transaction.entity"); let BillingController = BillingController_1 = class BillingController { billingService; paymobProvider; binanceProvider; logger = new common_1.Logger(BillingController_1.name); constructor(billingService, paymobProvider, binanceProvider) { this.billingService = billingService; this.paymobProvider = paymobProvider; this.binanceProvider = binanceProvider; } async getSubscription(req) { return this.billingService.getSubscription(req.tenant.id); } async checkout(req, body) { const tenantId = req.tenant.id; const plan = body.plan; const pricing = { 'STARTER': 29, 'PRO': 89, }; const amount = pricing[plan] || 0; if (amount === 0 && plan !== 'FREE') { throw new common_1.BadRequestException('Invalid plan or price not configured'); } if (body.provider === transaction_entity_1.PaymentProvider.PAYMOB) { const { paymentKey, orderId } = await this.paymobProvider.createPaymentKey(tenantId, amount, plan); const iframeId = this.billingService.getIframeId(); const checkoutUrl = `https://accept.paymob.com/api/acceptance/iframes/${iframeId}?payment_token=${paymentKey}`; return { checkoutUrl, orderId }; } if (body.provider === transaction_entity_1.PaymentProvider.BINANCE) { return this.binanceProvider.createOrder(tenantId, amount, plan); } throw new common_1.BadRequestException('Invalid payment provider'); } async handlePaymobCallback(query, req) { this.logger.log(`🔄 PayMob Redirect Callback: ID ${query.id}, Success: ${query.success}`); if (query.success === 'true' && query.id) { try { const txDetails = await this.paymobProvider.getTransactionDetails(query.id); if (txDetails && txDetails.success === true) { const extraDesc = txDetails.order?.shipping_data?.extra_description || ""; const [tenantId, plan] = extraDesc.split('|'); if (tenantId) { await this.billingService.processSuccessfulPayment(query.id.toString(), transaction_entity_1.PaymentProvider.PAYMOB, txDetails.amount_cents / 100, { tenantId, plan: plan || 'PRO' }); this.logger.log(`🚀 Immediate Activation triggered via Callback for Tenant ${tenantId}`); } } } catch (e) { this.logger.error(`Failed during immediate activation fallback: ${e.message}`); } } const targetUrl = `https://map-dashboard.intaleqapp.com/dashboard.html#billing?payment_status=${query.success === 'true' ? 'success' : 'failed'}&id=${query.id}`; return ` Intaleq Maps | تمت العملية بنجاح

شكراً لك، حمزة!

تم تفعيل خطة PRO بنجاح. يتم الآن توجيهك إلى لوحة التحكم...

`; } async handlePaymobWebhook(body, hmac) { this.logger.log(`📥 PayMob Webhook Received: Transaction ID ${body.obj?.id}`); if (!this.paymobProvider.verifyHmac(body.obj, hmac)) { this.logger.error('❌ PayMob HMAC Verification Failed'); throw new common_1.BadRequestException('Invalid signature'); } if (body.obj.success === true) { const extraDesc = body.obj.order?.shipping_data?.extra_description || ""; const [tenantId, plan] = extraDesc.split('|'); if (!tenantId) { this.logger.error(`❌ PayMob Webhook failed: No tenantId in metadata. Raw: ${extraDesc}`); return { status: 'error', message: 'No tenantId found' }; } await this.billingService.processSuccessfulPayment(body.obj.id.toString(), transaction_entity_1.PaymentProvider.PAYMOB, body.obj.amount_cents / 100, { tenantId, plan: plan || 'PRO' }); } return { status: 'success' }; } async handleBinanceWebhook(body, req) { const timestamp = req.headers['binancepay-timestamp']; const nonce = req.headers['binancepay-nonce']; const signature = req.headers['binancepay-signature']; this.logger.log(`📥 Binance Webhook Received: Transaction ID ${body.bizId || 'UNKNOWN'}`); if (!timestamp || !nonce || !signature) { this.logger.error('❌ Binance Webhook: Missing required headers'); throw new common_1.BadRequestException('Missing headers'); } if (!this.binanceProvider.verifySignature(timestamp, nonce, signature, body)) { this.logger.error('❌ Binance Signature Verification Failed'); throw new common_1.BadRequestException('Invalid signature'); } if (body.bizStatus === 'PAY_SUCCESS') { try { let dataObj = {}; if (body.data) { dataObj = JSON.parse(body.data); } let tenantId = ''; let plan = 'PRO'; if (dataObj.passThroughInfo) { const passThrough = JSON.parse(dataObj.passThroughInfo); tenantId = passThrough.tenantId; plan = passThrough.plan; } if (!tenantId) { this.logger.error(`❌ Binance Webhook failed: No tenantId found. Body: ${JSON.stringify(body)}`); return { returnCode: 'FAIL', returnMessage: 'No tenantId found' }; } const externalTxId = dataObj.merchantTradeNo || body.bizId?.toString(); await this.billingService.processSuccessfulPayment(externalTxId, transaction_entity_1.PaymentProvider.BINANCE, 0, { tenantId, plan }); this.logger.log(`✅ Binance Payment Processed Successfully for Tenant ${tenantId}`); } catch (err) { this.logger.error(`❌ Failed to process Binance payment: ${err.message}`); return { returnCode: 'FAIL', returnMessage: err.message }; } } return { returnCode: 'SUCCESS', returnMessage: null, }; } async getInvoices(req) { return this.billingService.getTransactionHistory(req.tenant.id); } }; exports.BillingController = BillingController; __decorate([ (0, swagger_1.ApiBearerAuth)(), (0, common_1.UseGuards)(firebase_auth_guard_1.FirebaseAuthGuard), (0, common_1.Get)('subscription'), (0, swagger_1.ApiOperation)({ summary: 'Get current subscription details' }), __param(0, (0, common_1.Req)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], BillingController.prototype, "getSubscription", null); __decorate([ (0, swagger_1.ApiBearerAuth)(), (0, common_1.UseGuards)(firebase_auth_guard_1.FirebaseAuthGuard), (0, common_1.Post)('checkout'), (0, swagger_1.ApiOperation)({ summary: 'Initialize a checkout session' }), __param(0, (0, common_1.Req)()), __param(1, (0, common_1.Body)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], BillingController.prototype, "checkout", null); __decorate([ (0, common_1.Get)('callback/paymob'), (0, swagger_1.ApiOperation)({ summary: 'PayMob Redirection Handler' }), __param(0, (0, common_1.Query)()), __param(1, (0, common_1.Req)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], BillingController.prototype, "handlePaymobCallback", null); __decorate([ (0, common_1.Post)('webhooks/paymob'), (0, swagger_1.ApiOperation)({ summary: 'PayMob Payment Webhook' }), __param(0, (0, common_1.Body)()), __param(1, (0, common_1.Query)('hmac')), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, String]), __metadata("design:returntype", Promise) ], BillingController.prototype, "handlePaymobWebhook", null); __decorate([ (0, common_1.Post)('webhooks/binance'), (0, swagger_1.ApiOperation)({ summary: 'Binance Payment Webhook' }), __param(0, (0, common_1.Body)()), __param(1, (0, common_1.Req)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], BillingController.prototype, "handleBinanceWebhook", null); __decorate([ (0, swagger_1.ApiBearerAuth)(), (0, common_1.UseGuards)(firebase_auth_guard_1.FirebaseAuthGuard), (0, common_1.Get)('invoices'), (0, swagger_1.ApiOperation)({ summary: 'Get payment history' }), __param(0, (0, common_1.Req)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], BillingController.prototype, "getInvoices", null); exports.BillingController = BillingController = BillingController_1 = __decorate([ (0, swagger_1.ApiTags)('billing'), (0, common_1.Controller)('billing'), __metadata("design:paramtypes", [billing_service_1.BillingService, paymob_provider_1.PayMobProvider, binance_provider_1.BinanceProvider]) ], BillingController); //# sourceMappingURL=billing.controller.js.map