Added Payment Request, Recurring Payment and Advance Payment Related Tables

This commit is contained in:
ashutosh.nehete 2025-11-01 10:38:05 +05:30
parent 68aec35028
commit b4677aacf3
15 changed files with 204 additions and 103 deletions

View File

@ -113,6 +113,11 @@ namespace Marco.Pms.DataAccess.Data
public DbSet<ExpensesReimburseMapping> ExpensesReimburseMapping { get; set; }
public DbSet<StatusPermissionMapping> StatusPermissionMapping { get; set; }
public DbSet<ExpensesStatusMapping> ExpensesStatusMapping { get; set; }
public DbSet<PaymentRequest> PaymentRequests { get; set; }
public DbSet<RecurringPayment> RecurringPayments { get; set; }
public DbSet<AdvancePaymentTransaction> AdvancePaymentTransactions { get; set; }
public DbSet<StatusUpdateLog> StatusUpdateLogs { get; set; }
public DbSet<FCMTokenMapping> FCMTokenMappings { get; set; }
@ -758,32 +763,49 @@ namespace Marco.Pms.DataAccess.Data
Id = Guid.Parse("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"),
Name = "Cash",
Description = "Physical currency; still used for small or informal transactions.",
IsActive = true,
TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26")
IsActive = true
},
new PaymentModeMatser
{
Id = Guid.Parse("48d9b462-5d87-4dec-8dec-2bc943943172"),
Name = "Cheque",
Description = "Paper-based payment order; less common now due to processing delays and fraud risks.",
IsActive = true,
TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26")
IsActive = true
},
new PaymentModeMatser
{
Id = Guid.Parse("ed667353-8eea-4fd1-8750-719405932480"),
Name = "NetBanking",
Description = "Online banking portals used to transfer funds directly between accounts",
IsActive = true,
TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26")
IsActive = true
},
new PaymentModeMatser
{
Id = Guid.Parse("2e919e94-694c-41d9-9489-0a2b4208a027"),
Name = "UPI",
Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.",
IsActive = true,
TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26")
IsActive = true
},
new PaymentModeMatser
{
Id = Guid.Parse("a820f240-5e9a-4ae9-9091-8a7aa7720cea"),
Name = "Credit card",
Description = "A credit card is a payment card that allows you to borrow funds from a financial institution to pay for goods and services",
IsActive = true
},
new PaymentModeMatser
{
Id = Guid.Parse("95697409-baf6-4f78-86ab-42d93d9569a8"),
Name = "Debit Card",
Description = "A debit card is a payment card that deducts funds directly from the cardholder's bank account when a purchase is made.",
IsActive = true
},
new PaymentModeMatser
{
Id = Guid.Parse("f67beee6-6763-4108-922c-03bd86b9178d"),
Name = "Advance Payment",
Description = "When a bill is paid using the amount received in advance from a company.",
IsActive = true
}
);

View File

@ -0,0 +1,27 @@
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Utilities;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System.ComponentModel.DataAnnotations.Schema;
namespace Marco.Pms.Model.Expenses
{
public class AdvancePaymentTransaction : TenantRelation
{
public Guid Id { get; set; }
public string FinanceUIdPrefix { get; set; } = default!;
public int FinanceUIdPostfix { get; set; }
public Guid EmployeeId { get; set; }
[ValidateNever]
[ForeignKey("EmployeeId")]
public Employee? Employee { get; set; }
public double Amount { get; set; }
public DateTime CreatedAt { get; set; }
public Guid CreatedById { get; set; }
[ValidateNever]
[ForeignKey("CreatedById")]
public Employee? CreatedBy { get; set; }
public bool IsActive { get; set; }
}
}

View File

@ -0,0 +1,53 @@
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Master;
using Marco.Pms.Model.Utilities;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System.ComponentModel.DataAnnotations.Schema;
namespace Marco.Pms.Model.Expenses
{
public class PaymentRequest : TenantRelation
{
public Guid Id { get; set; }
public string Title { get; set; } = default!;
public string Description { get; set; } = default!;
public string UIDPrefix { get; set; } = default!;
public int UIDPostfix { get; set; }
public string Payee { get; set; } = default!;
public Guid CurrencyId { get; set; }
[ValidateNever]
[ForeignKey("CurrencyId")]
public CurrencyMaster? Currency { get; set; }
public double Amount { get; set; }
public DateTime DueDate { get; set; }
public Guid? RecurringPaymentId { get; set; }
[ValidateNever]
[ForeignKey("RecurringPaymentId")]
public RecurringPayment? RecurringPayment { get; set; }
public Guid? ExpenseCategoryId { get; set; }
[ValidateNever]
[ForeignKey("ExpenseCategoryId")]
public ExpensesTypeMaster? ExpenseCategory { get; set; }
public Guid ExpenseStatusId { get; set; }
[ValidateNever]
[ForeignKey("ExpenseStatusId")]
public ExpensesStatusMaster? ExpenseStatus { get; set; }
public bool IsActive { get; set; }
public DateTime CreatedAt { get; set; }
public Guid CreatedById { get; set; }
[ValidateNever]
[ForeignKey("CreatedById")]
public Employee? CreatedBy { get; set; }
public DateTime UpdatedAt { get; set; }
public Guid UpdatedById { get; set; }
[ValidateNever]
[ForeignKey("UpdatedById")]
public Employee? UpdatedBy { get; set; }
}
}

