235 lines
7.6 KiB
C#
235 lines
7.6 KiB
C#
|
|
using Microsoft.AspNetCore.Mvc;
|
||
|
|
using Microsoft.EntityFrameworkCore;
|
||
|
|
using LingAdmin.API.Data;
|
||
|
|
using LingAdmin.API.Models;
|
||
|
|
using LingAdmin.API.DTOs;
|
||
|
|
using Dapr.Client;
|
||
|
|
|
||
|
|
namespace LingAdmin.API.Controllers;
|
||
|
|
|
||
|
|
[ApiController]
|
||
|
|
[Route("api/[controller]")]
|
||
|
|
public class RequisitionsController : ControllerBase
|
||
|
|
{
|
||
|
|
private readonly AppDbContext _context;
|
||
|
|
private readonly DaprClient _daprClient;
|
||
|
|
private readonly ILogger<RequisitionsController> _logger;
|
||
|
|
|
||
|
|
public RequisitionsController(AppDbContext context, DaprClient daprClient, ILogger<RequisitionsController> logger)
|
||
|
|
{
|
||
|
|
_context = context;
|
||
|
|
_daprClient = daprClient;
|
||
|
|
_logger = logger;
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpGet]
|
||
|
|
public async Task<ActionResult<ApiResponse<List<object>>>> GetRequisitions()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var requisitions = await _context.Requisitions
|
||
|
|
.Select(r => new
|
||
|
|
{
|
||
|
|
id = r.Id,
|
||
|
|
reqNo = r.ReqNo,
|
||
|
|
requester = r.Requester,
|
||
|
|
department = r.Department,
|
||
|
|
date = r.Date.ToString("yyyy-MM-dd"),
|
||
|
|
status = r.Status,
|
||
|
|
totalAmount = r.TotalAmount
|
||
|
|
})
|
||
|
|
.ToListAsync();
|
||
|
|
|
||
|
|
return Ok(ApiResponse<List<object>>.Success(requisitions.Cast<object>().ToList()));
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
_logger.LogError(ex, "Error retrieving requisitions");
|
||
|
|
return StatusCode(500, ApiResponse<List<object>>.Error("Internal server error", 500));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpGet("{id}")]
|
||
|
|
public async Task<ActionResult<ApiResponse<object>>> GetRequisition(int id)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var requisition = await _context.Requisitions
|
||
|
|
.Include(r => r.Items)
|
||
|
|
.FirstOrDefaultAsync(r => r.Id == id);
|
||
|
|
|
||
|
|
if (requisition == null)
|
||
|
|
{
|
||
|
|
return NotFound(ApiResponse<object>.Error("Requisition not found", 404));
|
||
|
|
}
|
||
|
|
|
||
|
|
var result = new
|
||
|
|
{
|
||
|
|
id = requisition.Id,
|
||
|
|
reqNo = requisition.ReqNo,
|
||
|
|
requester = requisition.Requester,
|
||
|
|
department = requisition.Department,
|
||
|
|
date = requisition.Date.ToString("yyyy-MM-dd"),
|
||
|
|
status = requisition.Status,
|
||
|
|
description = requisition.Description,
|
||
|
|
items = requisition.Items.Select(i => new
|
||
|
|
{
|
||
|
|
id = i.Id,
|
||
|
|
itemName = i.ItemName,
|
||
|
|
quantity = i.Quantity,
|
||
|
|
price = i.Price
|
||
|
|
}).ToList()
|
||
|
|
};
|
||
|
|
|
||
|
|
return Ok(ApiResponse<object>.Success(result));
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
_logger.LogError(ex, "Error retrieving requisition {Id}", id);
|
||
|
|
return StatusCode(500, ApiResponse<object>.Error("Internal server error", 500));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpPost]
|
||
|
|
public async Task<ActionResult<ApiResponse<object>>> CreateRequisition(CreateRequisitionDto dto)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
// Generate next requisition number
|
||
|
|
var lastReqNo = await _context.Requisitions
|
||
|
|
.OrderByDescending(r => r.Id)
|
||
|
|
.Select(r => r.ReqNo)
|
||
|
|
.FirstOrDefaultAsync();
|
||
|
|
|
||
|
|
int nextNumber = 1;
|
||
|
|
if (!string.IsNullOrEmpty(lastReqNo))
|
||
|
|
{
|
||
|
|
var numberPart = lastReqNo.Split('-').LastOrDefault();
|
||
|
|
if (int.TryParse(numberPart, out int current))
|
||
|
|
{
|
||
|
|
nextNumber = current + 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
var reqNo = $"PR-{DateTime.Now.Year}{nextNumber:D3}";
|
||
|
|
|
||
|
|
var requisition = new Requisition
|
||
|
|
{
|
||
|
|
ReqNo = reqNo,
|
||
|
|
Requester = dto.Requester,
|
||
|
|
Department = dto.Department,
|
||
|
|
Date = dto.Date,
|
||
|
|
Status = dto.Status,
|
||
|
|
Description = dto.Description,
|
||
|
|
TotalAmount = dto.Items.Sum(i => i.Quantity * i.Price)
|
||
|
|
};
|
||
|
|
|
||
|
|
foreach (var itemDto in dto.Items)
|
||
|
|
{
|
||
|
|
requisition.Items.Add(new RequisitionItem
|
||
|
|
{
|
||
|
|
ItemName = itemDto.ItemName,
|
||
|
|
Quantity = itemDto.Quantity,
|
||
|
|
Price = itemDto.Price
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
_context.Requisitions.Add(requisition);
|
||
|
|
await _context.SaveChangesAsync();
|
||
|
|
|
||
|
|
// Publish event via Dapr
|
||
|
|
try
|
||
|
|
{
|
||
|
|
await _daprClient.PublishEventAsync("pubsub", "requisition-created", new
|
||
|
|
{
|
||
|
|
id = requisition.Id,
|
||
|
|
reqNo = requisition.ReqNo,
|
||
|
|
requester = requisition.Requester,
|
||
|
|
totalAmount = requisition.TotalAmount
|
||
|
|
});
|
||
|
|
}
|
||
|
|
catch (Exception pubEx)
|
||
|
|
{
|
||
|
|
_logger.LogWarning(pubEx, "Failed to publish requisition-created event");
|
||
|
|
}
|
||
|
|
|
||
|
|
return Ok(ApiResponse<object>.Success(new { id = requisition.Id }));
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
_logger.LogError(ex, "Error creating requisition");
|
||
|
|
return StatusCode(500, ApiResponse<object>.Error("Internal server error", 500));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpPut("{id}")]
|
||
|
|
public async Task<ActionResult<ApiResponse<object>>> UpdateRequisition(int id, CreateRequisitionDto dto)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var requisition = await _context.Requisitions
|
||
|
|
.Include(r => r.Items)
|
||
|
|
.FirstOrDefaultAsync(r => r.Id == id);
|
||
|
|
|
||
|
|
if (requisition == null)
|
||
|
|
{
|
||
|
|
return NotFound(ApiResponse<object>.Error("Requisition not found", 404));
|
||
|
|
}
|
||
|
|
|
||
|
|
requisition.Requester = dto.Requester;
|
||
|
|
requisition.Department = dto.Department;
|
||
|
|
requisition.Date = dto.Date;
|
||
|
|
requisition.Status = dto.Status;
|
||
|
|
requisition.Description = dto.Description;
|
||
|
|
|
||
|
|
// Remove old items and add new ones
|
||
|
|
_context.RequisitionItems.RemoveRange(requisition.Items);
|
||
|
|
requisition.Items.Clear();
|
||
|
|
|
||
|
|
foreach (var itemDto in dto.Items)
|
||
|
|
{
|
||
|
|
requisition.Items.Add(new RequisitionItem
|
||
|
|
{
|
||
|
|
ItemName = itemDto.ItemName,
|
||
|
|
Quantity = itemDto.Quantity,
|
||
|
|
Price = itemDto.Price
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
requisition.TotalAmount = dto.Items.Sum(i => i.Quantity * i.Price);
|
||
|
|
|
||
|
|
await _context.SaveChangesAsync();
|
||
|
|
|
||
|
|
return Ok(ApiResponse<object>.Success(new { id = requisition.Id }));
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
_logger.LogError(ex, "Error updating requisition {Id}", id);
|
||
|
|
return StatusCode(500, ApiResponse<object>.Error("Internal server error", 500));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpDelete("{id}")]
|
||
|
|
public async Task<ActionResult<ApiResponse<object>>> DeleteRequisition(int id)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var requisition = await _context.Requisitions.FindAsync(id);
|
||
|
|
if (requisition == null)
|
||
|
|
{
|
||
|
|
return NotFound(ApiResponse<object>.Error("Requisition not found", 404));
|
||
|
|
}
|
||
|
|
|
||
|
|
_context.Requisitions.Remove(requisition);
|
||
|
|
await _context.SaveChangesAsync();
|
||
|
|
|
||
|
|
return Ok(ApiResponse<object>.Success(new { }));
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
_logger.LogError(ex, "Error deleting requisition {Id}", id);
|
||
|
|
return StatusCode(500, ApiResponse<object>.Error("Internal server error", 500));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|