Feature: add ability to unmap receipts from transactions
Add unmap functionality to allow users to disassociate receipts from transactions without deleting them: - ReceiptManager: Add UnmapReceiptAsync method - Receipts page: Add OnPostUnmapAsync handler - Receipts view: Add Unmap button for mapped receipts with confirmation dialog This provides a non-destructive alternative to deleting receipts when they need to be remapped to different transactions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -235,6 +235,14 @@
|
||||
Map
|
||||
</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form method="post" asp-page-handler="Unmap" asp-route-receiptId="@r.Id" style="display: inline;" onsubmit="return confirm('Are you sure you want to unmap this receipt from the transaction?');">
|
||||
<button type="submit" class="btn btn-outline-warning btn-sm" title="Unmap from Transaction">
|
||||
Unmap
|
||||
</button>
|
||||
</form>
|
||||
}
|
||||
<form method="post" asp-page-handler="Delete" asp-route-receiptId="@r.Id" style="display: inline;" onsubmit="return confirm('Are you sure you want to delete this receipt?');">
|
||||
<button type="submit" class="btn btn-outline-danger btn-sm" title="Delete">
|
||||
Delete
|
||||
|
||||
@@ -218,6 +218,24 @@ namespace MoneyMap.Pages
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostUnmapAsync(long receiptId)
|
||||
{
|
||||
var success = await _receiptManager.UnmapReceiptAsync(receiptId);
|
||||
|
||||
if (success)
|
||||
{
|
||||
Message = "Receipt unmapped successfully.";
|
||||
IsSuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Message = "Failed to unmap receipt.";
|
||||
IsSuccess = false;
|
||||
}
|
||||
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
private async Task LoadReceiptsAsync()
|
||||
{
|
||||
var receipts = await _db.Receipts
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace MoneyMap.Services
|
||||
Task<ReceiptUploadResult> UploadUnmappedReceiptAsync(IFormFile file);
|
||||
Task<bool> DeleteReceiptAsync(long receiptId);
|
||||
Task<bool> MapReceiptToTransactionAsync(long receiptId, long transactionId);
|
||||
Task<bool> UnmapReceiptAsync(long receiptId);
|
||||
string GetReceiptPhysicalPath(Receipt receipt);
|
||||
Task<Receipt?> GetReceiptAsync(long receiptId);
|
||||
}
|
||||
@@ -210,6 +211,19 @@ namespace MoneyMap.Services
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> UnmapReceiptAsync(long receiptId)
|
||||
{
|
||||
var receipt = await _db.Receipts.FindAsync(receiptId);
|
||||
if (receipt == null)
|
||||
return false;
|
||||
|
||||
// Set TransactionId to null to unmap
|
||||
receipt.TransactionId = null;
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string SanitizeFileName(string fileName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
@@ -219,7 +233,7 @@ namespace MoneyMap.Services
|
||||
var sanitized = new StringBuilder();
|
||||
foreach (var c in fileName)
|
||||
{
|
||||
if (c == '®' || c == '™' || c == '©')
|
||||
if (c == '<EFBFBD>' || c == '<EFBFBD>' || c == '<EFBFBD>')
|
||||
{
|
||||
// Skip trademark/copyright symbols
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user