View File

@ -0,0 +1,60 @@
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Master;
using Marco.Pms.Model.TenantModels;
using Marco.Pms.Model.Utilities;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System.ComponentModel.DataAnnotations.Schema;
namespace Marco.Pms.Model.Expenses
{
public class RecurringPayment : TenantRelation
{
public Guid Id { get; set; }
public string Title { get; set; } = default!;
public string Description { get; set; } = default!;
public string UIDPrefix { get; set; } = default!;
public int UIDPostfix { get; set; }
public string Payee { get; set; } = default!;
public string NotifyTo { get; set; } = default!;
public Guid CurrencyId { get; set; }
[ValidateNever]
[ForeignKey("CurrencyId")]
public CurrencyMaster? Currency { get; set; }
public double Amount { get; set; }
public DateTime StrikeDate { get; set; }
public DateTime LatestPRGeneratedAt { get; set; }
public int PaymentBufferDays { get; set; }
public int NumberOfIteration { get; set; }
public Guid? ExpenseCategoryId { get; set; }
[ValidateNever]
[ForeignKey("ExpenseCategoryId")]
public ExpensesTypeMaster? ExpenseCategory { get; set; }
public Guid ExpenseStatusId { get; set; }
[ValidateNever]
[ForeignKey("ExpenseStatusId")]
public ExpensesStatusMaster? ExpenseStatus { get; set; }
public Guid StatusId { get; set; }
[ValidateNever]
[ForeignKey("StatusId")]
public ExpensesStatusMaster? Status { get; set; }
public PLAN_FREQUENCY Frequency { get; set; }
public bool IsVariable { get; set; }
public bool IsActive { get; set; }
public DateTime CreatedAt { get; set; }
public Guid CreatedById { get; set; }
[ValidateNever]
[ForeignKey("CreatedById")]
public Employee? CreatedBy { get; set; }
public DateTime UpdatedAt { get; set; }
public Guid UpdatedById { get; set; }
[ValidateNever]
[ForeignKey("UpdatedById")]
public Employee? UpdatedBy { get; set; }
}
}

View File

@ -1,8 +1,6 @@
using Marco.Pms.Model.Utilities;
namespace Marco.Pms.Model.Master
namespace Marco.Pms.Model.Master
{
public class PaymentModeMatser : TenantRelation
public class PaymentModeMatser
{
public Guid Id { get; set; }
public string Name { get; set; } = string.Empty;

View File

@ -0,0 +1,21 @@
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Utilities;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System.ComponentModel.DataAnnotations.Schema;
namespace Marco.Pms.Model.Master
{
public class StatusUpdateLog : TenantRelation
{
public Guid Id { get; set; }
public Guid StatusId { get; set; }
public Guid EntityId { get; set; }
public string? Comment { get; set; }
public DateTime UpdatedAt { get; set; }
public Guid UpdatedById { get; set; }
[ValidateNever]
[ForeignKey("UpdatedById")]
public Employee? UpdatedBy { get; set; }
}
}

View File

@ -5,6 +5,5 @@
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string TenantId { get; set; } = string.Empty;
}
}

View File

@ -10,6 +10,6 @@
public enum PLAN_FREQUENCY
{
MONTHLY = 0, QUARTERLY = 1, HALF_YEARLY = 2, YEARLY = 3
MONTHLY = 0, QUARTERLY = 1, HALF_YEARLY = 2, YEARLY = 3, DAILY = 4
}
}

View File

