CUB-37: implement cost-per-print calculation service
This commit is contained in:
@@ -2,6 +2,7 @@ using Extrudex.API.DTOs;
|
||||
using Extrudex.API.DTOs.PrintJobs;
|
||||
using Extrudex.Domain.Entities;
|
||||
using Extrudex.Domain.Enums;
|
||||
using Extrudex.Domain.Interfaces;
|
||||
using Extrudex.Infrastructure.Data;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@@ -19,16 +20,22 @@ namespace Extrudex.API.Controllers;
|
||||
public class PrintJobsController : ControllerBase
|
||||
{
|
||||
private readonly ExtrudexDbContext _dbContext;
|
||||
private readonly ICostPerPrintService _costService;
|
||||
private readonly ILogger<PrintJobsController> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PrintJobsController"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dbContext">The database context for data access.</param>
|
||||
/// <param name="costService">The cost-per-print calculation service.</param>
|
||||
/// <param name="logger">The logger for diagnostic output.</param>
|
||||
public PrintJobsController(ExtrudexDbContext dbContext, ILogger<PrintJobsController> logger)
|
||||
public PrintJobsController(
|
||||
ExtrudexDbContext dbContext,
|
||||
ICostPerPrintService costService,
|
||||
ILogger<PrintJobsController> logger)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
_costService = costService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -413,6 +420,34 @@ public class PrintJobsController : ControllerBase
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
// ── POST /api/printjobs/{id}/cost ─────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the cost of goods sold (COGS) for a specific print job.
|
||||
/// Uses the spool’s purchase price and the print job’s derived grams consumed
|
||||
/// to produce a cost breakdown. Returns warnings instead of errors when
|
||||
/// cost data is missing or incomplete.
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier of the print job.</param>
|
||||
/// <returns>A cost breakdown with warnings if data is incomplete.</returns>
|
||||
/// <response code="200">Returns the cost breakdown for the print job.</response>
|
||||
/// <response code="404">If the print job with the given ID is not found.</response>
|
||||
[HttpPost("{id:guid}/cost")]
|
||||
[ProducesResponseType(typeof(CostPerPrintResponse), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<CostPerPrintResponse>> CalculateCost(Guid id)
|
||||
{
|
||||
_logger.LogDebug("Calculating cost for print job {Id}", id);
|
||||
|
||||
var result = await _costService.CalculateAsync(id);
|
||||
|
||||
// If the job was not found, return 404
|
||||
if (result.Warnings.Any(w => w.Contains("not found")))
|
||||
return NotFound(new { error = $"Print job with ID '{id}' not found." });
|
||||
|
||||
return Ok(MapCostToResponse(result));
|
||||
}
|
||||
|
||||
// ── Gram Derivation Formula ────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
@@ -509,4 +544,22 @@ public class PrintJobsController : ControllerBase
|
||||
CreatedAt = j.CreatedAt,
|
||||
UpdatedAt = j.UpdatedAt
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Maps a domain CostPerPrintResult to an API CostPerPrintResponse DTO.
|
||||
/// </summary>
|
||||
private static CostPerPrintResponse MapCostToResponse(CostPerPrintResult r) => new()
|
||||
{
|
||||
PrintJobId = r.PrintJobId,
|
||||
PrintName = r.PrintName,
|
||||
SpoolId = r.SpoolId,
|
||||
SpoolSerial = r.SpoolSerial,
|
||||
MmExtruded = r.MmExtruded,
|
||||
GramsDerived = r.GramsDerived,
|
||||
PurchasePrice = r.PurchasePrice,
|
||||
WeightTotalGrams = r.WeightTotalGrams,
|
||||
CostPerGram = r.CostPerGram,
|
||||
CostPerPrint = r.CostPerPrint,
|
||||
Warnings = r.Warnings
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user