From 42ccfe0700ff2fc74cfa2b21e25c57d9ce41ff75 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 4 May 2020 21:13:46 +1000 Subject: [PATCH] Checkout stubs (#3672) * minor fixes for name spaces, collector facade and composer version bump * Fixes for invoiceworkflowsettings * Add more context to support emails * Working on Firing Subscriptions * Minor fixes * Fixes for gateway filtering * Checkout Driver --- app/Console/Commands/CreateTestData.php | 24 +-- app/Http/Controllers/Auth/LoginController.php | 6 +- app/Http/Controllers/MigrationController.php | 9 +- .../Controllers/SubscriptionController.php | 4 +- .../Support/Messages/SendingController.php | 2 +- app/Http/Livewire/InvoicesTable.php | 2 +- app/Jobs/Invoice/InvoiceWorkflowSettings.php | 11 +- app/Jobs/Util/SubscriptionHandler.php | 34 +++++ app/Mail/SupportMessageSent.php | 12 +- app/Models/Client.php | 3 +- app/PaymentDrivers/BasePaymentDriver.php | 78 +++++++++- app/PaymentDrivers/CheckoutPaymentDriver.php | 139 ++++++++++++++++++ app/PaymentDrivers/StripePaymentDriver.php | 1 - composer.json | 3 +- config/collector.php | 13 +- config/ninja.php | 1 + database/seeds/RandomDataSeeder.php | 13 ++ .../gateways/checkout/credit_card.blade.php | 42 ++++++ 18 files changed, 347 insertions(+), 50 deletions(-) create mode 100644 app/Jobs/Util/SubscriptionHandler.php create mode 100644 app/PaymentDrivers/CheckoutPaymentDriver.php create mode 100644 resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php diff --git a/app/Console/Commands/CreateTestData.php b/app/Console/Commands/CreateTestData.php index 52714d69e1..df22a2a24b 100644 --- a/app/Console/Commands/CreateTestData.php +++ b/app/Console/Commands/CreateTestData.php @@ -462,36 +462,14 @@ class CreateTestData extends Command $invoice = $invoice_calc->getInvoice(); $invoice->save(); - $invoice->service()->createInvitations(); - - $invoice->ledger()->updateInvoiceBalance($invoice->balance); - - //UpdateCompanyLedgerWithInvoice::dispatchNow($invoice, $invoice->balance, $invoice->company); + $invoice->service()->createInvitations()->markSent(); $this->invoice_repo->markSent($invoice); - $invoice->service()->createInvitations(); - if (rand(0, 1)) { - // $payment = PaymentFactory::create($client->company->id, $client->user->id); - // $payment->date = $dateable; - // $payment->client_id = $client->id; - // $payment->amount = $invoice->balance; - // $payment->transaction_reference = rand(0, 500); - // $payment->type_id = PaymentType::CREDIT_CARD_OTHER; - // $payment->status_id = Payment::STATUS_COMPLETED; - // $payment->number = $client->getNextPaymentNumber($client); - // $payment->currency_id = 1; - // $payment->save(); - - // $payment->invoices()->save($invoice); $invoice = $invoice->service()->markPaid()->save(); - //$payment = $invoice->payments->first(); - - //$payment->service()->updateInvoicePayment(); - //UpdateInvoicePayment::dispatchNow($payment, $payment->company); } //@todo this slow things down, but gives us PDFs of the invoices for inspection whilst debugging. event(new InvoiceWasCreated($invoice, $invoice->company)); diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index c9ecda95eb..2f55e37f70 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -28,7 +28,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Log; use Laravel\Socialite\Facades\Socialite; -use Turbo124\Collector\CollectorFacade as Collector; +use Turbo124\Collector\Facades\LightLogs; class LoginController extends BaseController { @@ -172,7 +172,7 @@ class LoginController extends BaseController if ($this->attemptLogin($request)) { - Collector::create(new LoginSuccess()) + LightLogs::create(new LoginSuccess()) ->increment() ->batch(); @@ -186,7 +186,7 @@ class LoginController extends BaseController return $this->listResponse($ct); } else { - Collector::create(new LoginFailure()) + LightLogs::create(new LoginFailure()) ->increment() ->batch(); diff --git a/app/Http/Controllers/MigrationController.php b/app/Http/Controllers/MigrationController.php index 1348bbfa82..0b0bbfcc17 100644 --- a/app/Http/Controllers/MigrationController.php +++ b/app/Http/Controllers/MigrationController.php @@ -201,7 +201,8 @@ class MigrationController extends BaseController if ($checks['same_keys'] && $checks['with_force']) { info('Migrating: Same company keys, with force.'); - $this->purgeCompany($company); + if($company) + $this->purgeCompany($company); $account = auth()->user()->account; $company = (new ImportMigrations())->getCompany($account); @@ -255,7 +256,8 @@ class MigrationController extends BaseController if (!$checks['same_keys'] && $checks['existing_company'] && $checks['with_force']) { info('Migrating: Different keys, exisiting company with force option.'); - $this->purgeCompany($company); + if($company) + $this->purgeCompany($company); $account = auth()->user()->account; $company = (new ImportMigrations())->getCompany($account); @@ -283,7 +285,8 @@ class MigrationController extends BaseController if (!$checks['same_keys'] && $checks['with_force']) { info('Migrating: Different keys with force.'); - $this->purgeCompany($existing_company); + if($existing_company) + $this->purgeCompany($existing_company); $account = auth()->user()->account; $company = (new ImportMigrations())->getCompany($account); diff --git a/app/Http/Controllers/SubscriptionController.php b/app/Http/Controllers/SubscriptionController.php index 118e30fea8..243a458e57 100644 --- a/app/Http/Controllers/SubscriptionController.php +++ b/app/Http/Controllers/SubscriptionController.php @@ -302,7 +302,9 @@ class SubscriptionController extends BaseController public function create(CreateSubscriptionRequest $request) { $subscription = SubscriptionFactory::create(auth()->user()->company()->id, auth()->user()->id); - + $subscription->fill($request->all()); + $subscription->save(); + return $this->itemResponse($subscription); } diff --git a/app/Http/Controllers/Support/Messages/SendingController.php b/app/Http/Controllers/Support/Messages/SendingController.php index e404c59abc..2efba47ecf 100644 --- a/app/Http/Controllers/Support/Messages/SendingController.php +++ b/app/Http/Controllers/Support/Messages/SendingController.php @@ -80,6 +80,6 @@ class SendingController extends Controller return response()->json([ 'success' => true - ]); + ], 200); } } diff --git a/app/Http/Livewire/InvoicesTable.php b/app/Http/Livewire/InvoicesTable.php index abc401d7c9..e400047986 100644 --- a/app/Http/Livewire/InvoicesTable.php +++ b/app/Http/Livewire/InvoicesTable.php @@ -3,7 +3,7 @@ namespace App\Http\Livewire; use App\Models\Invoice; -use App\Traits\WithSorting; +use App\Utils\Traits\WithSorting; use Carbon\Carbon; use Livewire\Component; use Livewire\WithPagination; diff --git a/app/Jobs/Invoice/InvoiceWorkflowSettings.php b/app/Jobs/Invoice/InvoiceWorkflowSettings.php index 9678680ebc..b12bf333af 100644 --- a/app/Jobs/Invoice/InvoiceWorkflowSettings.php +++ b/app/Jobs/Invoice/InvoiceWorkflowSettings.php @@ -55,10 +55,11 @@ class InvoiceWorkflowSettings implements ShouldQueue $this->base_repository->archive($this->invoice); } - if ($this->client->getSetting('auto_email_invoice')) { - $this->invoice->invitations->each(function ($invitation, $key) { - $this->invoice->service()->sendEmail($invitation->contact); - }); - } + //@TODO this setting should only fire for recurring invoices + // if ($this->client->getSetting('auto_email_invoice')) { + // $this->invoice->invitations->each(function ($invitation, $key) { + // $this->invoice->service()->sendEmail($invitation->contact); + // }); + // } } } diff --git a/app/Jobs/Util/SubscriptionHandler.php b/app/Jobs/Util/SubscriptionHandler.php new file mode 100644 index 0000000000..ec4a7da247 --- /dev/null +++ b/app/Jobs/Util/SubscriptionHandler.php @@ -0,0 +1,34 @@ +user()->account; + + $plan = $account->plan ?: 'Self Hosted'; + + $company = auth()->user()->company(); + $user = auth()->user(); + + $subject = "Customer MSG {$user->present()->name} - [{$plan} - DB:{$company->db}]"; + return $this->from(config('mail.from.address')) //todo this needs to be fixed to handle the hosted version - ->subject(ctrans('texts.new_support_message')) + ->subject($subject) ->markdown('email.support.message', [ 'message' => $this->message, 'system_info' => $system_info, diff --git a/app/Models/Client.php b/app/Models/Client.php index 6175f676db..92198fcf57 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -16,7 +16,6 @@ use App\DataMapper\CompanySettings; use App\Factory\CreditFactory; use App\Factory\InvoiceFactory; use App\Factory\QuoteFactory; -use App\Models\Client; use App\Models\Company; use App\Models\CompanyGateway; use App\Models\Country; @@ -346,7 +345,7 @@ class Client extends BaseModel implements HasLocalePreference $company_gateways = $this->getSetting('company_gateway_ids'); if (strlen($company_gateways)>=1) { - $gateways = $this->company->company_gateways->whereIn('id', $payment_gateways); + $gateways = $this->company->company_gateways->whereIn('id', $company_gateways); } else { $gateways = $this->company->company_gateways; } diff --git a/app/PaymentDrivers/BasePaymentDriver.php b/app/PaymentDrivers/BasePaymentDriver.php index b77e087a78..8cf3ef1a56 100644 --- a/app/PaymentDrivers/BasePaymentDriver.php +++ b/app/PaymentDrivers/BasePaymentDriver.php @@ -143,20 +143,21 @@ class BasePaymentDriver */ public function refundPayment($payment, $amount = 0) { - if ($amount) { - $amount = min($amount, $payment->getCompletedAmount()); - } else { - $amount = $payment->getCompletedAmount(); - } if ($payment->is_deleted) { return false; } - if (! $amount) { + if (!$amount || $amount == 0) { return false; } + if ($amount) { + $amount = min($amount, $payment->getCompletedAmount()); + } else { + $amount = $payment->getCompletedAmount(); + } + if ($payment->type_id == Payment::TYPE_CREDIT_CARD) { return $payment->recordRefund($amount); } @@ -177,6 +178,15 @@ class BasePaymentDriver return false; } + protected function refundDetails($payment, $amount) + { + return [ + 'amount' => $amount, + 'transactionReference' => $payment->transaction_reference, + 'currency' => $payment->client->getCurrencyCode(), + ]; + } + protected function attemptVoidPayment($response, $payment, $amount) { // Partial refund not allowed for unsettled transactions @@ -226,7 +236,7 @@ class BasePaymentDriver acceptNotification() - convert an incoming request from an off-site gateway to a generic notification object for further processing */ - protected function paymentDetails($input) : array + protected function paymentDetails() : array { $data = [ 'currency' => $this->client->getCurrencyCode(), @@ -285,4 +295,58 @@ class BasePaymentDriver return $payment; } + + + + + + + + + + + + + + + + + + /////////////////////////////// V1 cut and paste + public function completeOffsitePurchase($input) + { + $this->input = $input; + $transRef = array_get($this->input, 'token'); + + if (method_exists($this->gateway(), 'completePurchase')) { + $details = $this->paymentDetails(); + $response = $this->gateway()->completePurchase($details)->send(); + $paymentRef = $response->getTransactionReference() ?: $transRef; + + if ($response->isCancelled()) { + return false; + } elseif (!$response->isSuccessful()) { + throw new \Exception($response->getMessage()); + } + } else { + $paymentRef = $transRef; + } + + //$this->updateClientFromOffsite($transRef, $paymentRef); + + // check invoice still has balance + if (!floatval($this->invoice()->balance)) { + throw new Exception(trans('texts.payment_error_code', ['code' => 'NB'])); + } + + // check this isn't a duplicate transaction reference + if (Payment::whereAccountId($this->invitation->account_id) + ->whereTransactionReference($paymentRef) + ->first() + ) { + throw new Exception(trans('texts.payment_error_code', ['code' => 'DT'])); + } + + return $this->createPayment($paymentRef); + } } diff --git a/app/PaymentDrivers/CheckoutPaymentDriver.php b/app/PaymentDrivers/CheckoutPaymentDriver.php new file mode 100644 index 0000000000..c685110a11 --- /dev/null +++ b/app/PaymentDrivers/CheckoutPaymentDriver.php @@ -0,0 +1,139 @@ + $invoice->getRequestedAmount(), + 'currency' => $invoice->getCurrencyCode(), + 'returnUrl' => $completeUrl, + 'cancelUrl' => $this->invitation->getLink(), + 'description' => trans('texts.' . $invoice->getEntityType()) . " {$invoice->number}", + 'transactionId' => $invoice->number, + 'transactionType' => 'Purchase', + 'clientIp' => Request::getClientIp(), + ]; + + */ +class CheckoutPaymentDriver extends BasePaymentDriver +{ + use SystemLogTrait; + + /* The company gateway instance*/ + protected $company_gateway; + + /* The Omnipay payment driver instance*/ + protected $gateway; + + /* The Invitation */ + protected $invitation; + + /* Gateway capabilities */ + protected $refundable = true; + + /* Token billing */ + protected $token_billing = true; + + /* Authorise payment methods */ + protected $can_authorise_credit_card = true; + + public function createTransactionToken($amount) + { + // if ($this->invoice()->getCurrencyCode() == 'BHD') { + // $amount = $this->invoice()->getRequestedAmount() / 10; + // } elseif ($this->invoice()->getCurrencyCode() == 'KWD') { + // $amount = $this->invoice()->getRequestedAmount() * 10; + // } elseif ($this->invoice()->getCurrencyCode() == 'OMR') { + // $amount = $this->invoice()->getRequestedAmount(); + // } else + // $amount = $this->invoice()->getRequestedAmount(); + + $response = $this->gateway()->purchase([ + 'amount' => $amount, + 'currency' => $this->client->getCurrencyCode(), + ])->send(); + + if ($response->isRedirect()) { + $token = $response->getTransactionReference(); + + session()->flash('transaction_reference', $token); + + + // On each request, session()->flash() || sesion('', value) || session[name] ||session->flash(key, value) + + return $token; + } + + return false; + } + + public function viewForType($gateway_type_id) + { + switch ($gateway_type_id) { + case GatewayType::CREDIT_CARD: + return 'gateways.checkout.credit_card'; + break; + case GatewayType::TOKEN: + break; + + default: + break; + } + } + + /** + * + * $data = [ + 'invoices' => $invoices, + 'amount' => $amount, + 'fee' => $gateway->calcGatewayFee($amount), + 'amount_with_fee' => $amount + $gateway->calcGatewayFee($amount), + 'token' => auth()->user()->client->gateway_token($gateway->id, $payment_method_id), + 'payment_method_id' => $payment_method_id, + 'hashed_ids' => explode(",", request()->input('hashed_ids')), + ]; + */ + public function processPaymentView(array $data) + { + $data['token'] = $this->createTransactionToken($data['amount']); + $data['gateway'] = $this->gateway(); + + return render($this->viewForType($data['payment_method_id']), $data); + } + + + + public function processPaymentResponse($request) + { + $data['token'] = session('transaction_reference'); + + $this->completeOffsitePurchase($data); + + } +} \ No newline at end of file diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index 4e34fe2eb4..4f119ceca8 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -13,7 +13,6 @@ namespace App\PaymentDrivers; use App\Events\Payment\PaymentWasCreated; use App\Factory\PaymentFactory; -//use App\Jobs\Invoice\UpdateInvoicePayment; use App\Jobs\Util\SystemLogger; use App\Models\ClientGatewayToken; use App\Models\GatewayType; diff --git a/composer.json b/composer.json index 345516d5c8..ac2d648730 100644 --- a/composer.json +++ b/composer.json @@ -22,6 +22,7 @@ "ext-json": "*", "asgrim/ofxparser": "^1.2", "ashallendesign/laravel-exchange-rates": "^2.1", + "beganovich/omnipay-checkout": "dev-master", "cleverit/ubl_invoice": "^1.3", "codedge/laravel-selfupdater": "~3.0", "composer/composer": "^1.10", @@ -53,7 +54,7 @@ "staudenmeir/eloquent-has-many-deep": "^1.11", "stripe/stripe-php": "^7.0", "superbalist/laravel-google-cloud-storage": "^2.2", - "turbo124/collector": "^0.2.0", + "turbo124/collector": "^0", "webpatser/laravel-countries": "dev-master#75992ad", "yajra/laravel-datatables-oracle": "~9.0" }, diff --git a/config/collector.php b/config/collector.php index 64f4ed04d7..7f4c5a1e28 100644 --- a/config/collector.php +++ b/config/collector.php @@ -5,7 +5,7 @@ return [ /** * Enable or disable the collector */ - 'enabled' => true, + 'enabled' => false, /** * The API endpoint for logs @@ -28,4 +28,15 @@ return [ */ 'cache_key' => 'collector', + /** + * Determines whether to log the + * host system variables using + * the built in metrics. + */ + 'system_logging' => [ + 'Turbo124\Collector\Jobs\System\CpuMetric', + 'Turbo124\Collector\Jobs\System\HdMetric', + 'Turbo124\Collector\Jobs\System\MemMetric', + ], + ]; \ No newline at end of file diff --git a/config/ninja.php b/config/ninja.php index 6ee84964ba..a528a13534 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -65,6 +65,7 @@ return [ 'password' => 'password', 'stripe' => env('STRIPE_KEYS', ''), 'paypal' => env('PAYPAL_KEYS', ''), + 'checkout' => env('CHECKOUT_KEYS',''), 'travis' => env('TRAVIS', false), 'test_email' => env('TEST_EMAIL', 'test@example.com'), ], diff --git a/database/seeds/RandomDataSeeder.php b/database/seeds/RandomDataSeeder.php index 7c10afb27e..20cb597eb9 100644 --- a/database/seeds/RandomDataSeeder.php +++ b/database/seeds/RandomDataSeeder.php @@ -275,5 +275,18 @@ class RandomDataSeeder extends Seeder $cg->config = encrypt(config('ninja.testvars.paypal')); $cg->save(); } + + if(config('ninja.testvars.checkout')) { + $cg = new CompanyGateway; + $cg->company_id = $company->id; + $cg->user_id = $user->id; + $cg->gateway_key = '3758e7f7c6f4cecf0f4f348b9a00f456'; + $cg->require_cvv = true; + $cg->show_billing_address = true; + $cg->show_shipping_address = true; + $cg->update_details = true; + $cg->config = encrypt(config('ninja.testvars.checkout')); + $cg->save(); + } } } diff --git a/resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php b/resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php new file mode 100644 index 0000000000..71419b67a9 --- /dev/null +++ b/resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php @@ -0,0 +1,42 @@ +@extends('portal.ninja2020.layout.app') + + +
+ +
+ + \ No newline at end of file