mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Cron checks for Rotessa Paymetns
This commit is contained in:
parent
da9e587f67
commit
4a7a54a9ea
@ -567,9 +567,9 @@ class CompanyGatewayController extends BaseController
|
||||
{
|
||||
|
||||
//Throttle here
|
||||
if (Cache::has("throttle_polling:import_customers:{$company_gateway->company->company_key}:{$company_gateway->hashed_id}")) {
|
||||
return response()->json(['message' => 'Please wait whilst your previous attempts complete.'], 200);
|
||||
}
|
||||
// if (Cache::has("throttle_polling:import_customers:{$company_gateway->company->company_key}:{$company_gateway->hashed_id}")) {
|
||||
// return response()->json(['message' => 'Please wait whilst your previous attempts complete.'], 200);
|
||||
// }
|
||||
|
||||
dispatch(function () use ($company_gateway) {
|
||||
MultiDB::setDb($company_gateway->company->db);
|
||||
|
@ -27,7 +27,7 @@ class AccountComponent extends Component
|
||||
'routing_number' => null,
|
||||
'institution_number' => null,
|
||||
'transit_number' => null,
|
||||
'bank_name' => ' ',
|
||||
'bank_name' => null,
|
||||
'account_number' => null,
|
||||
'country' => 'US',
|
||||
"authorization_type" => 'Online'
|
||||
|
@ -155,6 +155,7 @@ class CompanyGateway extends BaseModel
|
||||
'hxd6gwg3ekb9tb3v9lptgx1mqyg69zu9' => 322,
|
||||
'80af24a6a691230bbec33e930ab40666' => 323,
|
||||
'vpyfbmdrkqcicpkjqdusgjfluebftuva' => 324, //BTPay
|
||||
'91be24c7b792230bced33e930ac61676' => 325,
|
||||
];
|
||||
|
||||
protected $touches = [];
|
||||
|
154
app/PaymentDrivers/Rotessa/Jobs/TransactionReport.php
Normal file
154
app/PaymentDrivers/Rotessa/Jobs/TransactionReport.php
Normal file
@ -0,0 +1,154 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\PaymentDrivers\Rotessa\Jobs;
|
||||
|
||||
use App\Utils\Ninja;
|
||||
use App\Models\Payment;
|
||||
use App\Models\SystemLog;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\PaymentHash;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use App\Jobs\Mail\PaymentFailedMailer;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
|
||||
class TransactionReport implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
public $tries = 1; //number of retries
|
||||
|
||||
public $deleteWhenMissingModels = true;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
set_time_limit(0);
|
||||
|
||||
foreach(MultiDB::$dbs as $db)
|
||||
{
|
||||
MultiDB::setDB($db);
|
||||
|
||||
CompanyGateway::where('gateway_key', '91be24c7b792230bced33e930ac61676')
|
||||
->cursor()
|
||||
->each(function ($cg){
|
||||
|
||||
$driver = $cg->driver()->init();
|
||||
|
||||
//Approved Transactions
|
||||
$transactions = $driver->gatewayRequest("get", "transaction_report", ['page' => 1, 'status' => 'Approved', 'start_date' => now()->subMonths(2)->format('Y-m-d')]);
|
||||
|
||||
if($transactions->successful())
|
||||
{
|
||||
$transactions = $transactions->json();
|
||||
nlog($transactions);
|
||||
|
||||
Payment::query()
|
||||
->where('company_id', $cg->company_id)
|
||||
->where('status_id', Payment::STATUS_PENDING)
|
||||
->whereIn('transaction_reference', array_column($transactions, "transaction_schedule_id"))
|
||||
->cursor()
|
||||
->each(function ($payment) use ($transactions) {
|
||||
|
||||
$payment->status_id = Payment::STATUS_COMPLETED;
|
||||
$payment->save();
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => collect($transactions)->where('id', $payment->transaction_reference)->first()->toArray(), 'data' => []],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_ROTESSA,
|
||||
$payment->client,
|
||||
$payment->company,
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
//Declined / Charged Back Transactions
|
||||
$declined_transactions = $driver->gatewayRequest("get", "transaction_report", ['page' => 1, 'status' => 'Declined', 'start_date' => now()->subMonths(2)->format('Y-m-d')]);
|
||||
$chargeback_transactions = $driver->gatewayRequest("get", "transaction_report", ['page' => 1, 'status' => 'Chargeback', 'start_date' => now()->subMonths(2)->format('Y-m-d')]);
|
||||
|
||||
if($declined_transactions->successful() && $chargeback_transactions->successful()) {
|
||||
|
||||
$transactions = array_merge($declined_transactions->json(), $chargeback_transactions->json());
|
||||
|
||||
nlog($transactions);
|
||||
|
||||
Payment::query()
|
||||
->where('company_id', $cg->company_id)
|
||||
->where('status_id', Payment::STATUS_PENDING)
|
||||
->whereIn('transaction_reference', array_column($transactions, "transaction_schedule_id"))
|
||||
->cursor()
|
||||
->each(function ($payment) use ($transactions){
|
||||
|
||||
|
||||
$client = $payment->client;
|
||||
|
||||
$payment->service()->deletePayment();
|
||||
|
||||
$payment->status_id = Payment::STATUS_FAILED;
|
||||
$payment->save();
|
||||
|
||||
$payment_hash = PaymentHash::query()->where('payment_id', $payment->id)->first();
|
||||
|
||||
if ($payment_hash) {
|
||||
|
||||
App::forgetInstance('translator');
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($client->getMergedSettings()));
|
||||
App::setLocale($client->locale());
|
||||
|
||||
$error = ctrans('texts.client_payment_failure_body', [
|
||||
'invoice' => implode(',', $payment->invoices->pluck('number')->toArray()),
|
||||
'amount' => array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total, ]);
|
||||
} else {
|
||||
$error = 'Payment for '.$payment->client->present()->name()." for {$payment->amount} failed";
|
||||
}
|
||||
|
||||
PaymentFailedMailer::dispatch(
|
||||
$payment_hash,
|
||||
$client->company,
|
||||
$client,
|
||||
$error
|
||||
);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => collect($transactions)->where('id', $payment->transaction_reference)->first()->toArray(), 'data' => []],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_ROTESSA,
|
||||
$payment->client,
|
||||
$payment->company,
|
||||
);
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -81,7 +81,7 @@ class PaymentMethod implements MethodInterface
|
||||
'country' => ['required'],
|
||||
'name' => ['required'],
|
||||
'address_1' => ['required'],
|
||||
'address_2' => ['required'],
|
||||
// 'address_2' => ['required'],
|
||||
'city' => ['required'],
|
||||
'email' => ['required','email:filter'],
|
||||
'province_code' => ['required','size:2','alpha'],
|
||||
@ -90,7 +90,7 @@ class PaymentMethod implements MethodInterface
|
||||
'account_number' => ['required'],
|
||||
'bank_name' => ['required'],
|
||||
'phone' => ['required'],
|
||||
'home_phone' => ['required'],
|
||||
'home_phone' => ['required','size:10'],
|
||||
'bank_account_type'=>['required_if:country,US'],
|
||||
'routing_number'=>['required_if:country,US'],
|
||||
'institution_number'=>['required_if:country,CA','numeric'],
|
||||
@ -159,11 +159,14 @@ class PaymentMethod implements MethodInterface
|
||||
$transaction = new Transaction($request->only('frequency' ,'installments','amount','process_date') + ['comment' => $this->rotessa->getDescription(false) ]);
|
||||
$transaction->additional(['customer_id' => $customer->gateway_customer_reference]);
|
||||
$transaction = array_filter( $transaction->resolve());
|
||||
$response = $this->rotessa->gateway->capture($transaction)->send();
|
||||
$response = $this->rotessa->gatewayRequest('post','transaction_schedules', $transaction);
|
||||
|
||||
if($response->failed())
|
||||
$response->throw();
|
||||
|
||||
if(!$response->isSuccessful()) throw new \Exception($response->getMessage(), (int) $response->getCode());
|
||||
|
||||
return $this->processPendingPayment($response->getParameter('id'), (float) $response->getParameter('amount'), PaymentType::ACSS , $customer->token);
|
||||
$response = $response->json();
|
||||
nlog($response);
|
||||
return $this->processPendingPayment($response['id'], (float) $response['amount'], PaymentType::ACSS , $customer->token);
|
||||
} catch(\Throwable $e) {
|
||||
$this->processUnsuccessfulPayment( new InvalidResponseException($e->getMessage(), (int) $e->getCode()) );
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ class PatchTransactionSchedulesId extends BaseRequest implements RequestInterfac
|
||||
public function setId(int $value) {
|
||||
$this->setParameter('id',$value);
|
||||
}
|
||||
public function setAmount(int $value) {
|
||||
public function setAmount($value) {
|
||||
$this->setParameter('amount',$value);
|
||||
}
|
||||
public function setComment(string $value) {
|
||||
|
@ -15,7 +15,7 @@ class PostTransactionSchedulesUpdateViaPost extends BaseRequest implements Reque
|
||||
public function setId(int $value) {
|
||||
$this->setParameter('id',$value);
|
||||
}
|
||||
public function setAmount(int $value) {
|
||||
public function setAmount($value) {
|
||||
$this->setParameter('amount',$value);
|
||||
}
|
||||
public function setComment(string $value) {
|
||||
|
@ -30,6 +30,7 @@ use Illuminate\Database\Eloquent\Builder;
|
||||
use App\PaymentDrivers\Rotessa\Resources\Customer;
|
||||
use App\PaymentDrivers\Rotessa\PaymentMethod as Acss;
|
||||
use App\PaymentDrivers\Rotessa\PaymentMethod as BankTransfer;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class RotessaPaymentDriver extends BaseDriver
|
||||
{
|
||||
@ -54,11 +55,6 @@ class RotessaPaymentDriver extends BaseDriver
|
||||
|
||||
public function init(): self
|
||||
{
|
||||
|
||||
$this->gateway = Omnipay::create(
|
||||
$this->company_gateway->gateway->provider
|
||||
);
|
||||
$this->gateway->initialize((array) $this->company_gateway->getConfig());
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -117,30 +113,42 @@ class RotessaPaymentDriver extends BaseDriver
|
||||
}
|
||||
|
||||
public function importCustomers() {
|
||||
$this->init();
|
||||
|
||||
try {
|
||||
if(!$result = Cache::has("rotessa-import_customers-{$this->company_gateway->company->company_key}")) {
|
||||
$result = $this->gateway->getCustomers()->send();
|
||||
if(!$result->isSuccessful()) throw new \Exception($result->getMessage(), (int) $result->getCode());
|
||||
// cache results
|
||||
Cache::put("rotessa-import_customers-{$this->company_gateway->company->company_key}", $result->getData(), 60 * 60 * 24);
|
||||
}
|
||||
|
||||
$result = Cache::get("rotessa-import_customers-{$this->company_gateway->company->company_key}");
|
||||
$customers = collect($result)->unique('email');
|
||||
$result = $this->gatewayRequest('get','customers',[]);
|
||||
|
||||
if($result->failed())
|
||||
$result->throw();
|
||||
|
||||
$customers = collect($result->json())->unique('email');
|
||||
|
||||
$client_emails = $customers->pluck('email')->all();
|
||||
$company_id = $this->company_gateway->company->id;
|
||||
// get existing customers
|
||||
$client_contacts = ClientContact::where('company_id', $company_id)->whereIn('email', $client_emails )->whereNull('deleted_at')->get();
|
||||
$client_contacts = ClientContact::where('company_id', $company_id)
|
||||
->whereIn('email', $client_emails )
|
||||
->whereHas('client', function ($q){
|
||||
$q->where('is_deleted', false);
|
||||
})
|
||||
->whereNull('deleted_at')
|
||||
->get();
|
||||
|
||||
$client_contacts = $client_contacts->map(function($item, $key) use ($customers) {
|
||||
return array_merge([], (array) $customers->firstWhere("email", $item->email) , ['custom_identifier' => $item->client->number, 'identifier' => $item->client->number, 'client_id' => $item->client->id ]);
|
||||
return array_merge($customers->firstWhere("email", $item->email),['custom_identifier' => $item->client->number, 'identifier' => $item->client->number, 'client_id' => $item->client->id ]);
|
||||
} );
|
||||
|
||||
// create payment methods
|
||||
$client_contacts->each(
|
||||
function($contact) use ($customers) {
|
||||
$result = $this->gateway->getCustomersId(['id' => ($contact = (object) $contact)->id])->send();
|
||||
function($contact) {
|
||||
// $result = $this->gateway->getCustomersId(['id' => ($contact = (object) $contact)->id])->send();
|
||||
$contact = (object)$contact;
|
||||
|
||||
$result = $this->gatewayRequest("get","customers/{$contact->id}");
|
||||
$result = $result->json();
|
||||
|
||||
$this->client = Client::find($contact->client_id);
|
||||
$customer = (new Customer($result->getData()))->additional(['id' => $contact->id, 'custom_identifier' => $contact->custom_identifier ] );
|
||||
|
||||
$customer = (new Customer($result))->additional(['id' => $contact->id, 'custom_identifier' => $contact->custom_identifier ] );
|
||||
$this->findOrCreateCustomer($customer->additional + $customer->jsonSerialize());
|
||||
}
|
||||
);
|
||||
@ -150,8 +158,8 @@ class RotessaPaymentDriver extends BaseDriver
|
||||
$client_contacts = $customers->filter(function ($value, $key) use ($client_emails) {
|
||||
return !in_array(((object) $value)->email, $client_emails);
|
||||
})->each( function($customer) use ($company_id) {
|
||||
// create new client contact from rotess customer
|
||||
$customer = (object) $this->gateway->getCustomersId(['id' => ($customer = (object) $customer)->id])->send()->getData();
|
||||
|
||||
$customer = $this->gatewayRequest("get", "customers/{$customer['id']}")->json();
|
||||
/**
|
||||
{
|
||||
"account_number": "11111111"
|
||||
@ -186,7 +194,7 @@ class RotessaPaymentDriver extends BaseDriver
|
||||
*/
|
||||
$settings = ClientSettings::defaults();
|
||||
$settings->currency_id = $this->company_gateway->company->getSetting('currency_id');
|
||||
|
||||
$customer = (object)$customer;
|
||||
$client = (\App\Factory\ClientFactory::create($this->company_gateway->company_id, $this->company_gateway->user_id))->fill(
|
||||
[
|
||||
'address1' => $customer->address['address_1'] ?? '',
|
||||
@ -245,12 +253,18 @@ class RotessaPaymentDriver extends BaseDriver
|
||||
->where('gateway_customer_reference', Arr::only($data,'id'));
|
||||
})
|
||||
->exists();
|
||||
if ($existing) return true;
|
||||
if ($existing)
|
||||
return true;
|
||||
else if(!Arr::has($data,'id')) {
|
||||
$result = $this->gateway->authorize($data)->send();
|
||||
if (!$result->isSuccessful()) throw new \Exception($result->getMessage(), (int) $result->getCode());
|
||||
// $result = $this->gateway->authorize($data)->send();
|
||||
// if (!$result->isSuccessful()) throw new \Exception($result->getMessage(), (int) $result->getCode());
|
||||
|
||||
$customer = new Customer($result->getData());
|
||||
$result = $this->gatewayRequest('post', 'customers', $data);
|
||||
|
||||
if($result->failed())
|
||||
$result->throw();
|
||||
|
||||
$customer = new Customer($result->json());
|
||||
$data = array_filter($customer->resolve());
|
||||
|
||||
}
|
||||
@ -268,7 +282,6 @@ class RotessaPaymentDriver extends BaseDriver
|
||||
|
||||
return $data['id'];
|
||||
|
||||
throw new \Exception($result->getMessage(), (int) $result->getCode());
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
$data = [
|
||||
@ -276,7 +289,7 @@ class RotessaPaymentDriver extends BaseDriver
|
||||
'transaction_response' => $th->getMessage(),
|
||||
'success' => false,
|
||||
'description' => $th->getMessage(),
|
||||
'code' =>(int) $th->getCode()
|
||||
'code' => 500
|
||||
];
|
||||
|
||||
SystemLogger::dispatch(['server_response' => is_null($result) ? '' : $result->getMessage(), 'data' => $data], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, 880 , $this->client, $this->company_gateway->company);
|
||||
@ -284,4 +297,20 @@ class RotessaPaymentDriver extends BaseDriver
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
public function gatewayRequest($verb, $uri, $payload = [])
|
||||
{
|
||||
$r = Http::withToken($this->company_gateway->getConfigField('apiKey'))
|
||||
->{$verb}($this->getUrl().$uri, $payload);
|
||||
|
||||
nlog($r->body());
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
private function getUrl(): string
|
||||
{
|
||||
return $this->company_gateway->getConfigField('testMode') ? 'https://sandbox-api.rotessa.com/v1/' : 'https://api.rotessa.com/v1/';
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
{{ ctrans('texts.address2') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
<input class="input w-full" id="address_2" name="address_2" type="text" placeholder="Address Line 2" required value="{{ old('address_2', $address_2) }}">
|
||||
<input class="input w-full" id="address_2" name="address_2" type="text" placeholder="Address Line 2" value="{{ old('address_2', $address_2) }}">
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user