Improvements for Gateways that are preferentially sorted

This commit is contained in:
David Bomba
2026-01-13 17:55:39 +11:00
parent 5dbfcf7097
commit 48b07f4af7
6 changed files with 164 additions and 12 deletions

View File

@@ -22,8 +22,8 @@ use App\Jobs\Util\ApplePayDomain;
use Illuminate\Support\Facades\Cache;
use App\Factory\CompanyGatewayFactory;
use App\Filters\CompanyGatewayFilters;
use App\Repositories\CompanyRepository;
use Illuminate\Foundation\Bus\DispatchesJobs;
use App\Repositories\CompanyGatewayRepository;
use App\Transformers\CompanyGatewayTransformer;
use App\PaymentDrivers\Stripe\Jobs\StripeWebhook;
use App\PaymentDrivers\CheckoutCom\CheckoutSetupWebhook;
@@ -63,9 +63,9 @@ class CompanyGatewayController extends BaseController
/**
* CompanyGatewayController constructor.
* @param CompanyRepository $company_repo
* @param CompanyGatewayRepository $company_repo
*/
public function __construct(CompanyRepository $company_repo)
public function __construct(CompanyGatewayRepository $company_repo)
{
parent::__construct();
@@ -210,10 +210,14 @@ class CompanyGatewayController extends BaseController
/** @var \App\Models\User $user */
$user = auth()->user();
$company = $user->company();
$company_gateway = CompanyGatewayFactory::create($user->company()->id, $user->id);
$company_gateway->fill($request->all());
$company_gateway->save();
$this->company_repo->addGatewayToCompanyGatewayIds($company_gateway);
/*Always ensure at least one fees and limits object is set per gateway*/
$gateway_types = $company_gateway->driver(new Client())->getAvailableMethods();

View File

@@ -30,7 +30,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property bool $is_deleted
* @property string $config
* @property object $settings
* @property mixed $fees_and_limits
* @property array|object|mixed $fees_and_limits
* @property string|null $custom_value1
* @property string|null $custom_value2
* @property string|null $custom_value3

View File

@@ -0,0 +1,94 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2025. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Repositories;
use App\Utils\Ninja;
use App\Models\Company;
use App\Models\CompanyGateway;
use App\Repositories\BaseRepository;
/**
* CompanyGatewayRepository.
*/
class CompanyGatewayRepository extends BaseRepository
{
public function __construct()
{
}
public function archive($company_gateway): CompanyGateway
{
parent::archive($company_gateway);
$this->removeGatewayFromCompanyGatewayIds($company_gateway);
return $company_gateway;
}
public function delete($company_gateway): CompanyGateway
{
parent::delete($company_gateway);
$this->removeGatewayFromCompanyGatewayIds($company_gateway);
return $company_gateway;
}
public function restore($company_gateway): CompanyGateway
{
parent::restore($company_gateway);
$this->addGatewayToCompanyGatewayIds($company_gateway);
return $company_gateway;
}
public function addGatewayToCompanyGatewayIds(CompanyGateway $company_gateway)
{
$company_gateway_ids = $company_gateway->company->getSetting('company_gateway_ids');
if(strlen($company_gateway_ids ?? '') > 2){
$transformed_ids = collect($this->transformKeys(explode(',', $company_gateway_ids)))
->push($company_gateway->hashed_id)
->implode(",");
$company = $company_gateway->company;
$settings = $company->settings;
$settings->company_gateway_ids = $transformed_ids;
$company->settings = $settings;
$company->save();
}
}
public function removeGatewayFromCompanyGatewayIds(CompanyGateway $company_gateway)
{
$company_gateway_ids = $company_gateway->company->getSetting('company_gateway_ids');
if(strpos($company_gateway_ids, $company_gateway->hashed_id) !== false){
$transformed_ids = collect($this->transformKeys(explode(',', $company_gateway_ids)))
->filter(function ($id) use ($company_gateway){
return $id !== $company_gateway->hashed_id;
})
->implode(",");
$company = $company_gateway->company;
$settings = $company->settings;
$settings->company_gateway_ids = $transformed_ids;
$company->settings = $settings;
$company->save();
}
}
}

View File

@@ -33,9 +33,12 @@ use App\Events\Invoice\InvoiceWasPaid;
use App\Repositories\CreditRepository;
use App\Repositories\PaymentRepository;
use App\Events\Payment\PaymentWasCreated;
use App\Utils\Traits\MakesHash;
class AutoBillInvoice extends AbstractService
{
use MakesHash;
private Client $client;
private array $used_credit = [];
@@ -45,9 +48,7 @@ class AutoBillInvoice extends AbstractService
public function __construct(private Invoice $invoice, protected string $db)
{
$this->client = $this->invoice->client;
}
public function run()
@@ -55,7 +56,6 @@ class AutoBillInvoice extends AbstractService
MultiDB::setDb($this->db);
/* @var \App\Modesl\Client $client */
$is_partial = false;
/* Is the invoice payable? */
@@ -444,14 +444,32 @@ class AutoBillInvoice extends AbstractService
*/
public function getGateway($amount)
{
$company_gateway_ids = $this->client->getSetting('company_gateway_ids');
$transformed_ids = false;
//gateways are disabled!
if($company_gateway_ids == "0") {
return false;
}
elseif(strlen($company_gateway_ids ?? '') > 2){
// If the client has a special gateway configuration, we need to ensure we only use the ones that are enabled!
$transformed_ids = $this->transformKeys(explode(',', $company_gateway_ids));
}
//get all client gateway tokens and set the is_default one to the first record
$gateway_tokens = \App\Models\ClientGatewayToken::query()
->where('client_id', $this->client->id)
->where('is_deleted', 0)
->whereHas('gateway', function ($query) {
->whereHas('gateway', function ($query) use ($transformed_ids) {
$query->where('is_deleted', 0)
->where('deleted_at', null);
})->orderBy('is_default', 'DESC')
->where('deleted_at', null)
->when($transformed_ids, function ($q) use ($transformed_ids) {
$q->whereIn('id', $transformed_ids);
});
})
->orderBy('is_default', 'DESC')
->get();
$filtered_gateways = $gateway_tokens->filter(function ($gateway_token) use ($amount) {

View File

@@ -45,6 +45,44 @@ class CompanyGatewayApiTest extends TestCase
Model::reguard();
}
public function testCompanyGatewayIdsUpdateWhenAddingNewGateway()
{
$settings = $this->company->settings;
$settings->company_gateway_ids = "Xe0Vjm5ybx,Xe00Aw9Lex,Xe0RpmK3Gb";
$this->company->settings = $settings;
$this->company->save();
$this->assertEquals("Xe0Vjm5ybx,Xe00Aw9Lex,Xe0RpmK3Gb", $this->company->getSetting('company_gateway_ids'));
$data = [
'config' => 'random config',
'gateway_key' => '3b6621f970ab18887c4f6dca78d3f8bb',
];
/* POST */
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/company_gateways', $data);
$cg = $response->json();
$cg_id = $cg['data']['id'];
$this->assertNotNull($cg_id);
$response->assertStatus(200);
$company = $this->company->fresh();
$settings = $company->settings;
$this->assertCount(4, explode(',', $company->getSetting('company_gateway_ids')));
$this->assertStringContainsString($cg_id, $company->getSetting('company_gateway_ids'));
}
public function testBulkActions()
{
$cg = CompanyGatewayFactory::create($this->company->id, $this->user->id);

View File

@@ -12,12 +12,10 @@
namespace Tests\Feature;
use App\Jobs\Invoice\CheckGatewayFee;
use App\Models\CompanyGateway;
use App\Models\GatewayType;
use App\Models\Invoice;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\MockAccountData;
use Tests\TestCase;