Added the create payment received invoice API
This commit is contained in:
parent
5ff87cd870
commit
2b19890b53
11
Marco.Pms.Model/Dtos/Collection/ReceivedInvoicePaymentDto.cs
Normal file
11
Marco.Pms.Model/Dtos/Collection/ReceivedInvoicePaymentDto.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace Marco.Pms.Model.Dtos.Collection
|
||||
{
|
||||
public class ReceivedInvoicePaymentDto
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public required Guid InvoiceId { get; set; }
|
||||
public required DateTime PaymentReceivedDate { get; set; }
|
||||
public required string TransactionId { get; set; } = default!;
|
||||
public required double Amount { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
using Marco.Pms.Model.ViewModels.Activities;
|
||||
|
||||
namespace Marco.Pms.Model.ViewModels.Collection
|
||||
{
|
||||
public class ReceivedInvoicePaymentVM
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid InvoiceId { get; set; }
|
||||
public DateTime PaymentReceivedDate { get; set; }
|
||||
public string TransactionId { get; set; } = default!;
|
||||
public double Amount { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ using MarcoBMS.Services.Service;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Marco.Pms.Services.Controllers
|
||||
{
|
||||
@ -52,10 +53,10 @@ namespace Marco.Pms.Services.Controllers
|
||||
"Fetching invoice list: Page {PageNumber}, Size {PageSize}, Active={IsActive}, PendingOnly={IsPending}, Search='{SearchString}', From={From}, To={To}",
|
||||
pageNumber, pageSize, isActive, isPending, searchString ?? "", fromDate?.Date ?? DateTime.MinValue, toDate?.Date ?? DateTime.MaxValue);
|
||||
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
// Build base query with required includes and no tracking
|
||||
var invoicesQuery = context.Invoices
|
||||
var invoicesQuery = _context.Invoices
|
||||
.Include(i => i.Project)
|
||||
.Include(i => i.CreatedBy).ThenInclude(e => e!.JobRole)
|
||||
.Include(i => i.UpdatedBy).ThenInclude(e => e!.JobRole)
|
||||
@ -104,7 +105,7 @@ namespace Marco.Pms.Services.Controllers
|
||||
|
||||
// Fetch all related payment data in a single query
|
||||
var invoiceIds = invoices.Select(i => i.Id).ToList();
|
||||
var paymentGroups = await context.ReceivedInvoicePayments
|
||||
var paymentGroups = await _context.ReceivedInvoicePayments
|
||||
.AsNoTracking()
|
||||
.Where(rip => invoiceIds.Contains(rip.InvoiceId) && rip.TenantId == tenantId)
|
||||
.GroupBy(rip => rip.InvoiceId)
|
||||
@ -149,7 +150,7 @@ namespace Marco.Pms.Services.Controllers
|
||||
|
||||
|
||||
[HttpPost("invoice/create")]
|
||||
public async Task<IActionResult> CreateInvoiceAsync(InvoiceDto model)
|
||||
public async Task<IActionResult> CreateInvoiceAsync([FromBody] InvoiceDto model)
|
||||
{
|
||||
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
||||
//using var scope = _serviceScopeFactory.CreateScope();
|
||||
@ -309,6 +310,93 @@ namespace Marco.Pms.Services.Controllers
|
||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Invoice Created Successfully", 201));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new received invoice payment record after validating business rules.
|
||||
/// </summary>
|
||||
/// <param name="model">The received invoice payment data transfer object containing payment details.</param>
|
||||
/// <returns>An action result containing the created payment view model or error response.</returns>
|
||||
|
||||
[HttpPost("invoice/payment/received")]
|
||||
public async Task<IActionResult> CreateReceivedInvoicePaymentAsync([FromBody] ReceivedInvoicePaymentDto model)
|
||||
{
|
||||
// Validate input model
|
||||
if (model == null)
|
||||
{
|
||||
_logger.LogWarning("Received invoice payment creation request with null model");
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid model", "Request payload cannot be null", 400));
|
||||
}
|
||||
|
||||
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
|
||||
// Retrieve invoice with tenant isolation and no tracking for read-only access
|
||||
var invoice = await _context.Invoices
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(i => i.Id == model.InvoiceId && i.TenantId == tenantId);
|
||||
|
||||
if (invoice == null)
|
||||
{
|
||||
_logger.LogWarning("Invoice not found for ID {InvoiceId} and TenantId {TenantId}", model.InvoiceId, tenantId);
|
||||
return NotFound(ApiResponse<object>.ErrorResponse("Invoice not found", "The specified invoice does not exist", 404));
|
||||
}
|
||||
|
||||
// Check if invoice is already marked as completed
|
||||
if (invoice.MarkAsCompleted)
|
||||
{
|
||||
_logger.LogWarning("Attempt to add payment to completed invoice {InvoiceId}", model.InvoiceId);
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse(
|
||||
"Cannot add received payment to completed invoice",
|
||||
"Payments cannot be added to invoices that are already marked as completed", 400));
|
||||
}
|
||||
|
||||
// Validate payment received date is not in the future
|
||||
if (model.PaymentReceivedDate.Date > DateTime.UtcNow.Date)
|
||||
{
|
||||
_logger.LogWarning("Future payment date {PaymentReceivedDate} provided for invoice {InvoiceId}",
|
||||
model.PaymentReceivedDate, model.InvoiceId);
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse(
|
||||
"Payment received date cannot be in the future",
|
||||
"The payment received date must not be later than the current date", 400));
|
||||
}
|
||||
|
||||
// Validate client submitted date is not later than payment received date
|
||||
if (invoice.ClientSubmitedDate.Date > model.PaymentReceivedDate.Date)
|
||||
{
|
||||
_logger.LogWarning("Client submitted date {ClientSubmitedDate} is later than payment received date {PaymentReceivedDate} for invoice {InvoiceId}",
|
||||
invoice.ClientSubmitedDate, model.PaymentReceivedDate, model.InvoiceId);
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse(
|
||||
"Client submitted date is later than payment received date",
|
||||
"The client submission date cannot be later than the payment received date", 400));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Map DTO to entity and set creation metadata
|
||||
var receivedInvoicePayment = _mapper.Map<ReceivedInvoicePayment>(model);
|
||||
receivedInvoicePayment.CreatedAt = DateTime.UtcNow;
|
||||
receivedInvoicePayment.CreatedById = loggedInEmployee.Id;
|
||||
receivedInvoicePayment.TenantId = tenantId;
|
||||
|
||||
// Add new payment record and save changes
|
||||
_context.ReceivedInvoicePayments.Add(receivedInvoicePayment);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Map entity to view model for response
|
||||
var response = _mapper.Map<ReceivedInvoicePaymentVM>(receivedInvoicePayment);
|
||||
|
||||
_logger.LogInfo("Successfully created received payment {PaymentId} for invoice {InvoiceId}",
|
||||
receivedInvoicePayment.Id, model.InvoiceId);
|
||||
|
||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Payment invoice received successfully", 201));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error occurred while creating received payment for invoice {InvoiceId}", model.InvoiceId);
|
||||
return StatusCode(500, ApiResponse<object>.ErrorResponse(
|
||||
"Internal server error",
|
||||
"An unexpected error occurred while processing the request", 500));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -261,6 +261,9 @@ namespace Marco.Pms.Services.MappingProfiles
|
||||
#region ======================================================= Collection =======================================================
|
||||
CreateMap<InvoiceDto, Invoice>();
|
||||
CreateMap<Invoice, InvoiceListVM>();
|
||||
|
||||
CreateMap<ReceivedInvoicePaymentDto, ReceivedInvoicePayment>();
|
||||
CreateMap<ReceivedInvoicePayment, ReceivedInvoicePaymentVM>();
|
||||
#endregion
|
||||
|
||||
#region ======================================================= Master =======================================================
|
||||
|
Loading…
x
Reference in New Issue
Block a user