270 lines
12 KiB
C#

using AutoMapper;
using Marco.Pms.DataAccess.Data;
using Marco.Pms.Model.Dtos.Expenses;
using Marco.Pms.Model.Entitlements;
using Marco.Pms.Model.Expenses;
using Marco.Pms.Model.Utilities;
using Marco.Pms.Model.ViewModels.Expanses;
using Marco.Pms.Model.ViewModels.Master;
using Marco.Pms.Services.Service;
using MarcoBMS.Services.Helpers;
using MarcoBMS.Services.Service;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Document = Marco.Pms.Model.DocumentManager.Document;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace Marco.Pms.Services.Controllers
{
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class ExpenseController : ControllerBase
{
private readonly ApplicationDbContext _context;
private readonly UserHelper _userHelper;
private readonly PermissionServices _permission;
private readonly ILoggingService _logger;
private readonly S3UploadService _s3Service;
private readonly IMapper _mapper;
private readonly Guid tenantId;
public ExpenseController(
ApplicationDbContext context,
UserHelper userHelper,
PermissionServices permission,
ILoggingService logger,
S3UploadService s3Service,
IMapper mapper)
{
_context = context;
_userHelper = userHelper;
_permission = permission;
_logger = logger;
_s3Service = s3Service;
_mapper = mapper;
tenantId = userHelper.GetTenantId();
}
[HttpGet("list")]
public async Task<IActionResult> GetExpensesList()
{
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var loggedInEmployeeId = loggedInEmployee.Id;
List<Expenses>? expensesList = null;
var expensesListQuery = _context.Expenses
.Include(e => e.ExpensesType)
.Include(e => e.Project)
.Include(e => e.PaidBy)
.ThenInclude(e => e!.JobRole)
.Include(e => e.PaymentMode)
.Include(e => e.Status)
.Include(e => e.CreatedBy)
.Where(e => e.TenantId == tenantId);
var HasViewAllPermission = await _permission.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployeeId);
var HasViewSelfPermission = await _permission.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployeeId);
if (HasViewAllPermission)
{
expensesList = await expensesListQuery.ToListAsync();
}
else if (HasViewSelfPermission)
{
expensesList = await expensesListQuery.Where(e => e.CreatedById == loggedInEmployeeId).ToListAsync();
}
if (expensesList == null)
{
_logger.LogInfo("No Expense found for employee {EmployeeId}", loggedInEmployeeId);
return Ok(ApiResponse<object>.SuccessResponse(new List<ExpenseList>(), "No Expense found for current user", 200));
}
//ImageFilter? imageFilter = null;
//if (!string.IsNullOrWhiteSpace(filter))
//{
// try
// {
// var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
// //string unescapedJsonString = JsonSerializer.Deserialize<string>(filter, options) ?? "";
// //imageFilter = JsonSerializer.Deserialize<ImageFilter>(unescapedJsonString, options);
// imageFilter = JsonSerializer.Deserialize<ImageFilter>(filter, options);
// }
// catch (Exception ex)
// {
// _logger.LogWarning("[GetImageList] Failed to parse filter: {Message}", ex.Message);
// }
//}
var response = _mapper.Map<List<ExpenseList>>(expensesList);
var statusIds = expensesList.Select(e => e.StatusId).ToList();
var statusMappings = await _context.ExpensesStatusMapping
.Include(sm => sm.NextStatus)
.Where(sm => statusIds.Contains(sm.StatusId))
.ToListAsync();
foreach (var expense in response)
{
var statusMapping = statusMappings.Where(sm => sm.StatusId == expense.Status?.Id).Select(sm => _mapper.Map<ExpensesStatusMasterVM>(sm.NextStatus)).ToList();
expense.NextStatus = statusMapping;
}
return StatusCode(200, ApiResponse<object>.SuccessResponse(response, $"{response.Count} records of expenses for you fetched successfully", 200));
}
[HttpGet("details/{id}")]
public string Get(int id)
{
return "value";
}
[HttpPost("create")]
public async Task<IActionResult> Post([FromBody] CreateExpensesDto dto)
{
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var hasUploadPermission = await _permission.HasPermission(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id);
var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, dto.ProjectId);
if (!hasUploadPermission || !hasProjectPermission)
{
_logger.LogWarning("Access DENIED for employee {EmployeeId} for uploading expense on project {ProjectId}.", loggedInEmployee.Id, dto.ProjectId);
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403));
}
var isExpensesTypeExist = await _context.ExpensesTypeMaster.AnyAsync(et => et.Id == dto.ExpensesTypeId);
if (!isExpensesTypeExist)
{
_logger.LogWarning("Expenses type not for ID: {ExpensesTypeId} when creating new expense", dto.ExpensesTypeId);
return NotFound(ApiResponse<object>.ErrorResponse("Expanses Type not found", "Expanses Type not found", 404));
}
var isPaymentModeExist = await _context.PaymentModeMatser.AnyAsync(et => et.Id == dto.PaymentModeId);
if (!isPaymentModeExist)
{
_logger.LogWarning("Payment Mode not for ID: {PaymentModeId} when creating new expense", dto.PaymentModeId);
return NotFound(ApiResponse<object>.ErrorResponse("Payment Mode not found", "Payment Mode not found", 404));
}
var isStatusExist = await _context.ExpensesStatusMaster.AnyAsync(et => et.Id == dto.StatusId);
if (!isStatusExist)
{
_logger.LogWarning("Status not for ID: {PaymentModeId} when creating new expense", dto.PaymentModeId);
return NotFound(ApiResponse<object>.ErrorResponse("Status not found", "Status not found", 404));
}
var expense = new Expenses
{
ProjectId = dto.ProjectId,
ExpensesTypeId = dto.ExpensesTypeId,
PaymentModeId = dto.PaymentModeId,
PaidById = dto.PaidById,
CreatedById = loggedInEmployee.Id,
TransactionDate = dto.TransactionDate,
CreatedAt = DateTime.UtcNow,
TransactionId = dto.TransactionId,
Description = dto.Description,
Location = dto.Location,
GSTNumber = dto.GSTNumber,
SupplerName = dto.SupplerName,
Amount = dto.Amount,
NoOfPersons = dto.NoOfPersons,
StatusId = dto.StatusId,
PreApproved = dto.PreApproved,
IsActive = true,
TenantId = tenantId
};
_context.Expenses.Add(expense);
Guid batchId = Guid.NewGuid();
foreach (var attachment in dto.BillAttachments)
{
//if (!_s3Service.IsBase64String(attachment.Base64Data))
//{
// _logger.LogWarning("Image upload failed: Base64 data is missing While creating new expense entity for project {ProjectId} by employee {EmployeeId}", expense.ProjectId, expense.PaidById);
// return BadRequest(ApiResponse<object>.ErrorResponse("Base64 data is missing", "Base64 data is missing", 400));
//}
var base64 = attachment.Base64Data!.Contains(',')
? attachment.Base64Data[(attachment.Base64Data.IndexOf(",") + 1)..]
: attachment.Base64Data;
var fileType = _s3Service.GetContentTypeFromBase64(base64);
var fileName = _s3Service.GenerateFileName(fileType, expense.Id, "Expense");
var objectKey = $"tenant-{tenantId}/project-{expense.ProjectId}/Expenses/{fileName}";
try
{
await _s3Service.UploadFileAsync(base64, fileType, objectKey);
_logger.LogInfo("Image uploaded to S3 with key: {ObjectKey}", objectKey);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occured while saving image to S3");
//return BadRequest(ApiResponse<object>.ErrorResponse("Cannot upload attachment to S3", new
//{
// message = ex.Message,
// innerexcption = ex.InnerException?.Message,
// stackTrace = ex.StackTrace,
// source = ex.Source
//}, 400));
}
var document = new Document
{
BatchId = batchId,
UploadedById = loggedInEmployee.Id,
FileName = attachment.FileName ?? "",
ContentType = attachment.ContentType ?? "",
S3Key = objectKey,
//Base64Data = attachment.Base64Data,
FileSize = attachment.FileSize,
UploadedAt = DateTime.UtcNow,
TenantId = tenantId
};
_context.Documents.Add(document);
var billAttachement = new BillAttachments
{
DocumentId = document.Id,
ExpensesId = expense.Id,
TenantId = tenantId
};
_context.BillAttachments.Add(billAttachement);
}
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException dbEx)
{
_logger.LogError(dbEx, "Error occured while saving Expense, Document and bill attachment entity");
return BadRequest(ApiResponse<object>.ErrorResponse("Databsae Exception", new
{
Message = dbEx.Message,
StackTrace = dbEx.StackTrace,
Source = dbEx.Source,
innerexcption = new
{
Message = dbEx.InnerException?.Message,
StackTrace = dbEx.InnerException?.StackTrace,
Source = dbEx.InnerException?.Source,
}
}, 400));
}
_logger.LogInfo("Documents and attachments saved for Expense: {ExpenseId}", expense.Id);
return StatusCode(201, ApiResponse<object>.SuccessResponse(expense, "Expense created Successfully", 201));
}
[HttpPut("edit/{id}")]
public void Put(int id, [FromBody] string value)
{
}
[HttpDelete("delete/{id}")]
public void Delete(int id)
{
}
}
}