Added crude get payment request list API
This commit is contained in:
parent
be0230c265
commit
bb14204d65
13
Marco.Pms.Model/Filters/PaymentRequestFilter.cs
Normal file
13
Marco.Pms.Model/Filters/PaymentRequestFilter.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace Marco.Pms.Model.Filters
|
||||
{
|
||||
public class PaymentRequestFilter
|
||||
{
|
||||
public List<Guid>? ProjectIds { get; set; }
|
||||
public List<Guid>? StatusIds { get; set; }
|
||||
public List<Guid>? CreatedByIds { get; set; }
|
||||
public List<Guid>? CurrencyIds { get; set; }
|
||||
public List<Guid>? ExpenseCategoryIds { get; set; }
|
||||
public DateTime? StartDate { get; set; }
|
||||
public DateTime? EndDate { get; set; }
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,6 @@
|
||||
|
||||
public enum PLAN_FREQUENCY
|
||||
{
|
||||
MONTHLY = 0, QUARTERLY = 1, HALF_YEARLY = 2, YEARLY = 3, DAILY = 4
|
||||
MONTHLY = 0, QUARTERLY = 1, HALF_YEARLY = 2, YEARLY = 3, DAILY = 4, WEEKLY = 5
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,18 +123,17 @@ namespace Marco.Pms.Services.Controllers
|
||||
return StatusCode(response.StatusCode, response);
|
||||
}
|
||||
|
||||
[HttpGet("/get/transactions/{employeeId}")]
|
||||
public async Task<IActionResult> GetAdvancePaymentTransaction(Guid employeeId)
|
||||
{
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var response = await _expensesService.GetAdvancePaymentTransactionAsync(employeeId);
|
||||
|
||||
return StatusCode(response.StatusCode, response);
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Payment Request Functions ===================================================================
|
||||
|
||||
[HttpGet("get/payment-requests/list")]
|
||||
public async Task<IActionResult> GetPaymentRequestList([FromQuery] string? searchString, [FromQuery] string? filter, [FromQuery] bool isActive = true, [FromQuery] int pageSize = 20, [FromQuery] int pageNumber = 1)
|
||||
{
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var response = await _expensesService.GetPaymentRequestListAsync(searchString, filter, isActive, pageSize, pageNumber, loggedInEmployee, tenantId);
|
||||
return StatusCode(response.StatusCode, response);
|
||||
}
|
||||
[HttpPost("payment-request/create")]
|
||||
public async Task<IActionResult> CreatePaymentRequest([FromBody] PaymentRequestDto model)
|
||||
{
|
||||
@ -160,5 +159,19 @@ namespace Marco.Pms.Services.Controllers
|
||||
return StatusCode(response.StatusCode, response);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Advance Payment Functions ===================================================================
|
||||
|
||||
[HttpGet("/get/transactions/{employeeId}")]
|
||||
public async Task<IActionResult> GetAdvancePaymentTransaction(Guid employeeId)
|
||||
{
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var response = await _expensesService.GetAdvancePaymentTransactionAsync(employeeId);
|
||||
|
||||
return StatusCode(response.StatusCode, response);
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ using Marco.Pms.Model.Dtos.Expenses;
|
||||
using Marco.Pms.Model.Employees;
|
||||
using Marco.Pms.Model.Entitlements;
|
||||
using Marco.Pms.Model.Expenses;
|
||||
using Marco.Pms.Model.Filters;
|
||||
using Marco.Pms.Model.MongoDBModels;
|
||||
using Marco.Pms.Model.MongoDBModels.Employees;
|
||||
using Marco.Pms.Model.MongoDBModels.Expenses;
|
||||
@ -290,19 +291,11 @@ namespace Marco.Pms.Services.Service
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
if(string.IsNullOrWhiteSpace(financeUId))
|
||||
return ApiResponse<object>.ErrorResponse("Finance UID is required.", null, 400);
|
||||
|
||||
var parts = financeUId.Split('-');
|
||||
if (parts.Length != 2)
|
||||
return ApiResponse<object>.ErrorResponse("Invalid Finance UID format.", null, 400);
|
||||
|
||||
var prefix = parts[0];
|
||||
var postfixStr = parts[1];
|
||||
|
||||
if (!int.TryParse(postfixStr, out int postfix))
|
||||
return ApiResponse<object>.ErrorResponse("Invalid Finance UID number format.", null, 400);
|
||||
if (!id.HasValue && string.IsNullOrWhiteSpace(financeUId))
|
||||
{
|
||||
_logger.LogWarning("User do not provided id nor expenseUId");
|
||||
return ApiResponse<object>.ErrorResponse("Id or ExpenseUId atleast one must be provided", "Id or ExpenseUId atleast one must be provided", 400);
|
||||
}
|
||||
ExpenseDetailsMongoDB? expenseDetails = null;
|
||||
if (expenseDetails == null)
|
||||
{
|
||||
@ -320,8 +313,15 @@ namespace Marco.Pms.Services.Service
|
||||
.AsNoTracking().FirstOrDefaultAsync(e => (e.Id == id || e.ExpenseUId == financeUId) && e.TenantId == tenantId);
|
||||
|
||||
if (expense == null)
|
||||
{
|
||||
if (id.HasValue)
|
||||
{
|
||||
_logger.LogWarning("User attempted to fetch expense details with ID {ExpenseId}, but not found in both database and cache", id);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(financeUId))
|
||||
{
|
||||
_logger.LogWarning("User attempted to fetch expense details with expenseUId {ExpenseUId}, but not found in both database and cache", financeUId);
|
||||
}
|
||||
return ApiResponse<object>.ErrorResponse("Expense Not Found", "Expense Not Found", 404);
|
||||
}
|
||||
expenseDetails = await GetAllExpnesRelatedTablesForSingle(expense, expense.TenantId);
|
||||
@ -387,7 +387,7 @@ namespace Marco.Pms.Services.Service
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "An unhandled exception occurred while fetching an expense details {ExpenseId}.", id);
|
||||
_logger.LogError(ex, "An unhandled exception occurred while fetching an expense details {ExpenseId} or {ExpenseUId}.", id ?? Guid.Empty, financeUId ?? "");
|
||||
return ApiResponse<object>.ErrorResponse("An internal server error occurred.", ExceptionMapper(ex), 500);
|
||||
}
|
||||
}
|
||||
@ -436,60 +436,6 @@ namespace Marco.Pms.Services.Service
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse<object>> GetAdvancePaymentTransactionAsync(Guid employeeId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transactions = await _context.AdvancePaymentTransactions
|
||||
.Include(t => t.Employee)
|
||||
.Include(t => t.CreatedBy)
|
||||
.Where(t => t.EmployeeId == employeeId && t.IsActive)
|
||||
.OrderByDescending(t => t.CreatedAt)
|
||||
//.Select(t => new AdvancePaymentTransactionVM
|
||||
//{
|
||||
// Id = t.Id,
|
||||
// FinanceUId = t.FinanceUIdPrefix + "/" + t.FinanceUIdPostfix,
|
||||
// Amount = t.Amount,
|
||||
// CreatedAt = t.CreatedAt,
|
||||
// IsActive = t.IsActive,
|
||||
// Employee = t.Employee == null ? null : new BasicEmployeeVM
|
||||
// {
|
||||
// Id = t.Employee.Id,
|
||||
// FirstName = t.Employee.FirstName,
|
||||
// LastName = t.Employee.LastName,
|
||||
// },
|
||||
// CreatedBy = t.CreatedBy == null ? null : new BasicEmployeeVM
|
||||
// {
|
||||
// Id = t.CreatedBy.Id,
|
||||
// FirstName = t.Employee.FirstName,
|
||||
// LastName = t.Employee.LastName,
|
||||
// }
|
||||
//})
|
||||
.ToListAsync();
|
||||
|
||||
if (transactions == null || !transactions.Any())
|
||||
return ApiResponse<object>.ErrorResponse("No advance payment transactions found.", null, 404);
|
||||
|
||||
var response = transactions.Select(transaction =>
|
||||
{
|
||||
var result = _mapper.Map<AdvancePaymentTransactionVM>(transaction);
|
||||
result.FinanceUId = transaction.FinanceUIdPrefix + "/" + transaction.FinanceUIdPostfix.ToString("D5");
|
||||
return result;
|
||||
}).ToList();
|
||||
|
||||
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(response, "Advance payment transaction fetched successfully", 200);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception occurred while fetching the list of Advance Payment Transactions.");
|
||||
return ApiResponse<object>.ErrorResponse("Internal exception occurred.", ExceptionMapper(ex), 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Post Functions ===================================================================
|
||||
@ -1151,6 +1097,71 @@ namespace Marco.Pms.Services.Service
|
||||
|
||||
#region =================================================================== Payment Request Functions ===================================================================
|
||||
|
||||
public async Task<ApiResponse<object>> GetPaymentRequestListAsync(string? searchString, string? filter, bool isActive, int pageSize, int pageNumber, Employee loggedInEmployee, Guid tenantId)
|
||||
{
|
||||
var paymentRequestQuery = _context.PaymentRequests
|
||||
.Include(pr => pr.Currency)
|
||||
.Include(pr => pr.Project)
|
||||
.Include(pr => pr.RecurringPayment)
|
||||
.Include(pr => pr.ExpenseCategory)
|
||||
.Include(pr => pr.ExpenseStatus)
|
||||
.Include(pr => pr.CreatedBy)
|
||||
.ThenInclude(e => e!.JobRole)
|
||||
.Where(pr => pr.TenantId == tenantId &&
|
||||
pr.IsActive == isActive &&
|
||||
pr.Currency != null &&
|
||||
pr.ExpenseCategory != null &&
|
||||
pr.ExpenseStatus != null &&
|
||||
pr.CreatedBy != null &&
|
||||
pr.CreatedBy.JobRole != null);
|
||||
|
||||
//PaymentRequestFilter? paymentRequestFilter = TryDeserializePaymentRequestFilter(filter);
|
||||
|
||||
//if (paymentRequestFilter != null)
|
||||
//{
|
||||
// if (paymentRequestFilter.ProjectIds?.Any() ?? false)
|
||||
// {
|
||||
// paymentRequestQuery = paymentRequestQuery
|
||||
// .Where(pr => pr.ProjectId.HasValue &&
|
||||
// paymentRequestFilter.ProjectIds.Contains(pr.ProjectId.Value));
|
||||
// }
|
||||
// if (paymentRequestFilter.StatusIds?.Any() ?? false)
|
||||
// {
|
||||
// paymentRequestQuery = paymentRequestQuery
|
||||
// .Where(pr => paymentRequestFilter.StatusIds.Contains(pr.ExpenseStatusId));
|
||||
// }
|
||||
// if (paymentRequestFilter.CreatedByIds?.Any() ?? false)
|
||||
// {
|
||||
// paymentRequestQuery = paymentRequestQuery
|
||||
// .Where(pr => paymentRequestFilter.CreatedByIds.Contains(pr.CreatedById));
|
||||
// }
|
||||
// if (paymentRequestFilter.ExpenseCategoryIds?.Any() ?? false)
|
||||
// {
|
||||
// paymentRequestQuery = paymentRequestQuery
|
||||
// .Where(pr => paymentRequestFilter.ExpenseCategoryIds.Contains(pr.ExpenseCategoryId));
|
||||
// }
|
||||
//}
|
||||
|
||||
var totalEntites = await paymentRequestQuery.CountAsync();
|
||||
|
||||
var paymentRequests = await paymentRequestQuery
|
||||
.OrderByDescending(e => e.CreatedAt)
|
||||
.Skip((pageNumber - 1) * pageSize)
|
||||
.Take(pageSize).ToListAsync();
|
||||
|
||||
|
||||
var totalPages = (int)Math.Ceiling((double)totalEntites / pageSize);
|
||||
|
||||
var response = paymentRequests.Select(pr =>
|
||||
{
|
||||
var result = _mapper.Map<PaymentRequestVM>(pr);
|
||||
result.PaymentRequestUID = $"{pr.UIDPrefix}/{pr.UIDPostfix:D5}";
|
||||
return result;
|
||||
}).ToList();
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(response, $"{0} Payment request fetched successfully", 200);
|
||||
}
|
||||
|
||||
public async Task<ApiResponse<object>> CreatePaymentRequestAsync(PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId)
|
||||
{
|
||||
_logger.LogInfo("Start CreatePaymentRequestAsync for EmployeeId: {EmployeeId} TenantId: {TenantId}", loggedInEmployee.Id, tenantId);
|
||||
@ -1482,13 +1493,43 @@ namespace Marco.Pms.Services.Service
|
||||
_logger.LogInfo("End EditPaymentRequestAsync for PaymentRequestId: {PaymentRequestId}", id);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Payment Request Functions ===================================================================
|
||||
#region =================================================================== Advance Payment Functions ===================================================================
|
||||
public async Task<ApiResponse<object>> GetAdvancePaymentTransactionAsync(Guid employeeId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transactions = await _context.AdvancePaymentTransactions
|
||||
.Include(t => t.Employee)
|
||||
.Include(t => t.CreatedBy)
|
||||
.Where(t => t.EmployeeId == employeeId && t.IsActive)
|
||||
.OrderByDescending(t => t.CreatedAt)
|
||||
.ToListAsync();
|
||||
|
||||
if (transactions == null || !transactions.Any())
|
||||
return ApiResponse<object>.ErrorResponse("No advance payment transactions found.", null, 404);
|
||||
|
||||
var response = transactions.Select(transaction =>
|
||||
{
|
||||
var result = _mapper.Map<AdvancePaymentTransactionVM>(transaction);
|
||||
result.FinanceUId = $"{transaction.FinanceUIdPrefix}/{transaction.FinanceUIdPostfix:D5}";
|
||||
return result;
|
||||
}).ToList();
|
||||
|
||||
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(response, "Advance payment transaction fetched successfully", 200);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception occurred while fetching the list of Advance Payment Transactions.");
|
||||
return ApiResponse<object>.ErrorResponse("Internal exception occurred.", ExceptionMapper(ex), 500);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Payment Request Functions ===================================================================
|
||||
#region =================================================================== Recurring Payment Functions ===================================================================
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Helper Functions ===================================================================
|
||||
@ -1499,7 +1540,6 @@ namespace Marco.Pms.Services.Service
|
||||
var m = Regex.Match(id ?? string.Empty, @"(\d+)$");
|
||||
return m.Success ? int.Parse(m.Value) : int.MinValue; // put invalid IDs at the bottom
|
||||
}
|
||||
|
||||
private static object ExceptionMapper(Exception ex)
|
||||
{
|
||||
return new
|
||||
@ -1711,11 +1751,6 @@ namespace Marco.Pms.Services.Service
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the filter string, handling multiple potential formats (e.g., direct JSON vs. escaped JSON string).
|
||||
/// </summary>
|
||||
/// <param name="filter">The JSON filter string from the request.</param>
|
||||
/// <returns>An <see cref="ExpensesFilter"/> object or null if deserialization fails.</returns>
|
||||
private ExpensesFilter? TryDeserializeFilter(string? filter)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(filter))
|
||||
@ -1754,6 +1789,44 @@ namespace Marco.Pms.Services.Service
|
||||
}
|
||||
return expenseFilter;
|
||||
}
|
||||
private PaymentRequestFilter? TryDeserializePaymentRequestFilter(string? filter)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(filter))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||||
PaymentRequestFilter? expenseFilter = null;
|
||||
|
||||
try
|
||||
{
|
||||
// First, try to deserialize directly. This is the expected case (e.g., from a web client).
|
||||
expenseFilter = JsonSerializer.Deserialize<PaymentRequestFilter>(filter, options);
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
_logger.LogError(ex, "[{MethodName}] Failed to directly deserialize filter. Attempting to unescape and re-parse. Filter: {Filter}", nameof(TryDeserializeFilter), filter);
|
||||
|
||||
// If direct deserialization fails, it might be an escaped string (common with tools like Postman or some mobile clients).
|
||||
try
|
||||
{
|
||||
// Unescape the string first, then deserialize the result.
|
||||
string unescapedJsonString = JsonSerializer.Deserialize<string>(filter, options) ?? "";
|
||||
if (!string.IsNullOrWhiteSpace(unescapedJsonString))
|
||||
{
|
||||
expenseFilter = JsonSerializer.Deserialize<PaymentRequestFilter>(unescapedJsonString, options);
|
||||
}
|
||||
}
|
||||
catch (JsonException ex1)
|
||||
{
|
||||
// If both attempts fail, log the final error and return null.
|
||||
_logger.LogError(ex1, "[{MethodName}] All attempts to deserialize the filter failed. Filter will be ignored. Filter: {Filter}", nameof(TryDeserializeFilter), filter);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return expenseFilter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes and uploads attachments concurrently, then adds the resulting entities to the main DbContext.
|
||||
|
||||
@ -6,6 +6,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
||||
{
|
||||
public interface IExpensesService
|
||||
{
|
||||
#region =================================================================== Expenses Functions ===================================================================
|
||||
Task<ApiResponse<object>> GetExpensesListAsync(Employee loggedInEmployee, Guid tenantId, string? searchString, string? filter, int pageSize, int pageNumber);
|
||||
Task<ApiResponse<object>> GetExpenseDetailsAsync(Guid? id, string? financeUId, Employee loggedInEmployee, Guid tenantId);
|
||||
Task<ApiResponse<object>> GetSupplerNameListAsync(Employee loggedInEmployee, Guid tenantId);
|
||||
@ -14,11 +15,20 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
||||
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>> DeleteExpanseAsync(Guid id, Employee loggedInEmployee, Guid tenantId);
|
||||
#endregion
|
||||
|
||||
Task<ApiResponse<object>> GetAdvancePaymentTransactionAsync(Guid id);
|
||||
|
||||
|
||||
#region =================================================================== Payment Request Functions ===================================================================
|
||||
Task<ApiResponse<object>> GetPaymentRequestListAsync(string? searchString, string? filter, bool isActive, int pageSize, int pageNumber, Employee loggedInEmployee, Guid tenantId);
|
||||
Task<ApiResponse<object>> CreatePaymentRequestAsync(PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId);
|
||||
Task<ApiResponse<object>> EditPaymentRequestAsync(Guid id, PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId);
|
||||
#endregion
|
||||
|
||||
|
||||
#region =================================================================== Advance Payment Functions ===================================================================
|
||||
Task<ApiResponse<object>> GetAdvancePaymentTransactionAsync(Guid id);
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Recurring Payment Functions ===================================================================
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user