created the shell API to create payment request

This commit is contained in:
ashutosh.nehete 2025-11-01 15:09:54 +05:30
parent e3b418560b
commit e821724e83
11 changed files with 7527 additions and 14 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,145 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Marco.Pms.DataAccess.Migrations
{
/// <inheritdoc />
public partial class Made_UpdatedBy_And_UpdateAt_As_Nullable : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_PaymentRequests_Employees_UpdatedById",
table: "PaymentRequests");
migrationBuilder.DropForeignKey(
name: "FK_RecurringPayments_Employees_UpdatedById",
table: "RecurringPayments");
migrationBuilder.AlterColumn<Guid>(
name: "UpdatedById",
table: "RecurringPayments",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)")
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AlterColumn<DateTime>(
name: "UpdatedAt",
table: "RecurringPayments",
type: "datetime(6)",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "datetime(6)");
migrationBuilder.AlterColumn<Guid>(
name: "UpdatedById",
table: "PaymentRequests",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)")
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AlterColumn<DateTime>(
name: "UpdatedAt",
table: "PaymentRequests",
type: "datetime(6)",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "datetime(6)");
migrationBuilder.AddForeignKey(
name: "FK_PaymentRequests_Employees_UpdatedById",
table: "PaymentRequests",
column: "UpdatedById",
principalTable: "Employees",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_RecurringPayments_Employees_UpdatedById",
table: "RecurringPayments",
column: "UpdatedById",
principalTable: "Employees",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_PaymentRequests_Employees_UpdatedById",
table: "PaymentRequests");
migrationBuilder.DropForeignKey(
name: "FK_RecurringPayments_Employees_UpdatedById",
table: "RecurringPayments");
migrationBuilder.AlterColumn<Guid>(
name: "UpdatedById",
table: "RecurringPayments",
type: "char(36)",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)",
oldNullable: true)
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AlterColumn<DateTime>(
name: "UpdatedAt",
table: "RecurringPayments",
type: "datetime(6)",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
oldClrType: typeof(DateTime),
oldType: "datetime(6)",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "UpdatedById",
table: "PaymentRequests",
type: "char(36)",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)",
oldNullable: true)
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AlterColumn<DateTime>(
name: "UpdatedAt",
table: "PaymentRequests",
type: "datetime(6)",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
oldClrType: typeof(DateTime),
oldType: "datetime(6)",
oldNullable: true);
migrationBuilder.AddForeignKey(
name: "FK_PaymentRequests_Employees_UpdatedById",
table: "PaymentRequests",
column: "UpdatedById",
principalTable: "Employees",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_RecurringPayments_Employees_UpdatedById",
table: "RecurringPayments",
column: "UpdatedById",
principalTable: "Employees",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}

View File

@ -2460,10 +2460,10 @@ namespace Marco.Pms.DataAccess.Migrations
.IsRequired() .IsRequired()
.HasColumnType("longtext"); .HasColumnType("longtext");
b.Property<DateTime>("UpdatedAt") b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime(6)"); .HasColumnType("datetime(6)");
b.Property<Guid>("UpdatedById") b.Property<Guid?>("UpdatedById")
.HasColumnType("char(36)"); .HasColumnType("char(36)");
b.HasKey("Id"); b.HasKey("Id");
@ -2564,10 +2564,10 @@ namespace Marco.Pms.DataAccess.Migrations
.IsRequired() .IsRequired()
.HasColumnType("longtext"); .HasColumnType("longtext");
b.Property<DateTime>("UpdatedAt") b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime(6)"); .HasColumnType("datetime(6)");
b.Property<Guid>("UpdatedById") b.Property<Guid?>("UpdatedById")
.HasColumnType("char(36)"); .HasColumnType("char(36)");
b.HasKey("Id"); b.HasKey("Id");
@ -6395,9 +6395,7 @@ namespace Marco.Pms.DataAccess.Migrations
b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy")
.WithMany() .WithMany()
.HasForeignKey("UpdatedById") .HasForeignKey("UpdatedById");
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CreatedBy"); b.Navigation("CreatedBy");
@ -6458,9 +6456,7 @@ namespace Marco.Pms.DataAccess.Migrations
b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy")
.WithMany() .WithMany()
.HasForeignKey("UpdatedById") .HasForeignKey("UpdatedById");
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CreatedBy"); b.Navigation("CreatedBy");

View File

