From c313caa59e5e3a8e38ddce92d226c8e12c278bff Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 18:39:22 +1100 Subject: [PATCH] Add Payment Id to bank transactions table --- .../MatchBankTransactionRequest.php | 27 +++++++++- app/Jobs/Bank/MatchBankTransactions.php | 51 +++++++++++++++++++ .../BankTransactionTransformer.php | 9 ++++ tests/Feature/Bank/BankTransactionTest.php | 41 +++++++++++++++ tests/MockAccountData.php | 14 +++++ 5 files changed, 140 insertions(+), 2 deletions(-) diff --git a/app/Http/Requests/BankTransaction/MatchBankTransactionRequest.php b/app/Http/Requests/BankTransaction/MatchBankTransactionRequest.php index 280565926737..4306a31587af 100644 --- a/app/Http/Requests/BankTransaction/MatchBankTransactionRequest.php +++ b/app/Http/Requests/BankTransaction/MatchBankTransactionRequest.php @@ -13,6 +13,8 @@ namespace App\Http\Requests\BankTransaction; use App\Http\Requests\Request; use App\Models\BankTransaction; +use App\Models\Expense; +use App\Models\Payment; class MatchBankTransactionRequest extends Request { @@ -35,8 +37,10 @@ class MatchBankTransactionRequest extends Request ]; $rules['transactions.*.ninja_category_id'] = 'bail|nullable|sometimes|exists:expense_categories,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; - $rules['transactions.*.vendor_id'] = 'bail|sometimes|exists:vendors,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; + $rules['transactions.*.vendor_id'] = 'bail|nullable|sometimes|exists:vendors,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; $rules['transactions.*.id'] = 'bail|required|exists:bank_transactions,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; + $rules['transactions.*.payment_id'] = 'bail|sometimes|nullable|exists:payments,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; + $rules['transactions.*.expense_id'] = 'bail|sometimes|nullable|exists:expenses,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; return $rules; @@ -58,7 +62,26 @@ class MatchBankTransactionRequest extends Request if(array_key_exists('vendor_id', $inputs['transactions'][$key]) && strlen($inputs['transactions'][$key]['vendor_id']) >= 1) $inputs['transactions'][$key]['vendor_id'] = $this->decodePrimaryKey($inputs['transactions'][$key]['vendor_id']); - // $input = $this->decodePrimaryKeys($input); + if(array_key_exists('payment_id', $inputs['transactions'][$key]) && strlen($inputs['transactions'][$key]['payment_id']) >= 1){ + $inputs['transactions'][$key]['payment_id'] = $this->decodePrimaryKey($inputs['transactions'][$key]['payment_id']); + $p = Payment::withTrashed()->find($inputs['transactions'][$key]['payment_id']); + + /*Ensure we don't relink an existing payment*/ + if(!$p || $p->transaction_id) + $inputs['transactions'][$key]['payment_id'] = null; + + } + + if(array_key_exists('expense_id', $inputs['transactions'][$key]) && strlen($inputs['transactions'][$key]['expense_id']) >= 1){ + $inputs['transactions'][$key]['expense_id'] = $this->decodePrimaryKey($inputs['transactions'][$key]['expense_id']); + $e = Expense::withTrashed()->find($inputs['transactions'][$key]['expense_id']); + + /*Ensure we don't relink an existing expense*/ + if(!$e || $e->transaction_id) + $inputs['transactions'][$key]['expense_id'] = null; + + } + } $this->replace($inputs); diff --git a/app/Jobs/Bank/MatchBankTransactions.php b/app/Jobs/Bank/MatchBankTransactions.php index 0532d51e8b58..2643c4b9fb2c 100644 --- a/app/Jobs/Bank/MatchBankTransactions.php +++ b/app/Jobs/Bank/MatchBankTransactions.php @@ -23,6 +23,7 @@ use App\Models\BankIntegration; use App\Models\BankTransaction; use App\Models\Company; use App\Models\Currency; +use App\Models\Expense; use App\Models\ExpenseCategory; use App\Models\Invoice; use App\Models\Payment; @@ -112,6 +113,10 @@ class MatchBankTransactions implements ShouldQueue { if(array_key_exists('invoice_ids', $input) && strlen($input['invoice_ids']) > 1) $this->matchInvoicePayment($input); + elseif(array_key_exists('payment_id', $input) && strlen($input['payment_id']) > 1) + $this->linkPayment($input); + elseif(array_key_exists('expense_id', $input) && strlen($input['expense_id']) > 1) + $this->linkExpense($input); else $this->matchExpense($input); } @@ -156,6 +161,52 @@ class MatchBankTransactions implements ShouldQueue } + private function linkExpense($input) + { + + $this->bt = BankTransaction::find($input['id']); + + if(!$this->bt || $this->bt->status_id == BankTransaction::STATUS_CONVERTED) + return $this; + + $expense = Expense::withTrashed()->find($input['expense_id']); + + if($expense && !$expense->transaction_id) { + + $expense->transaction_id = $this->bt->id; + $expense->save(); + + $this->bt->expense_id = $expense->id; + $this->bt->status_id = BankTransaction::STATUS_CONVERTED; + $this->bt->save(); + + } + + } + + private function linkPayment($input) + { + + $this->bt = BankTransaction::find($input['id']); + + if(!$this->bt || $this->bt->status_id == BankTransaction::STATUS_CONVERTED) + return $this; + + $payment = Payment::withTrashed()->find($input['payment_id']); + + if($payment && !$payment->transaction_id) { + + $payment->transaction_id = $this->bt->id; + $payment->save(); + + $this->bt->payment_id = $payment->id; + $this->bt->status_id = BankTransaction::STATUS_CONVERTED; + $this->bt->save(); + + } + + } + private function matchInvoicePayment($input) :self { $this->bt = BankTransaction::find($input['id']); diff --git a/app/Transformers/BankTransactionTransformer.php b/app/Transformers/BankTransactionTransformer.php index 483dcc8426cb..3e590f9510b8 100644 --- a/app/Transformers/BankTransactionTransformer.php +++ b/app/Transformers/BankTransactionTransformer.php @@ -39,6 +39,7 @@ class BankTransactionTransformer extends EntityTransformer 'company', 'account', 'expense', + 'payment', 'vendor', 'bank_account', ]; @@ -66,6 +67,7 @@ class BankTransactionTransformer extends EntityTransformer 'base_type' => (string) $bank_transaction->base_type ?: '', 'invoice_ids' => (string) $bank_transaction->invoice_ids ?: '', 'expense_id'=> (string) $this->encodePrimaryKey($bank_transaction->expense_id) ?: '', + 'payment_id'=> (string) $this->encodePrimaryKey($bank_transaction->payment_id) ?: '', 'vendor_id'=> (string) $this->encodePrimaryKey($bank_transaction->vendor_id) ?: '', 'bank_transaction_rule_id' => (string) $this->encodePrimaryKey($bank_transaction->bank_transaction_rule_id) ?: '', 'is_deleted' => (bool) $bank_transaction->is_deleted, @@ -103,4 +105,11 @@ class BankTransactionTransformer extends EntityTransformer return $this->includeItem($bank_transaction->vendor, $transformer, Vendor::class); } + public function includePayment(BankTransaction $bank_transaction) + { + $transformer = new PaymentTransformer($this->serializer); + + return $this->includeItem($bank_transaction->payment, $transformer, Payment::class); + } + } diff --git a/tests/Feature/Bank/BankTransactionTest.php b/tests/Feature/Bank/BankTransactionTest.php index d6a524b2f95b..c18f083a0cbc 100644 --- a/tests/Feature/Bank/BankTransactionTest.php +++ b/tests/Feature/Bank/BankTransactionTest.php @@ -37,6 +37,47 @@ class BankTransactionTest extends TestCase ); } + public function testLinkPaymentToTransaction() + { + + $data = []; + + $bi = BankIntegrationFactory::create($this->company->id, $this->user->id, $this->account->id); + $bi->save(); + + $bt = BankTransactionFactory::create($this->company->id, $this->user->id); + $bt->bank_integration_id = $bi->id; + $bt->status_id = BankTransaction::STATUS_UNMATCHED; + $bt->description = 'Fuel'; + $bt->amount = 10; + $bt->currency_code = $this->client->currency()->code; + $bt->date = now()->format('Y-m-d'); + $bt->transaction_id = 1234567890; + $bt->category_id = 10000003; + $bt->base_type = 'CREDIT'; + $bt->save(); + + $data = []; + + $data['transactions'][] = [ + 'id' => $bt->hashed_id, + 'payment_id' => $this->payment->hashed_id + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson('/api/v1/bank_transactions/match', $data); + + $response->assertStatus(200); + + $this->assertEquals($this->payment->refresh()->transaction_id, $bt->id); + $this->assertEquals($bt->refresh()->payment_id, $this->payment->id); + $this->assertEquals(BankTransaction::STATUS_CONVERTED, $bt->status_id); + + } + + public function testMatchBankTransactionsValidationShouldFail() { $data = []; diff --git a/tests/MockAccountData.php b/tests/MockAccountData.php index 2c62a670e04c..f19bdf98d13e 100644 --- a/tests/MockAccountData.php +++ b/tests/MockAccountData.php @@ -37,6 +37,7 @@ use App\Models\Expense; use App\Models\ExpenseCategory; use App\Models\GroupSetting; use App\Models\InvoiceInvitation; +use App\Models\Payment; use App\Models\Product; use App\Models\Project; use App\Models\PurchaseOrder; @@ -159,6 +160,12 @@ trait MockAccountData */ public $bank_transaction_rule; + + /** + * @var + */ + public $payment; + /** * @var */ @@ -298,6 +305,13 @@ trait MockAccountData 'send_email' => true, ]); + $this->payment = Payment::factory()->create([ + 'user_id' => $user_id, + 'client_id' => $this->client->id, + 'company_id' => $this->company->id, + 'amount' => 10, + ]); + $contact2 = ClientContact::factory()->create([ 'user_id' => $user_id, 'client_id' => $this->client->id,