Fix material usage logging: remaining weight mode, edit modal, and consolidate duplicate logic
- InventoryController: extract RecordInventoryUsageAsync helper; both LogUsage (scan page) and LogMaterial (jobs modal, moved from JobsController) call it — no more duplicate save/GL logic across two controllers - Log Material modal: replace radio buttons with prominent toggle buttons so the active mode (Amount Used vs Amount Remaining) is always visually obvious; add always-visible preview line showing exactly what will be logged before saving - Edit Usage modal: add quantity field (pre-populated from existing transaction) with delta adjustment to InventoryItem.QuantityOnHand on save; include completed/terminal jobs in the dropdown so entries can be corrected after a job is marked done - Scan page job picker: include jobs completed within the last 7 days (marked with '(completed)') so usage can be logged after a job is finished Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4399,75 +4399,7 @@ public class JobsController : Controller
|
||||
_logger.LogInformation("Recorded first job creation for company {CompanyId}", companyId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs manual material usage from the job details page. Mirrors the QR scan LogUsage
|
||||
/// flow in InventoryController but returns JSON so the modal can close and refresh inline.
|
||||
/// Quantity is always the amount USED (caller converts from remaining if needed).
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> LogMaterial([FromBody] LogMaterialRequest req)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (req.QuantityUsed <= 0)
|
||||
return Json(new { success = false, message = "Quantity used must be greater than zero." });
|
||||
|
||||
var item = await _unitOfWork.InventoryItems.GetByIdAsync(req.InventoryItemId);
|
||||
if (item == null) return Json(new { success = false, message = "Inventory item not found." });
|
||||
|
||||
var job = await _unitOfWork.Jobs.GetByIdAsync(req.JobId);
|
||||
if (job == null) return Json(new { success = false, message = "Job not found." });
|
||||
|
||||
var txnType = req.TransactionType == "Waste"
|
||||
? InventoryTransactionType.Waste
|
||||
: InventoryTransactionType.JobUsage;
|
||||
|
||||
item.QuantityOnHand -= req.QuantityUsed;
|
||||
item.UpdatedAt = DateTime.UtcNow;
|
||||
await _unitOfWork.InventoryItems.UpdateAsync(item);
|
||||
|
||||
var txn = new PowderCoating.Core.Entities.InventoryTransaction
|
||||
{
|
||||
InventoryItemId = item.Id,
|
||||
TransactionType = txnType,
|
||||
Quantity = -req.QuantityUsed,
|
||||
UnitCost = item.UnitCost,
|
||||
TotalCost = req.QuantityUsed * item.UnitCost,
|
||||
TransactionDate = DateTime.UtcNow,
|
||||
BalanceAfter = item.QuantityOnHand,
|
||||
JobId = req.JobId,
|
||||
Reference = $"Job {job.JobNumber}",
|
||||
Notes = req.Notes?.Trim(),
|
||||
CompanyId = item.CompanyId,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
await _unitOfWork.InventoryTransactions.AddAsync(txn);
|
||||
await _unitOfWork.CompleteAsync();
|
||||
|
||||
// GL: DR COGS, CR Inventory Asset
|
||||
if (item.CogsAccountId.HasValue && item.InventoryAccountId.HasValue)
|
||||
{
|
||||
var cost = req.QuantityUsed * (item.AverageCost > 0 ? item.AverageCost : item.UnitCost);
|
||||
await _accountBalanceService.DebitAsync(item.CogsAccountId, cost);
|
||||
await _accountBalanceService.CreditAsync(item.InventoryAccountId, cost);
|
||||
}
|
||||
|
||||
return Json(new
|
||||
{
|
||||
success = true,
|
||||
message = $"Logged {req.QuantityUsed:N2} {item.UnitOfMeasure} of {item.Name}.",
|
||||
newBalance = item.QuantityOnHand,
|
||||
unitOfMeasure = item.UnitOfMeasure,
|
||||
itemName = item.Name
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error logging material for job {JobId}", req.JobId);
|
||||
return Json(new { success = false, message = "An error occurred. Please try again." });
|
||||
}
|
||||
}
|
||||
// LogMaterial has been consolidated into InventoryController.LogMaterial.
|
||||
|
||||
/// <summary>
|
||||
/// Inline-edits description, quantity, and unit price on a single job line item.
|
||||
@@ -4554,14 +4486,6 @@ public class PatchJobItemRequest
|
||||
public decimal Quantity { get; set; }
|
||||
public decimal UnitPrice { get; set; }
|
||||
}
|
||||
public class LogMaterialRequest
|
||||
{
|
||||
public int JobId { get; set; }
|
||||
public int InventoryItemId { get; set; }
|
||||
public decimal QuantityUsed { get; set; }
|
||||
public string TransactionType { get; set; } = "JobUsage";
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
public class CreateReworkJobRequest
|
||||
{
|
||||
public int ReworkRecordId { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user