Added the payment details in verify payment API
This commit is contained in:
parent
1d54af7c00
commit
04f1917332
@ -0,0 +1,77 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.PaymentGetway
|
||||||
|
{
|
||||||
|
public class RazorpayPaymentDetails
|
||||||
|
{
|
||||||
|
public string? PaymentId { get; set; }
|
||||||
|
public string? OrderId { get; set; }
|
||||||
|
public decimal Amount { get; set; }
|
||||||
|
public string? Currency { get; set; }
|
||||||
|
public string? Status { get; set; } // created, authorized, captured, refunded, failed
|
||||||
|
public string? Method { get; set; } // card, netbanking, wallet, upi
|
||||||
|
public string? Email { get; set; }
|
||||||
|
public string? Contact { get; set; }
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public string? CustomerName { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
// Payment method specific details
|
||||||
|
public CardDetails? CardDetails { get; set; }
|
||||||
|
public BankDetails? BankDetails { get; set; }
|
||||||
|
public UpiDetails? UpiDetails { get; set; }
|
||||||
|
public WalletDetails? WalletDetails { get; set; }
|
||||||
|
|
||||||
|
// Fee and tax
|
||||||
|
public decimal Fee { get; set; }
|
||||||
|
public decimal Tax { get; set; }
|
||||||
|
|
||||||
|
// Error details (if payment failed)
|
||||||
|
public string? ErrorCode { get; set; }
|
||||||
|
public string? ErrorDescription { get; set; }
|
||||||
|
|
||||||
|
// Additional flags
|
||||||
|
public bool InternationalPayment { get; set; }
|
||||||
|
public bool Captured { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CardDetails
|
||||||
|
{
|
||||||
|
public string? CardId { get; set; }
|
||||||
|
public string? Last4Digits { get; set; }
|
||||||
|
public string? Network { get; set; } // Visa, MasterCard, Amex, RuPay
|
||||||
|
public string? CardType { get; set; } // credit, debit, prepaid
|
||||||
|
public string? Issuer { get; set; } // Bank name
|
||||||
|
public bool International { get; set; }
|
||||||
|
public bool Emi { get; set; }
|
||||||
|
public string? SubType { get; set; } // consumer, business
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BankDetails
|
||||||
|
{
|
||||||
|
public string? Bank { get; set; }
|
||||||
|
public string? BankCode { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UpiDetails
|
||||||
|
{
|
||||||
|
public string? Vpa { get; set; } // UPI ID
|
||||||
|
public string? Provider { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class WalletDetails
|
||||||
|
{
|
||||||
|
public string? WalletName { get; set; } // paytm, phonepe, amazonpay, freecharge, jiomoney, olamoney
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RazorpayOrderDetails
|
||||||
|
{
|
||||||
|
public string? OrderId { get; set; }
|
||||||
|
public decimal Amount { get; set; }
|
||||||
|
public string? Currency { get; set; }
|
||||||
|
public string? Status { get; set; }
|
||||||
|
public string? Receipt { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public decimal AmountPaid { get; set; }
|
||||||
|
public decimal AmountDue { get; set; }
|
||||||
|
public int Attempts { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,8 @@
|
|||||||
using Marco.Pms.Model.Dtos.PaymentGetway;
|
using Marco.Pms.Model.Dtos.PaymentGetway;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Marco.Pms.Services.Helpers;
|
using Marco.Pms.Services.Service.ServiceInterfaces;
|
||||||
using MarcoBMS.Services.Helpers;
|
using MarcoBMS.Services.Helpers;
|
||||||
|
using MarcoBMS.Services.Service;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Marco.Pms.Services.Controllers
|
namespace Marco.Pms.Services.Controllers
|
||||||
@ -11,13 +12,15 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
public class PaymentController : ControllerBase
|
public class PaymentController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly UserHelper _userHelper;
|
private readonly UserHelper _userHelper;
|
||||||
private readonly PaymentHelper _paymentHelper;
|
private readonly ILoggingService _logger;
|
||||||
|
private readonly IRazorpayService _razorpayService;
|
||||||
private readonly Guid tenantId;
|
private readonly Guid tenantId;
|
||||||
private readonly Guid organizaionId;
|
private readonly Guid organizaionId;
|
||||||
public PaymentController(UserHelper userHelper, PaymentHelper paymentHelper)
|
public PaymentController(UserHelper userHelper, ILoggingService logger, IRazorpayService razorpayService)
|
||||||
{
|
{
|
||||||
_userHelper = userHelper;
|
_userHelper = userHelper;
|
||||||
_paymentHelper = paymentHelper;
|
_logger = logger;
|
||||||
|
_razorpayService = razorpayService;
|
||||||
tenantId = userHelper.GetTenantId();
|
tenantId = userHelper.GetTenantId();
|
||||||
organizaionId = userHelper.GetCurrentOrganizationId();
|
organizaionId = userHelper.GetCurrentOrganizationId();
|
||||||
}
|
}
|
||||||
@ -28,7 +31,7 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response = _paymentHelper.CreateOrder(model.Amount, loggedInEmployee, tenantId);
|
var response = _razorpayService.CreateOrder(model.Amount, loggedInEmployee, tenantId);
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Payment created successfully", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(response, "Payment created successfully", 200));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -51,20 +54,57 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
[HttpPost("verify-payment")]
|
[HttpPost("verify-payment")]
|
||||||
public IActionResult VerifyPayment([FromBody] PaymentVerificationRequest request)
|
public IActionResult VerifyPayment([FromBody] PaymentVerificationRequest request)
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInfo("Payment verification started for OrderId: {OrderId}, PaymentId: {PaymentId}",
|
||||||
|
request.OrderId ?? "", request.PaymentId ?? "");
|
||||||
|
|
||||||
|
// Validate request
|
||||||
|
if (string.IsNullOrEmpty(request.OrderId) || string.IsNullOrEmpty(request.PaymentId) || string.IsNullOrEmpty(request.Signature))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Payment verification failed - Missing required parameters");
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Missing required parameters", 400));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify signature
|
||||||
string payload = request.OrderId + "|" + request.PaymentId;
|
string payload = request.OrderId + "|" + request.PaymentId;
|
||||||
string actualSignature = request.Signature ?? "";
|
string actualSignature = request.Signature;
|
||||||
string expectedSignature = _paymentHelper.GetExpectedSignature(payload);
|
string expectedSignature = _razorpayService.GetExpectedSignature(payload);
|
||||||
|
|
||||||
if (actualSignature == expectedSignature)
|
if (actualSignature == expectedSignature)
|
||||||
{
|
{
|
||||||
// Payment is verified, process accordingly e.g. update tenant payment details
|
_logger.LogInfo("Payment signature verified successfully for OrderId: {OrderId}", request.OrderId);
|
||||||
return Ok(new { status = "success" });
|
|
||||||
|
// Fetch complete payment details from Razorpay including card details
|
||||||
|
var razorpayPaymentDetails = _razorpayService.GetPaymentDetailsAsync(request.PaymentId);
|
||||||
|
|
||||||
|
// Fetch order details from Razorpay
|
||||||
|
var razorpayOrderDetails = _razorpayService.GetOrderDetailsAsync(request.OrderId);
|
||||||
|
|
||||||
|
_logger.LogInfo("Invoice generated and saved for OrderId: {OrderId}", request.OrderId);
|
||||||
|
|
||||||
|
// Prepare response with all details
|
||||||
|
var responseData = new
|
||||||
|
{
|
||||||
|
RazorpayPaymentDetails = razorpayPaymentDetails,
|
||||||
|
RazorpayOrderDetails = razorpayOrderDetails
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(responseData, "Payment verified successfully", 200));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return BadRequest(new { status = "failure", message = "Invalid signature" });
|
_logger.LogWarning("Payment signature verification failed for OrderId: {OrderId}", request.OrderId);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid signature - Payment verification failed", 400));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error during payment verification for OrderId: {OrderId}", request.OrderId ?? "");
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("An error occurred during payment verification", 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,57 +0,0 @@
|
|||||||
using Marco.Pms.Model.Employees;
|
|
||||||
using Marco.Pms.Model.ViewModels.PaymentGetway;
|
|
||||||
using Razorpay.Api;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Marco.Pms.Services.Helpers
|
|
||||||
{
|
|
||||||
public class PaymentHelper
|
|
||||||
{
|
|
||||||
private readonly IConfiguration _configuration;
|
|
||||||
private readonly string key = "YOUR_RAZORPAY_KEY";
|
|
||||||
private readonly string secret = "YOUR_RAZORPAY_SECRET";
|
|
||||||
public PaymentHelper(IConfiguration configuration)
|
|
||||||
{
|
|
||||||
_configuration = configuration;
|
|
||||||
key = configuration["Razorpay:Key"] ?? "";
|
|
||||||
secret = configuration["Razorpay:Secret"] ?? "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public CreateOrderVM CreateOrder(double amount, Employee loggedInEmployee, Guid tenantId)
|
|
||||||
{
|
|
||||||
RazorpayClient client = new RazorpayClient(key, secret);
|
|
||||||
|
|
||||||
var receipt = $"rec_{Guid.NewGuid()}";
|
|
||||||
var length = receipt.Length;
|
|
||||||
|
|
||||||
Dictionary<string, object> options = new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{ "amount", amount * 100 }, // amount in paise
|
|
||||||
{ "currency", "INR" },
|
|
||||||
{ "receipt", receipt},
|
|
||||||
{ "payment_capture", 1 }
|
|
||||||
};
|
|
||||||
|
|
||||||
Order order = client.Order.Create(options);
|
|
||||||
var response = new CreateOrderVM
|
|
||||||
{
|
|
||||||
OrderId = order["id"],
|
|
||||||
Key = key
|
|
||||||
};
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetExpectedSignature(string payload)
|
|
||||||
{
|
|
||||||
string expectedSignature;
|
|
||||||
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret)))
|
|
||||||
{
|
|
||||||
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
|
|
||||||
expectedSignature = Convert.ToHexString(hash).ToLower();
|
|
||||||
}
|
|
||||||
|
|
||||||
return expectedSignature;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -183,6 +183,7 @@ builder.Services.AddScoped<IExpensesService, ExpensesService>();
|
|||||||
builder.Services.AddScoped<IMasterService, MasterService>();
|
builder.Services.AddScoped<IMasterService, MasterService>();
|
||||||
builder.Services.AddScoped<IDirectoryService, DirectoryService>();
|
builder.Services.AddScoped<IDirectoryService, DirectoryService>();
|
||||||
builder.Services.AddScoped<IFirebaseService, FirebaseService>();
|
builder.Services.AddScoped<IFirebaseService, FirebaseService>();
|
||||||
|
builder.Services.AddScoped<IRazorpayService, RazorpayService>();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Helpers
|
#region Helpers
|
||||||
@ -191,7 +192,6 @@ builder.Services.AddScoped<UserHelper>();
|
|||||||
builder.Services.AddScoped<RolesHelper>();
|
builder.Services.AddScoped<RolesHelper>();
|
||||||
builder.Services.AddScoped<EmployeeHelper>();
|
builder.Services.AddScoped<EmployeeHelper>();
|
||||||
builder.Services.AddScoped<ReportHelper>();
|
builder.Services.AddScoped<ReportHelper>();
|
||||||
builder.Services.AddScoped<PaymentHelper>();
|
|
||||||
builder.Services.AddScoped<CacheUpdateHelper>();
|
builder.Services.AddScoped<CacheUpdateHelper>();
|
||||||
builder.Services.AddScoped<FeatureDetailsHelper>();
|
builder.Services.AddScoped<FeatureDetailsHelper>();
|
||||||
builder.Services.AddScoped<UtilityMongoDBHelper>();
|
builder.Services.AddScoped<UtilityMongoDBHelper>();
|
||||||
|
|||||||
336
Marco.Pms.Services/Service/RazorpayService.cs
Normal file
336
Marco.Pms.Services/Service/RazorpayService.cs
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
using Marco.Pms.Model.Employees;
|
||||||
|
using Marco.Pms.Model.ViewModels.PaymentGetway;
|
||||||
|
using Marco.Pms.Services.Service.ServiceInterfaces;
|
||||||
|
using MarcoBMS.Services.Service;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Razorpay.Api;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Services.Service
|
||||||
|
{
|
||||||
|
public class RazorpayService : IRazorpayService
|
||||||
|
{
|
||||||
|
private readonly RazorpayClient _razorpayClient;
|
||||||
|
private readonly ILoggingService _logger;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
private readonly string key;
|
||||||
|
private readonly string secret;
|
||||||
|
public RazorpayService(IConfiguration configuration, ILoggingService logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_configuration = configuration;
|
||||||
|
key = configuration["Razorpay:Key"] ?? "";
|
||||||
|
secret = configuration["Razorpay:Secret"] ?? "";
|
||||||
|
_razorpayClient = new RazorpayClient(key, secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateOrderVM CreateOrder(double amount, Employee loggedInEmployee, Guid tenantId)
|
||||||
|
{
|
||||||
|
RazorpayClient client = new RazorpayClient(key, secret);
|
||||||
|
|
||||||
|
var receipt = $"rec_{Guid.NewGuid()}";
|
||||||
|
var length = receipt.Length;
|
||||||
|
|
||||||
|
Dictionary<string, object> options = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "amount", amount * 100 }, // amount in paise
|
||||||
|
{ "currency", "INR" },
|
||||||
|
{ "receipt", receipt},
|
||||||
|
{ "payment_capture", 1 }
|
||||||
|
};
|
||||||
|
|
||||||
|
Order order = client.Order.Create(options);
|
||||||
|
var response = new CreateOrderVM
|
||||||
|
{
|
||||||
|
OrderId = order["id"],
|
||||||
|
Key = key
|
||||||
|
};
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetExpectedSignature(string payload)
|
||||||
|
{
|
||||||
|
string expectedSignature;
|
||||||
|
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret)))
|
||||||
|
{
|
||||||
|
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
|
||||||
|
expectedSignature = Convert.ToHexString(hash).ToLower();
|
||||||
|
}
|
||||||
|
|
||||||
|
return expectedSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetch complete payment details from Razorpay including card details
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="paymentId">Razorpay Payment ID</param>
|
||||||
|
/// <returns>Complete payment details with card information</returns>
|
||||||
|
public RazorpayPaymentDetails? GetPaymentDetailsAsync(string paymentId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInfo("Fetching payment details from Razorpay for PaymentId: {PaymentId}", paymentId);
|
||||||
|
|
||||||
|
// Fetch payment details from Razorpay
|
||||||
|
Payment payment = _razorpayClient.Payment.Fetch(paymentId);
|
||||||
|
|
||||||
|
// Extract customer name from notes or fetch from customer API
|
||||||
|
string customerName = ExtractCustomerName(payment);
|
||||||
|
|
||||||
|
// Map to custom model with all details
|
||||||
|
var paymentDetails = new RazorpayPaymentDetails
|
||||||
|
{
|
||||||
|
PaymentId = payment.Attributes["id"]?.ToString(),
|
||||||
|
OrderId = payment.Attributes["order_id"]?.ToString(),
|
||||||
|
Amount = Convert.ToDecimal(payment.Attributes["amount"]) / 100, // Convert from paise to rupees
|
||||||
|
Currency = payment.Attributes["currency"]?.ToString(),
|
||||||
|
Status = payment.Attributes["status"]?.ToString(),
|
||||||
|
Method = payment.Attributes["method"]?.ToString(),
|
||||||
|
Email = payment.Attributes["email"]?.ToString(),
|
||||||
|
Contact = payment.Attributes["contact"]?.ToString(),
|
||||||
|
Description = payment.Attributes["description"]?.ToString(),
|
||||||
|
CustomerName = customerName,
|
||||||
|
CreatedAt = DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt64(payment.Attributes["created_at"])).DateTime,
|
||||||
|
|
||||||
|
// Card details (if payment method is card)
|
||||||
|
CardDetails = payment.Attributes["method"]?.ToString() == "card"
|
||||||
|
? ExtractCardDetails(payment)
|
||||||
|
: null,
|
||||||
|
|
||||||
|
// Bank details (if payment method is netbanking)
|
||||||
|
BankDetails = payment.Attributes["method"]?.ToString() == "netbanking"
|
||||||
|
? ExtractBankDetails(payment)
|
||||||
|
: null,
|
||||||
|
|
||||||
|
// UPI details (if payment method is upi)
|
||||||
|
UpiDetails = payment.Attributes["method"]?.ToString() == "upi"
|
||||||
|
? ExtractUpiDetails(payment)
|
||||||
|
: null,
|
||||||
|
|
||||||
|
// Wallet details (if payment method is wallet)
|
||||||
|
WalletDetails = payment.Attributes["method"]?.ToString() == "wallet"
|
||||||
|
? ExtractWalletDetails(payment)
|
||||||
|
: null,
|
||||||
|
|
||||||
|
// Additional details
|
||||||
|
Fee = payment.Attributes["fee"] != null
|
||||||
|
? Convert.ToDecimal(payment.Attributes["fee"]) / 100
|
||||||
|
: 0,
|
||||||
|
Tax = payment.Attributes["tax"] != null
|
||||||
|
? Convert.ToDecimal(payment.Attributes["tax"]) / 100
|
||||||
|
: 0,
|
||||||
|
ErrorCode = payment.Attributes["error_code"]?.ToString(),
|
||||||
|
ErrorDescription = payment.Attributes["error_description"]?.ToString(),
|
||||||
|
InternationalPayment = Convert.ToBoolean(payment.Attributes["international"] ?? false),
|
||||||
|
Captured = Convert.ToBoolean(payment.Attributes["captured"] ?? false)
|
||||||
|
};
|
||||||
|
|
||||||
|
_logger.LogInfo("Payment details fetched successfully from Razorpay for PaymentId: {PaymentId}", paymentId);
|
||||||
|
return paymentDetails;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error fetching payment details from Razorpay for PaymentId: {PaymentId}", paymentId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extract card details from payment
|
||||||
|
/// </summary>
|
||||||
|
private CardDetails? ExtractCardDetails(Payment payment)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var cardObj = payment.Attributes["card"];
|
||||||
|
if (cardObj == null) return null;
|
||||||
|
|
||||||
|
string json = JsonConvert.SerializeObject(cardObj);
|
||||||
|
Dictionary<string, object>? cardDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
|
||||||
|
|
||||||
|
return new CardDetails
|
||||||
|
{
|
||||||
|
CardId = cardDict?["id"]?.ToString(),
|
||||||
|
Last4Digits = cardDict?["last4"]?.ToString(),
|
||||||
|
Network = cardDict?["network"]?.ToString(), // Visa, MasterCard, Amex, etc.
|
||||||
|
CardType = cardDict?["type"]?.ToString(), // credit, debit, prepaid
|
||||||
|
Issuer = cardDict?["issuer"]?.ToString(), // Bank name
|
||||||
|
International = Convert.ToBoolean(cardDict?["international"] ?? false),
|
||||||
|
Emi = Convert.ToBoolean(cardDict?["emi"] ?? false),
|
||||||
|
SubType = cardDict?["sub_type"]?.ToString() // consumer, business
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error extracting card details");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extract bank details from payment
|
||||||
|
/// </summary>
|
||||||
|
private BankDetails? ExtractBankDetails(Payment payment)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new BankDetails
|
||||||
|
{
|
||||||
|
Bank = payment.Attributes["bank"]?.ToString(),
|
||||||
|
BankCode = payment.Attributes["bank_code"]?.ToString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error extracting bank details");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extract UPI details from payment
|
||||||
|
/// </summary>
|
||||||
|
private UpiDetails? ExtractUpiDetails(Payment payment)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var vpaObj = payment.Attributes["vpa"];
|
||||||
|
|
||||||
|
return new UpiDetails
|
||||||
|
{
|
||||||
|
Vpa = vpaObj?.ToString(), // UPI ID
|
||||||
|
Provider = payment.Attributes["provider"]?.ToString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error extracting UPI details");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extract wallet details from payment
|
||||||
|
/// </summary>
|
||||||
|
private WalletDetails? ExtractWalletDetails(Payment payment)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new WalletDetails
|
||||||
|
{
|
||||||
|
WalletName = payment.Attributes["wallet"]?.ToString() // paytm, phonepe, amazonpay, etc.
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error extracting wallet details");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extract customer name from payment object
|
||||||
|
/// </summary>
|
||||||
|
private string ExtractCustomerName(Payment payment)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Option 1: Get from notes (if you passed customer name during order creation)
|
||||||
|
var notesObj = payment.Attributes["notes"];
|
||||||
|
if (notesObj != null)
|
||||||
|
{
|
||||||
|
var notesDict = notesObj as Dictionary<string, object>;
|
||||||
|
if (notesDict != null && notesDict.ContainsKey("customer_name"))
|
||||||
|
{
|
||||||
|
return notesDict["customer_name"]?.ToString() ?? "CustomerName";
|
||||||
|
}
|
||||||
|
if (notesDict != null && notesDict.ContainsKey("name"))
|
||||||
|
{
|
||||||
|
return notesDict["name"]?.ToString() ?? "CustomerName";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option 2: Get from customer ID and fetch customer details
|
||||||
|
var customerId = payment.Attributes["customer_id"]?.ToString();
|
||||||
|
if (!string.IsNullOrEmpty(customerId))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Customer customer = _razorpayClient.Customer.Fetch(customerId);
|
||||||
|
return customer.Attributes["name"]?.ToString() ?? "CustomerName";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error fetching customer details for CustomerId: {CustomerId}", customerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option 3: Extract from card holder name (if available)
|
||||||
|
if (payment.Attributes["method"]?.ToString() == "card")
|
||||||
|
{
|
||||||
|
var cardObj = payment.Attributes["card"];
|
||||||
|
if (cardObj != null)
|
||||||
|
{
|
||||||
|
string json = JsonConvert.SerializeObject(cardObj);
|
||||||
|
Dictionary<string, object>? dictionary = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
|
||||||
|
|
||||||
|
var cardName = dictionary?["name"]?.ToString();
|
||||||
|
if (!string.IsNullOrEmpty(cardName))
|
||||||
|
{
|
||||||
|
return cardName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option 4: Use email as fallback
|
||||||
|
return payment.Attributes["email"]?.ToString() ?? "Customer";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error extracting customer name from payment");
|
||||||
|
return "Customer";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetch order details from Razorpay
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="orderId">Razorpay Order ID</param>
|
||||||
|
/// <returns>Order details</returns>
|
||||||
|
public RazorpayOrderDetails? GetOrderDetailsAsync(string orderId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInfo("Fetching order details from Razorpay for OrderId: {OrderId}", orderId);
|
||||||
|
|
||||||
|
Order order = _razorpayClient.Order.Fetch(orderId);
|
||||||
|
|
||||||
|
var orderDetails = new RazorpayOrderDetails
|
||||||
|
{
|
||||||
|
OrderId = order.Attributes["id"]?.ToString(),
|
||||||
|
Amount = Convert.ToDecimal(order.Attributes["amount"]) / 100,
|
||||||
|
Currency = order.Attributes["currency"]?.ToString(),
|
||||||
|
Status = order.Attributes["status"]?.ToString(),
|
||||||
|
Receipt = order.Attributes["receipt"]?.ToString(),
|
||||||
|
CreatedAt = DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt64(order.Attributes["created_at"])).DateTime,
|
||||||
|
AmountPaid = order.Attributes["amount_paid"] != null
|
||||||
|
? Convert.ToDecimal(order.Attributes["amount_paid"]) / 100
|
||||||
|
: 0,
|
||||||
|
AmountDue = order.Attributes["amount_due"] != null
|
||||||
|
? Convert.ToDecimal(order.Attributes["amount_due"]) / 100
|
||||||
|
: 0,
|
||||||
|
Attempts = Convert.ToInt32(order.Attributes["attempts"] ?? 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
_logger.LogInfo("Order details fetched successfully from Razorpay for OrderId: {OrderId}", orderId);
|
||||||
|
return orderDetails;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error fetching order details from Razorpay for OrderId: {OrderId}", orderId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
using Marco.Pms.Model.Employees;
|
||||||
|
using Marco.Pms.Model.ViewModels.PaymentGetway;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Services.Service.ServiceInterfaces
|
||||||
|
{
|
||||||
|
public interface IRazorpayService
|
||||||
|
{
|
||||||
|
CreateOrderVM CreateOrder(double amount, Employee loggedInEmployee, Guid tenantId);
|
||||||
|
string GetExpectedSignature(string payload);
|
||||||
|
RazorpayPaymentDetails? GetPaymentDetailsAsync(string paymentId);
|
||||||
|
RazorpayOrderDetails? GetOrderDetailsAsync(string orderId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -54,5 +54,9 @@
|
|||||||
"Razorpay": {
|
"Razorpay": {
|
||||||
"Key": "rzp_test_RXCzgEcXucbuAi",
|
"Key": "rzp_test_RXCzgEcXucbuAi",
|
||||||
"Secret": "YNAVBXxRsDg8Oat4M1C3m09W"
|
"Secret": "YNAVBXxRsDg8Oat4M1C3m09W"
|
||||||
|
},
|
||||||
|
"Encryption": {
|
||||||
|
"PaymentKey": "4oZV1Za+zqD0CgTvRrj5zUVQeMxok5MSTz6c3wsECdM=",
|
||||||
|
"CollectionKey": "9bVvYrbL1uB+v6TjWRsJ8N8VFI8rE7e7hVhVSKg3JZU="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user