@ -0,0 +1,15 @@
namespace Marco.Pms.Model.Dtos.Expenses
{
public class PaymentRequestDto
{
public Guid? Id { get; set; }
public required string Title { get; set; }
public required string Description { get; set; }
public required string Payee { get; set; }
public required Guid CurrencyId { get; set; }
public required double Amount { get; set; }
public required DateTime DueDate { get; set; }
public Guid? ProjectId { get; set; }
public required Guid ExpenseCategoryId { get; set; }
}
}

View File

@ -49,8 +49,8 @@ namespace Marco.Pms.Model.Expenses
[ValidateNever] [ValidateNever]
[ForeignKey("CreatedById")] [ForeignKey("CreatedById")]
public Employee? CreatedBy { get; set; } public Employee? CreatedBy { get; set; }
public DateTime UpdatedAt { get; set; } public DateTime? UpdatedAt { get; set; }
public Guid UpdatedById { get; set; } public Guid? UpdatedById { get; set; }
[ValidateNever] [ValidateNever]
[ForeignKey("UpdatedById")] [ForeignKey("UpdatedById")]

View File

@ -56,8 +56,8 @@ namespace Marco.Pms.Model.Expenses
[ValidateNever] [ValidateNever]
[ForeignKey("CreatedById")] [ForeignKey("CreatedById")]
public Employee? CreatedBy { get; set; } public Employee? CreatedBy { get; set; }
public DateTime UpdatedAt { get; set; } public DateTime? UpdatedAt { get; set; }
public Guid UpdatedById { get; set; } public Guid? UpdatedById { get; set; }
[ValidateNever] [ValidateNever]
[ForeignKey("UpdatedById")] [ForeignKey("UpdatedById")]

View File

@ -0,0 +1,30 @@
using Marco.Pms.Model.Expenses;
using Marco.Pms.Model.Master;
using Marco.Pms.Model.ViewModels.Activities;
using Marco.Pms.Model.ViewModels.Master;
using Marco.Pms.Model.ViewModels.Projects;
namespace Marco.Pms.Model.ViewModels.Expenses
{
public class PaymentRequestVM
{
public Guid Id { get; set; }
public string? Title { get; set; }
public string? Description { get; set; }
public string? PaymentRequestUID { get; set; }
public string? Payee { get; set; }
public CurrencyMaster? Currency { get; set; }
public double Amount { get; set; }
public DateTime DueDate { get; set; }
public BasicProjectVM? Project { get; set; }
public RecurringPayment? RecurringPayment { get; set; }
public ExpensesTypeMasterVM? ExpenseCategory { get; set; }
public ExpensesStatusMasterVM? ExpenseStatus { get; set; }
public bool IsActive { get; set; }
public DateTime CreatedAt { get; set; }
public BasicEmployeeVM? CreatedBy { get; set; }
public DateTime? UpdatedAt { get; set; }
public Guid? UpdatedById { get; set; }
public BasicEmployeeVM? UpdatedBy { get; set; }
}
}

View File

@ -29,6 +29,7 @@ namespace Marco.Pms.Services.Controllers
tenantId = userHelper.GetTenantId(); tenantId = userHelper.GetTenantId();
} }
#region =================================================================== Expense Functions ===================================================================
/// <summary> /// <summary>
/// Retrieves a paginated list of expenses based on user permissions and optional filters. /// Retrieves a paginated list of expenses based on user permissions and optional filters.
@ -122,5 +123,21 @@ namespace Marco.Pms.Services.Controllers
return StatusCode(response.StatusCode, response); return StatusCode(response.StatusCode, response);
} }
#endregion
#region =================================================================== Payment Request Functions ===================================================================
[HttpPost("payment-request/create")]
public async Task<IActionResult> CreatePaymentRequest([FromBody] PaymentRequestDto model)
{
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _expensesService.CreatePaymentRequestAsync(model, loggedInEmployee, tenantId);
if (response.Success)
{
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Payment_Request", Response = response.Data };
await _signalR.SendNotificationAsync(notification);
}
return StatusCode(response.StatusCode, response);
}
#endregion
} }
} }

View File

@ -257,6 +257,10 @@ namespace Marco.Pms.Services.MappingProfiles
.ForMember( .ForMember(
dest => dest.Id, dest => dest.Id,
opt => opt.MapFrom(src => Guid.Parse(src.Id))); opt => opt.MapFrom(src => Guid.Parse(src.Id)));
#region ======================================================= Payment Request =======================================================
CreateMap<PaymentRequestDto, PaymentRequest>();
CreateMap<PaymentRequest, PaymentRequestVM>();
#endregion
#endregion #endregion

View File

