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 _logger; public RequisitionsController(AppDbContext context, DaprClient daprClient, ILogger logger) { _context = context; _daprClient = daprClient; _logger = logger; } [HttpGet] public async Task>>> 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>.Success(requisitions.Cast().ToList())); } catch (Exception ex) { _logger.LogError(ex, "Error retrieving requisitions"); return StatusCode(500, ApiResponse>.Error("Internal server error", 500)); } } [HttpGet("{id}")] public async Task>> GetRequisition(int id) { try { var requisition = await _context.Requisitions .Include(r => r.Items) .FirstOrDefaultAsync(r => r.Id == id); if (requisition == null) { return NotFound(ApiResponse.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.Success(result)); } catch (Exception ex) { _logger.LogError(ex, "Error retrieving requisition {Id}", id); return StatusCode(500, ApiResponse.Error("Internal server error", 500)); } } [HttpPost] public async Task>> 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.Success(new { id = requisition.Id })); } catch (Exception ex) { _logger.LogError(ex, "Error creating requisition"); return StatusCode(500, ApiResponse.Error("Internal server error", 500)); } } [HttpPut("{id}")] public async Task>> 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.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.Success(new { id = requisition.Id })); } catch (Exception ex) { _logger.LogError(ex, "Error updating requisition {Id}", id); return StatusCode(500, ApiResponse.Error("Internal server error", 500)); } } [HttpDelete("{id}")] public async Task>> DeleteRequisition(int id) { try { var requisition = await _context.Requisitions.FindAsync(id); if (requisition == null) { return NotFound(ApiResponse.Error("Requisition not found", 404)); } _context.Requisitions.Remove(requisition); await _context.SaveChangesAsync(); return Ok(ApiResponse.Success(new { })); } catch (Exception ex) { _logger.LogError(ex, "Error deleting requisition {Id}", id); return StatusCode(500, ApiResponse.Error("Internal server error", 500)); } } }