diff --git a/app/Http/Controllers/CompanyGatewayController.php b/app/Http/Controllers/CompanyGatewayController.php index 56fc9ce0c1ff..552374bfd2bc 100644 --- a/app/Http/Controllers/CompanyGatewayController.php +++ b/app/Http/Controllers/CompanyGatewayController.php @@ -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); diff --git a/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php b/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php index 01df934dcf3d..c7702b4e66a3 100644 --- a/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php +++ b/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php @@ -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' diff --git a/app/Models/CompanyGateway.php b/app/Models/CompanyGateway.php index 62ba38ee8e41..ce561f31bf0c 100644 --- a/app/Models/CompanyGateway.php +++ b/app/Models/CompanyGateway.php @@ -155,6 +155,7 @@ class CompanyGateway extends BaseModel 'hxd6gwg3ekb9tb3v9lptgx1mqyg69zu9' => 322, '80af24a6a691230bbec33e930ab40666' => 323, 'vpyfbmdrkqcicpkjqdusgjfluebftuva' => 324, //BTPay + '91be24c7b792230bced33e930ac61676' => 325, ]; protected $touches = []; diff --git a/app/PaymentDrivers/Rotessa/Jobs/TransactionReport.php b/app/PaymentDrivers/Rotessa/Jobs/TransactionReport.php new file mode 100644 index 000000000000..dc8020cca796 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/Jobs/TransactionReport.php @@ -0,0 +1,154 @@ +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, + ); + + }); + } + }); + + } + } + +} \ No newline at end of file diff --git a/app/PaymentDrivers/Rotessa/PaymentMethod.php b/app/PaymentDrivers/Rotessa/PaymentMethod.php index 87c9e2499fb0..9fd4d9f094e5 100755 --- a/app/PaymentDrivers/Rotessa/PaymentMethod.php +++ b/app/PaymentDrivers/Rotessa/PaymentMethod.php @@ -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()) ); } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php index fa04b9f05da6..9eac3cfabc2d 100644 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php @@ -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) { diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php index e037c5b4d322..afd4596bc9b6 100644 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php @@ -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) { diff --git a/app/PaymentDrivers/RotessaPaymentDriver.php b/app/PaymentDrivers/RotessaPaymentDriver.php index 585503d16d54..4326d9280a6f 100644 --- a/app/PaymentDrivers/RotessaPaymentDriver.php +++ b/app/PaymentDrivers/RotessaPaymentDriver.php @@ -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/'; + } + } diff --git a/resources/views/portal/ninja2020/gateways/rotessa/components/address.blade.php b/resources/views/portal/ninja2020/gateways/rotessa/components/address.blade.php index 0d00f32dd036..ef19c8f8b765 100644 --- a/resources/views/portal/ninja2020/gateways/rotessa/components/address.blade.php +++ b/resources/views/portal/ninja2020/gateways/rotessa/components/address.blade.php @@ -22,7 +22,7 @@ {{ ctrans('texts.address2') }}
- +