diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 78cb989..475cd5d 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -71,16 +71,48 @@ namespace Marco.Pms.Services.Controllers #endregion #region =================================================================== Purchase Invoice Status APIs =================================================================== + + /// + /// Retrieves the purchase invoice status. + /// + /// The cancellation token. + /// The HTTP response containing the purchase invoice status. [HttpGet("purchase-invoice-status/list")] public async Task GetPurchaseInvoiceStatus(CancellationToken ct) { + // Get the currently logged-in employee. var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + + // Retrieve the purchase invoice status asynchronously. var response = await _masterService.GetPurchaseInvoiceStatusAsync(loggedInEmployee, ct); + + // Return the HTTP response with the purchase invoice status. return StatusCode(response.StatusCode, response); } #endregion + #region =================================================================== Invoice Attachment Type APIs =================================================================== + + /// + /// Retrieves the invoice attachment types. + /// + /// The cancellation token. + /// The HTTP response containing the invoice attachment types. + [HttpGet("purchase-attachment-type/list")] + public async Task GetInvoiceAttachmentType(CancellationToken ct) + { + // Get the currently logged-in employee. + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + + // Retrieve the invoice attachment types asynchronously. + var response = await _masterService.GetInvoiceAttachmentTypeAsync(loggedInEmployee, ct); + + // Return the HTTP response with the invoice attachment types. + return StatusCode(response.StatusCode, response); + } + #endregion + #region =================================================================== Currency APIs =================================================================== [HttpGet("currencies/list")] diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index 7398aab..e55adf8 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -244,6 +244,61 @@ namespace Marco.Pms.Services.Service #endregion + #region =================================================================== Invoice Attachment Type APIs =================================================================== + + /// + /// Asynchronously retrieves the list of valid Invoice Attachment Types. + /// + /// The current user context for audit logging. + /// Token to propagate notification that operations should be canceled. + /// A standardized API response containing a list of attachment type DTOs. + public async Task> GetInvoiceAttachmentTypeAsync(Employee loggedInEmployee, CancellationToken cancellationToken = default) + { + // 1. Structured Logging: Audit WHO is requesting the data + _logger.LogInfo("Initiating fetch of Invoice Attachment Types. Requested by User ID: {UserId}", loggedInEmployee.Id); + + try + { + // 2. Database Optimization: + // - AsNoTracking(): Crucial for read-only lists. Bypasses change tracking overhead. + // - Select(): Projects directly to DTO. Fetches ONLY needed columns (SQL optimization). + var attachmentTypes = await _context.InvoiceAttachmentTypes + .AsNoTracking() + .OrderBy(type => type.Name) + .ToListAsync(cancellationToken); // 3. Pass the token to EF Core + + _logger.LogInfo("Successfully retrieved {Count} Invoice Attachment Types.", attachmentTypes.Count); + + // 4. Strong Typing: Return IEnumerable instead of 'object' + return ApiResponse.SuccessResponse( + attachmentTypes, + $"{attachmentTypes.Count} record(s) of invoice attachment type fetched successfully", + 200 + ); + } + catch (OperationCanceledException) + { + // Handle request cancellation (e.g., user navigated away) + _logger.LogWarning("Invoice Attachment Type fetch operation was canceled by the client."); + return ApiResponse.ErrorResponse("Operation canceled", "Request canceled by user", 499); + } + catch (Exception ex) + { + // 5. Security & Error Handling: + // Log the real error with stack trace internally. + _logger.LogError(ex, "Critical error fetching Invoice Attachment Types for User ID: {UserId}", loggedInEmployee.Id); + + // Return a sanitized message to the client. Never expose raw SQL errors or Stack Traces. + return ApiResponse.ErrorResponse( + "An unexpected error occurred while processing your request.", + "Internal Server Error", + 500 + ); + } + } + + #endregion + #region =================================================================== Currency APIs =================================================================== public async Task> GetCurrencyAsync(Employee loggedInEmployee, Guid tenantId) diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index 93b71ec..889c8fb 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -25,6 +25,10 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces #region =================================================================== Purchase Invoice Status APIs =================================================================== Task> GetPurchaseInvoiceStatusAsync(Employee loggedInEmployee, CancellationToken cancellationToken); + #endregion + #region =================================================================== Invoice Attachment Type APIs =================================================================== + Task> GetInvoiceAttachmentTypeAsync(Employee loggedInEmployee, CancellationToken cancellationToken); + #endregion #region =================================================================== Currency APIs =================================================================== Task> GetCurrencyAsync(Employee loggedInEmployee, Guid tenantId);