diff --git a/src/PowderCoating.Web/Controllers/InvoicesController.cs b/src/PowderCoating.Web/Controllers/InvoicesController.cs index d6ad3ab..39ed6af 100644 --- a/src/PowderCoating.Web/Controllers/InvoicesController.cs +++ b/src/PowderCoating.Web/Controllers/InvoicesController.cs @@ -1499,6 +1499,29 @@ public class InvoicesController : Controller await _unitOfWork.Payments.SoftDeleteAsync(payment.Id); } + // Re-release any deposits that were applied to this invoice so they can be + // auto-applied to the replacement invoice. Without this, AppliedToInvoiceId + // stays set and the deposit lookup (AppliedToInvoiceId == null) skips them. + var appliedDeposits = await _unitOfWork.Deposits.FindAsync( + d => d.AppliedToInvoiceId == invoice.Id && !d.IsDeleted); + var totalDepositReleased = 0m; + foreach (var deposit in appliedDeposits) + { + deposit.AppliedToInvoiceId = null; + deposit.AppliedDate = null; + deposit.UpdatedAt = DateTime.UtcNow; + await _unitOfWork.Deposits.UpdateAsync(deposit); + totalDepositReleased += deposit.Amount; + } + // Restore the CustomerDeposits 2300 liability that was cleared when the deposits + // were applied. Mirrors the DR at apply time; follows the same simplified reversal + // pattern as the rest of the void (regular payment GL entries are also left as-is). + if (totalDepositReleased > 0) + { + var custDepositsAcctId = await GetCustomerDepositsAccountIdAsync(invoice.CompanyId); + await _accountBalanceService.CreditAsync(custDepositsAcctId, totalDepositReleased); + } + // Void any gift certificates that were generated from this invoice. // Capture each GC's remaining balance BEFORE voiding so the GL entries below can use it. var gcLiabilityAcctId = await GetGcLiabilityAccountIdAsync(invoice.CompanyId);