From e44fd37badfe3e7e9f53fcaf49b6d602f4239e26 Mon Sep 17 00:00:00 2001 From: e1um Date: Wed, 21 Jan 2026 12:44:51 -0500 Subject: [PATCH] fix: sync transaction contact_id when document contact changes When a document (invoice/bill) is updated to change the contact (vendor/customer), any existing transactions linked to that document now have their contact_id updated to match. This fixes an issue where reports filtering by contact would not include transactions from documents that were reassigned to a different contact. Fixes #3336 --- app/Jobs/Document/UpdateDocument.php | 12 +++++++- tests/Feature/Purchases/BillsTest.php | 41 +++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/app/Jobs/Document/UpdateDocument.php b/app/Jobs/Document/UpdateDocument.php index 49f8bebc7..6fc370116 100644 --- a/app/Jobs/Document/UpdateDocument.php +++ b/app/Jobs/Document/UpdateDocument.php @@ -27,7 +27,10 @@ class UpdateDocument extends Job implements ShouldUpdate event(new DocumentUpdating($this->model, $this->request)); - \DB::transaction(function () { + // Track original contact_id to sync transactions if it changes + $originalContactId = $this->model->contact_id; + + \DB::transaction(function () use ($originalContactId) { // Upload attachment if ($this->request->file('attachment')) { $this->deleteMediaModel($this->model, 'attachment', $this->request); @@ -66,6 +69,13 @@ class UpdateDocument extends Job implements ShouldUpdate $this->model->update($this->request->all()); + // Sync transaction contact_id if document contact changed + if (isset($this->request['contact_id']) && $originalContactId != $this->request['contact_id']) { + $this->model->transactions()->update([ + 'contact_id' => $this->request['contact_id'], + ]); + } + $this->model->updateRecurring($this->request->all()); }); diff --git a/tests/Feature/Purchases/BillsTest.php b/tests/Feature/Purchases/BillsTest.php index c879a2ea2..d61a0e1ed 100644 --- a/tests/Feature/Purchases/BillsTest.php +++ b/tests/Feature/Purchases/BillsTest.php @@ -4,6 +4,9 @@ namespace Tests\Feature\Purchases; use App\Exports\Purchases\Bills\Bills as Export; use App\Jobs\Document\CreateDocument; +use App\Jobs\Document\UpdateDocument; +use App\Models\Banking\Transaction; +use App\Models\Common\Contact; use App\Models\Document\Document; use Illuminate\Http\UploadedFile; use Illuminate\Support\Carbon; @@ -235,6 +238,44 @@ class BillsTest extends FeatureTestCase $this->assertFlashLevel('success'); } + public function testItShouldUpdateTransactionContactWhenBillVendorChanges() + { + // Create two different vendors + $vendorA = Contact::factory()->vendor()->enabled()->create(); + $vendorB = Contact::factory()->vendor()->enabled()->create(); + + // Create a bill with vendor A + $request = $this->getRequest(); + $request['contact_id'] = $vendorA->id; + $request['contact_name'] = $vendorA->name; + $request['contact_email'] = $vendorA->email; + + $bill = $this->dispatch(new CreateDocument($request)); + + // Create a transaction (payment) for this bill with vendor A + $transaction = Transaction::factory()->expense()->create([ + 'document_id' => $bill->id, + 'contact_id' => $vendorA->id, + 'type' => 'expense', + ]); + + // Verify transaction has vendor A's contact_id + $this->assertEquals($vendorA->id, $transaction->contact_id); + + // Update the bill to use vendor B + $request['contact_id'] = $vendorB->id; + $request['contact_name'] = $vendorB->name; + $request['contact_email'] = $vendorB->email; + + $this->dispatch(new UpdateDocument($bill, $request)); + + // Refresh the transaction from database + $transaction->refresh(); + + // Verify transaction's contact_id was updated to vendor B + $this->assertEquals($vendorB->id, $transaction->contact_id); + } + public function getRequest($recurring = false) { $factory = Document::factory();