Added create order and verify payment API for razor pay

This commit is contained in:
ashutosh.nehete 2025-10-24 17:01:22 +05:30
parent c6744f0556
commit 1d54af7c00
9 changed files with 164 additions and 4 deletions

View File

@ -8,6 +8,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="3.0.0" /> <PackageReference Include="MongoDB.Driver" Version="3.0.0" />
<PackageReference Include="Razorpay" Version="3.3.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,7 @@
namespace Marco.Pms.Model.Dtos.PaymentGetway
{
public class CreateOrderDto
{
public double Amount { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace Marco.Pms.Model.Dtos.PaymentGetway
{
public class PaymentVerificationRequest
{
public string? OrderId { get; set; }
public string? PaymentId { get; set; }
public string? Signature { get; set; }
}
}

View File

@ -0,0 +1,8 @@
namespace Marco.Pms.Model.ViewModels.PaymentGetway
{
public class CreateOrderVM
{
public string? OrderId { get; set; }
public string? Key { get; set; }
}
}

View File

@ -0,0 +1,71 @@
using Marco.Pms.Model.Dtos.PaymentGetway;
using Marco.Pms.Model.Utilities;
using Marco.Pms.Services.Helpers;
using MarcoBMS.Services.Helpers;
using Microsoft.AspNetCore.Mvc;
namespace Marco.Pms.Services.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PaymentController : ControllerBase
{
private readonly UserHelper _userHelper;
private readonly PaymentHelper _paymentHelper;
private readonly Guid tenantId;
private readonly Guid organizaionId;
public PaymentController(UserHelper userHelper, PaymentHelper paymentHelper)
{
_userHelper = userHelper;
_paymentHelper = paymentHelper;
tenantId = userHelper.GetTenantId();
organizaionId = userHelper.GetCurrentOrganizationId();
}
[HttpPost("create-order")]
public async Task<IActionResult> CreateOrder([FromBody] CreateOrderDto model)
{
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
try
{
var response = _paymentHelper.CreateOrder(model.Amount, loggedInEmployee, tenantId);
return Ok(ApiResponse<object>.SuccessResponse(response, "Payment created successfully", 200));
}
catch (Exception ex)
{
return StatusCode(500, ApiResponse<object>.ErrorResponse("Error occured While creating the payment", new
{
Message = ex.Message,
StackTrace = ex.StackTrace,
Source = ex.Source,
InnerException = new
{
Message = ex.InnerException?.Message,
StackTrace = ex.InnerException?.StackTrace,
Source = ex.InnerException?.Source,
}
}, 500));
}
}
[HttpPost("verify-payment")]
public IActionResult VerifyPayment([FromBody] PaymentVerificationRequest request)
{
string payload = request.OrderId + "|" + request.PaymentId;
string actualSignature = request.Signature ?? "";
string expectedSignature = _paymentHelper.GetExpectedSignature(payload);
if (actualSignature == expectedSignature)
{
// Payment is verified, process accordingly e.g. update tenant payment details
return Ok(new { status = "success" });
}
else
{
return BadRequest(new { status = "failure", message = "Invalid signature" });
}
}
}
}

View File

@ -0,0 +1,57 @@
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;
}
}
}

View File

@ -34,6 +34,7 @@
<PackageReference Include="Mime-Detective" Version="24.12.2" /> <PackageReference Include="Mime-Detective" Version="24.12.2" />
<PackageReference Include="Mime-Detective.Definitions.Exhaustive" Version="24.12.2" /> <PackageReference Include="Mime-Detective.Definitions.Exhaustive" Version="24.12.2" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" /> <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
<PackageReference Include="Razorpay" Version="3.3.2" />
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" /> <PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" /> <PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />

View File

@ -1,6 +1,6 @@
using Marco.Pms.CacheHelper;
using FirebaseAdmin; using FirebaseAdmin;
using Google.Apis.Auth.OAuth2; using Google.Apis.Auth.OAuth2;
using Marco.Pms.CacheHelper;
using Marco.Pms.DataAccess.Data; using Marco.Pms.DataAccess.Data;
using Marco.Pms.Helpers; using Marco.Pms.Helpers;
using Marco.Pms.Helpers.CacheHelper; using Marco.Pms.Helpers.CacheHelper;
@ -55,7 +55,7 @@ builder.Services.AddCors(options =>
policy.AllowAnyOrigin() policy.AllowAnyOrigin()
.AllowAnyMethod() .AllowAnyMethod()
.AllowAnyHeader() .AllowAnyHeader()
.WithExposedHeaders("Authorization"); .WithExposedHeaders("Authorization", "X-Request-ID", "X-Correlation-ID");
}); });
// A stricter policy for production (loaded from config) // A stricter policy for production (loaded from config)
@ -65,7 +65,8 @@ builder.Services.AddCors(options =>
{ {
policy.WithOrigins(allowedOrigins) policy.WithOrigins(allowedOrigins)
.AllowAnyMethod() .AllowAnyMethod()
.AllowAnyHeader(); .AllowAnyHeader()
.WithExposedHeaders("Authorization", "X-Request-ID", "X-Correlation-ID");
}); });
}); });
#endregion #endregion
@ -190,6 +191,7 @@ 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>();

View File

@ -9,7 +9,7 @@
"Title": "Dev" "Title": "Dev"
}, },
"ConnectionStrings": { "ConnectionStrings": {
"DefaultConnectionString": "Server=147.93.98.152;User ID=devuser;Password=AppUser@123$;Database=MarcoBMS1" "DefaultConnectionString": "Server=147.93.98.152;User ID=devuser;Password=AppUser@123$;Database=MarcoBMSStage"
}, },
"SmtpSettings": { "SmtpSettings": {
"SmtpServer": "smtp.gmail.com", "SmtpServer": "smtp.gmail.com",
@ -50,5 +50,9 @@
"SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs", "SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs",
"ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches?socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500", "ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches?socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500",
"ModificationConnectionString": "mongodb://devuser:DevPass123@147.93.98.152:27017/MarcoBMSLocalDev?authSource=admin&eplicaSet=rs01&directConnection=true" "ModificationConnectionString": "mongodb://devuser:DevPass123@147.93.98.152:27017/MarcoBMSLocalDev?authSource=admin&eplicaSet=rs01&directConnection=true"
},
"Razorpay": {
"Key": "rzp_test_RXCzgEcXucbuAi",
"Secret": "YNAVBXxRsDg8Oat4M1C3m09W"
} }
} }