@ -659,7 +659,6 @@ namespace Marco.Pms.Services.Controllers
var _masteData = scope.ServiceProvider.GetRequiredService<MasterDataService>();
var expensesTypeMaster = _masteData.GetExpensesTypeesData(tenant.Id);
var paymentModeMatser = _masteData.GetPaymentModesData(tenant.Id);
var documentCategoryMaster = _masteData.GetDocumentCategoryData(tenant.Id);
var employeeDocumentId = documentCategoryMaster.Where(dc => dc.Name == "Employee Documents").Select(dc => dc.Id).FirstOrDefault();
@ -668,7 +667,6 @@ namespace Marco.Pms.Services.Controllers
var documentTypeMaster = _masteData.GetDocumentTypeData(tenant.Id, employeeDocumentId, projectDocumentId);
_context.ExpensesTypeMaster.AddRange(expensesTypeMaster);
_context.PaymentModeMatser.AddRange(paymentModeMatser);
_context.DocumentCategoryMasters.AddRange(documentCategoryMaster);
_context.DocumentTypeMasters.AddRange(documentTypeMaster);
@ -1216,10 +1214,8 @@ namespace Marco.Pms.Services.Controllers
if (features.Modules?.Expense?.Enabled ?? false)
{
var expensesTypeMaster = _masteData.GetExpensesTypeesData(tenant.Id);
var paymentModeMatser = _masteData.GetPaymentModesData(tenant.Id);
_context.ExpensesTypeMaster.AddRange(expensesTypeMaster);
_context.PaymentModeMatser.AddRange(paymentModeMatser);
}
await _context.SaveChangesAsync();
@ -1552,7 +1548,6 @@ namespace Marco.Pms.Services.Controllers
if (features.Modules?.Expense?.Enabled ?? false)
{
var expensesTypeMaster = _masteData.GetExpensesTypeesData(tenant.Id);
var paymentModeMatser = _masteData.GetPaymentModesData(tenant.Id);
var expensesTypeTask = Task.Run(async () =>
{
@ -1560,25 +1555,14 @@ namespace Marco.Pms.Services.Controllers
var expensesTypeNames = expensesTypeMaster.Select(et => et.Name).ToList();
return await _context.ExpensesTypeMaster.AnyAsync(et => expensesTypeNames.Contains(et.Name) && et.TenantId == tenant.Id);
});
var paymentModeTask = Task.Run(async () =>
{
await using var _context = await _dbContextFactory.CreateDbContextAsync();
var paymentModeNames = paymentModeMatser.Select(py => py.Name).ToList();
return await _context.PaymentModeMatser.AnyAsync(py => paymentModeNames.Contains(py.Name) && py.TenantId == tenant.Id);
});
await Task.WhenAll(expensesTypeTask, paymentModeTask);
await Task.WhenAll(expensesTypeTask);
var expensesTypeExist = expensesTypeTask.Result;
var paymentModeExist = paymentModeTask.Result;
if (!expensesTypeExist)
{
context.ExpensesTypeMaster.AddRange(expensesTypeMaster);
}
if (!paymentModeExist)
{
context.PaymentModeMatser.AddRange(paymentModeMatser);
}
}
await context.SaveChangesAsync();

View File