@ -66,6 +66,8 @@ namespace Marco.Pms.Services.Service
_mapper = mapper; _mapper = mapper;
} }
#region =================================================================== Expense Functions ===================================================================
#region =================================================================== Get Functions =================================================================== #region =================================================================== Get Functions ===================================================================
/// <summary> /// <summary>
@ -1079,6 +1081,90 @@ namespace Marco.Pms.Services.Service
#endregion #endregion
#endregion
#region =================================================================== Payment Request Functions ===================================================================
public async Task<ApiResponse<object>> CreatePaymentRequestAsync(PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId)
{
string uIDPrefix = $"PY/{DateTime.Now.ToString("MMyy")}";
var expenseCategoryTask = Task.Run(async () =>
{
await using var context = await _dbContextFactory.CreateDbContextAsync();
return await context.ExpensesTypeMaster.FirstOrDefaultAsync(et => et.Id == model.ExpenseCategoryId && et.IsActive);
});
var currencyTask = Task.Run(async () =>
{
await using var context = await _dbContextFactory.CreateDbContextAsync();
return await context.CurrencyMaster.FirstOrDefaultAsync(c => c.Id == model.CurrencyId);
});
var expenseStatusTask = Task.Run(async () =>
{
await using var context = await _dbContextFactory.CreateDbContextAsync();
return await context.ExpensesStatusMaster.FirstOrDefaultAsync(es => es.Id == Draft && es.IsActive);
});
var projectTask = Task.Run(async () =>
{
await using var context = await _dbContextFactory.CreateDbContextAsync();
return await context.Projects.FirstOrDefaultAsync(P => model.ProjectId.HasValue && P.Id == model.ProjectId.Value);
});
await Task.WhenAll(expenseCategoryTask, currencyTask, expenseStatusTask, projectTask);
var expenseCategory = expenseCategoryTask.Result;
if (expenseCategory == null)
{
return ApiResponse<object>.ErrorResponse("Expense Category not found", "Expense Category not found", 404);
}
var currency = currencyTask.Result;
if (currency == null)
{
return ApiResponse<object>.ErrorResponse("Currency not found", "Currency not found", 404);
}
var expenseStatus = expenseStatusTask.Result;
if (expenseCategory == null)
{
return ApiResponse<object>.ErrorResponse("Expense Status not found", "Expense Status not found", 404);
}
var project = projectTask.Result;
var lastPR = await _context.PaymentRequests.Where(pr => pr.UIDPrefix == uIDPrefix).OrderByDescending(pr => pr.UIDPostfix).FirstOrDefaultAsync();
int uIDPostfix = lastPR == null ? 1 : (lastPR.UIDPostfix + 1);
var paymentRequest = _mapper.Map<PaymentRequest>(model);
paymentRequest.ExpenseStatusId = Draft;
paymentRequest.UIDPrefix = uIDPrefix;
paymentRequest.UIDPostfix = uIDPostfix;
paymentRequest.IsActive = true;
paymentRequest.CreatedAt = DateTime.UtcNow;
paymentRequest.CreatedById = loggedInEmployee.Id;
paymentRequest.TenantId = tenantId;
var response = _mapper.Map<PaymentRequestVM>(paymentRequest);
response.PaymentRequestUID = $"{paymentRequest.UIDPrefix}/{paymentRequest.UIDPostfix.ToString("D5")}";
response.Currency = currency;
response.ExpenseCategory = _mapper.Map<ExpensesTypeMasterVM>(expenseCategory);
response.ExpenseStatus = _mapper.Map<ExpensesStatusMasterVM>(expenseStatus);
response.Project = _mapper.Map<BasicProjectVM>(project);
response.CreatedBy = _mapper.Map<BasicEmployeeVM>(loggedInEmployee);
return ApiResponse<object>.SuccessResponse(response, "Created the Payment Request Successfully", 201);
}
#endregion
#region =================================================================== Payment Request Functions ===================================================================
#endregion
#region =================================================================== Payment Request Functions ===================================================================
#endregion
#region =================================================================== Helper Functions =================================================================== #region =================================================================== Helper Functions ===================================================================
private int ExtractNumber(string id) private int ExtractNumber(string id)

View File

@ -14,5 +14,8 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
Task<ApiResponse<object>> ChangeStatusAsync(ExpenseRecordDto model, Employee loggedInEmployee, Guid tenantId); Task<ApiResponse<object>> ChangeStatusAsync(ExpenseRecordDto model, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId); Task<ApiResponse<object>> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> DeleteExpanseAsync(Guid id, Employee loggedInEmployee, Guid tenantId); Task<ApiResponse<object>> DeleteExpanseAsync(Guid id, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> CreatePaymentRequestAsync(PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId);
} }
} }