Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | import { Injectable, Logger, BadRequestException } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { PaymentProviderRegion, PaymentRoutingRule, PaymentRoutingDecision, } from './schemas/payment-routing.schema'; import { BillingService } from '../billing/billing.service'; @Injectable() export class PaymentRoutingService { private readonly logger = new Logger(PaymentRoutingService.name); constructor( @InjectModel(PaymentProviderRegion.name) private readonly regionModel: Model<PaymentProviderRegion>, @InjectModel(PaymentRoutingRule.name) private readonly ruleModel: Model<PaymentRoutingRule>, @InjectModel(PaymentRoutingDecision.name) private readonly decisionModel: Model<PaymentRoutingDecision>, private readonly billingService: BillingService, ) {} async getRouteProvider( tenantId: string, billingCountry: string, amount: number, currency: string, ): Promise<string> { const cleanCountry = billingCountry.trim().toUpperCase(); // 1. Check custom tenant rules const customRule = await this.ruleModel .findOne({ tenantId, countryCode: { $in: [cleanCountry, '*'] }, isActive: true, }) .sort({ priority: -1 }) .exec(); if (customRule) { await this.decisionModel.create({ tenantId, billingCountry: cleanCountry, amount, currency, routedProvider: customRule.providerName, routingRuleId: (customRule as any)._id.toString(), reason: 'Custom tenant routing rule matches country', }); return customRule.providerName; } // 2. Check system region settings const systemRegion = await this.regionModel .findOne({ countryCode: cleanCountry, isActive: true }) .exec(); if (systemRegion) { await this.decisionModel.create({ tenantId, billingCountry: cleanCountry, amount, currency, routedProvider: systemRegion.primaryProvider, reason: 'System regional defaults matches country', }); return systemRegion.primaryProvider; } // 3. System hardcoded default fallback: // If country is India (IN), use Easebuzz; otherwise use Stripe. const routedProvider = cleanCountry === 'IN' ? 'Easebuzz' : 'Stripe'; await this.decisionModel.create({ tenantId, billingCountry: cleanCountry, amount, currency, routedProvider, reason: 'Hardcoded country rules default routing fallback', }); return routedProvider; } async configureCustomRule( tenantId: string, name: string, countryCode: string, providerName: string, priority = 0, ): Promise<PaymentRoutingRule> { if (!['Stripe', 'Easebuzz'].includes(providerName)) { throw new BadRequestException(`Unsupported gateway: ${providerName}`); } return this.ruleModel.create({ tenantId, name, countryCode: countryCode.toUpperCase(), providerName, priority, isActive: true, }); } async configureSystemRegion( countryCode: string, primaryProvider: string, fallbackProvider?: string, ): Promise<PaymentProviderRegion> { const cleanCountry = countryCode.toUpperCase(); const existing = await this.regionModel .findOne({ countryCode: cleanCountry }) .exec(); const doc = existing ?? new this.regionModel({ countryCode: cleanCountry }); doc.primaryProvider = primaryProvider; if (fallbackProvider) doc.fallbackProvider = fallbackProvider; doc.isActive = true; await doc.save(); return doc; } } |