@ -1190,7 +1190,7 @@ namespace Marco.Pms.Services.Helpers
var paymentModeTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.PaymentModeMatser.AsNoTracking().Where(pm => paymentModeIds.Contains(pm.Id) && pm.TenantId == tenantId).ToListAsync();
return await dbContext.PaymentModeMatser.AsNoTracking().Where(pm => paymentModeIds.Contains(pm.Id)).ToListAsync();
});
var statusMappingTask = Task.Run(async () =>
{
@ -1320,7 +1320,7 @@ namespace Marco.Pms.Services.Helpers
var paymentModeTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == model.PaymentModeId && pm.TenantId == tenantId);
return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == model.PaymentModeId);
});
var statusMappingTask = Task.Run(async () =>
{

View File

@ -385,10 +385,7 @@ namespace Marco.Pms.Services.MappingProfiles
CreateMap<PaymentModeMatser, PaymentModeMatserMongoDB>()
.ForMember(
dest => dest.Id,
opt => opt.MapFrom(src => src.Id.ToString()))
.ForMember(
dest => dest.TenantId,
opt => opt.MapFrom(src => src.TenantId.ToString()));
opt => opt.MapFrom(src => src.Id.ToString()));
CreateMap<PaymentModeMatserMongoDB, PaymentModeMatserVM>()
.ForMember(

View File

@ -1136,7 +1136,7 @@ namespace Marco.Pms.Services.Service
var paymentModeTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.PaymentModeMatser.AsNoTracking().Where(pm => paymentModeIds.Contains(pm.Id) && pm.TenantId == tenantId).ToListAsync();
return await dbContext.PaymentModeMatser.AsNoTracking().Where(pm => paymentModeIds.Contains(pm.Id)).ToListAsync();
});
var statusMappingTask = Task.Run(async () =>
{

View File

@ -298,44 +298,6 @@ namespace Marco.Pms.Services.Service
}
};
}
public List<PaymentModeMatser> GetPaymentModesData(Guid tenantId)
{
return new List<PaymentModeMatser>
{
new PaymentModeMatser
{
Id = Guid.NewGuid(),
Name = "Cash",
Description = "Physical currency; still used for small or informal transactions.",
IsActive = true,
TenantId = tenantId
},
new PaymentModeMatser
{
Id = Guid.NewGuid(),
Name = "Cheque",
Description = "Paper-based payment order; less common now due to processing delays and fraud risks.",
IsActive = true,
TenantId = tenantId
},
new PaymentModeMatser
{
Id = Guid.NewGuid(),
Name = "NetBanking",
Description = "Online banking portals used to transfer funds directly between accounts",
IsActive = true,
TenantId = tenantId
},
new PaymentModeMatser
{
Id = Guid.NewGuid(),
Name = "UPI",
Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.",
IsActive = true,
TenantId = tenantId
}
};
}
public List<DocumentCategoryMaster> GetDocumentCategoryData(Guid tenantId)
{
return new List<DocumentCategoryMaster> {

View File

@ -2259,7 +2259,7 @@ namespace Marco.Pms.Services.Service
try
{
// Featching the list of Payment Modes.
var paymentModes = await _context.PaymentModeMatser.Where(pm => pm.TenantId == tenantId && pm.IsActive == isActive).ToListAsync();
var paymentModes = await _context.PaymentModeMatser.Where(pm => pm.IsActive == isActive).ToListAsync();
var response = _mapper.Map<List<PaymentModeMatserVM>>(paymentModes);
_logger.LogInfo("{Count} records of payment modes have been fetched successfully by employee {EmployeeId}", response.Count, loggedInEmployee.Id);
@ -2284,7 +2284,6 @@ namespace Marco.Pms.Services.Service
}
// Mapping the DTO to PaymentModeMatser Model
var paymentMode = _mapper.Map<PaymentModeMatser>(model);
paymentMode.TenantId = tenantId;
_context.PaymentModeMatser.Add(paymentMode);
await _context.SaveChangesAsync();
@ -2325,7 +2324,7 @@ namespace Marco.Pms.Services.Service
return ApiResponse<object>.ErrorResponse("Invalid Data", "User has send invalid payload", 400);
}
var paymentMode = await _context.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(et => et.Id == model.Id.Value && et.TenantId == tenantId);
var paymentMode = await _context.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(et => et.Id == model.Id.Value);
// Checking if Payment Mode exists
if (paymentMode == null)
@ -2383,7 +2382,7 @@ namespace Marco.Pms.Services.Service
return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403);
}
var paymentMode = await _context.PaymentModeMatser.FirstOrDefaultAsync(et => et.Id == id && et.TenantId == tenantId);
var paymentMode = await _context.PaymentModeMatser.FirstOrDefaultAsync(et => et.Id == id);
// Checking if Payment Mode exists
if (paymentMode == null)

View File

@ -525,10 +525,8 @@ namespace Marco.Pms.Services.Service
if (features.Modules?.Expense?.Enabled ?? false)
{
var expensesTypeMaster = _masteData.GetExpensesTypeesData(tenant.Id);
var paymentModeMatser = _masteData.GetPaymentModesData(tenant.Id);
_context.ExpensesTypeMaster.AddRange(expensesTypeMaster);
_context.PaymentModeMatser.AddRange(paymentModeMatser);
}
await _context.SaveChangesAsync();
@ -809,33 +807,14 @@ namespace Marco.Pms.Services.Service
if (features.Modules?.Expense?.Enabled ?? false)
{
var expensesTypeMaster = _masteData.GetExpensesTypeesData(tenant.Id);
var paymentModeMatser = _masteData.GetPaymentModesData(tenant.Id);
var expensesTypeTask = Task.Run(async () =>
{
await using var _context = await _dbContextFactory.CreateDbContextAsync();
var expensesTypeNames = expensesTypeMaster.Select(et => et.Name).ToList();
return await _context.ExpensesTypeMaster.AnyAsync(et => expensesTypeNames.Contains(et.Name) && et.TenantId == tenant.Id);
});
var paymentModeTask = Task.Run(async () =>
{
await using var _context = await _dbContextFactory.CreateDbContextAsync();
var paymentModeNames = paymentModeMatser.Select(py => py.Name).ToList();
return await _context.PaymentModeMatser.AnyAsync(py => paymentModeNames.Contains(py.Name) && py.TenantId == tenant.Id);
});
var expensesTypeNames = expensesTypeMaster.Select(et => et.Name).ToList();
await Task.WhenAll(expensesTypeTask, paymentModeTask);
var expensesTypeExist = expensesTypeTask.Result;
var paymentModeExist = paymentModeTask.Result;
var expensesTypeExist = await context.ExpensesTypeMaster.AnyAsync(et => expensesTypeNames.Contains(et.Name) && et.TenantId == tenant.Id);
if (!expensesTypeExist)
{
context.ExpensesTypeMaster.AddRange(expensesTypeMaster);
}
if (!paymentModeExist)
{
context.PaymentModeMatser.AddRange(paymentModeMatser);
}
}
await context.SaveChangesAsync();