diff --git a/app/PaymentDrivers/Stripe/ACH.php b/app/PaymentDrivers/Stripe/ACH.php index 5167dc47744e..50e5f32c4c50 100644 --- a/app/PaymentDrivers/Stripe/ACH.php +++ b/app/PaymentDrivers/Stripe/ACH.php @@ -98,7 +98,7 @@ class ACH { $stripe_event = $event['data']['object']; - + $token = ClientGatewayToken::where('token', $stripe_event['id']) ->where('gateway_customer_reference', $stripe_event['customer']) ->first(); diff --git a/app/PaymentDrivers/Stripe/Jobs/PaymentIntentProcessingWebhook.php b/app/PaymentDrivers/Stripe/Jobs/PaymentIntentProcessingWebhook.php new file mode 100644 index 000000000000..0f89d5a8f905 --- /dev/null +++ b/app/PaymentDrivers/Stripe/Jobs/PaymentIntentProcessingWebhook.php @@ -0,0 +1,255 @@ +stripe_request = $stripe_request; + $this->company_key = $company_key; + $this->company_gateway_id = $company_gateway_id; + } + + /* Stub processing payment intents with a pending payment */ + public function handle() + { + + MultiDB::findAndSetDbByCompanyKey($this->company_key); + + $company = Company::where('company_key', $this->company_key)->first(); + + foreach ($this->stripe_request as $transaction) { + + if(array_key_exists('payment_intent', $transaction)) + { + $payment = Payment::query() + ->where('company_id', $company->id) + ->where('transaction_reference', $transaction['payment_intent']) + ->first(); + + } + else + { + $payment = Payment::query() + ->where('company_id', $company->id) + ->where('transaction_reference', $transaction['id']) + ->first(); + } + + if ($payment) { + $payment->status_id = Payment::STATUS_PENDING; + $payment->save(); + + $this->payment_completed = true; + } + } + + + if($this->payment_completed) + return; + + $company_gateway = CompanyGateway::find($this->company_gateway_id); + $stripe_driver = $company_gateway->driver()->init(); + + $charge_id = false; + + if(isset($this->stripe_request['object']['charges']) && optional($this->stripe_request['object']['charges']['data'][0])['id']) + $charge_id = $this->stripe_request['object']['charges']['data'][0]['id']; // API VERSION 2018 + elseif (isset($this->stripe_request['object']['latest_charge'])) + $charge_id = $this->stripe_request['object']['latest_charge']; // API VERSION 2022-11-15 + + + if(!$charge_id){ + nlog("could not resolve charge"); + return; + } + + $pi = \Stripe\PaymentIntent::retrieve($this->stripe_request['object']['id'], $stripe_driver->stripe_connect_auth); + + $charge = \Stripe\Charge::retrieve($charge_id, $stripe_driver->stripe_connect_auth); + + if(!$charge) + { + nlog("no charge found"); + nlog($this->stripe_request); + return; + } + + $company = Company::where('company_key', $this->company_key)->first(); + + $payment = Payment::query() + ->where('company_id', $company->id) + ->where('transaction_reference', $charge['id']) + ->first(); + + //return early + if($payment && $payment->status_id == Payment::STATUS_PENDING){ + nlog(" payment found and status correct - returning "); + return; + } + elseif($payment){ + $payment->status_id = Payment::STATUS_PENDING; + $payment->save(); + } + + $hash = isset($charge['metadata']['payment_hash']) ? $charge['metadata']['payment_hash'] : false; + + if(!$hash) + return; + + $payment_hash = PaymentHash::where('hash', $hash)->first(); + + if(!$payment_hash) + return; + + $stripe_driver->client = $payment_hash->fee_invoice->client; + + $meta = [ + 'gateway_type_id' => $pi['metadata']['gateway_type_id'], + 'transaction_reference' => $charge['id'], + 'customer' => $charge['customer'], + 'payment_method' => $charge['payment_method'], + 'card_details' => isset($charge['payment_method_details']['card']['brand']) ? $charge['payment_method_details']['card']['brand'] : PaymentType::CREDIT_CARD_OTHER + ]; + + SystemLogger::dispatch( + ['response' => $this->stripe_request, 'data' => []], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_SUCCESS, + SystemLog::TYPE_STRIPE, + null, + $company, + ); + + if(isset($pi['payment_method_types']) && in_array('us_bank_account', $pi['payment_method_types'])) + { + + $invoice = Invoice::with('client')->withTrashed()->find($payment_hash->fee_invoice_id); + $client = $invoice->client; + + if($invoice->is_deleted) + return; + + $this->updateAchPayment($payment_hash, $client, $meta); + } + + } + + private function updateAchPayment($payment_hash, $client, $meta) + { + $company_gateway = CompanyGateway::find($this->company_gateway_id); + $payment_method_type = $meta['gateway_type_id']; + $driver = $company_gateway->driver($client)->init()->setPaymentMethod($payment_method_type); + + $payment_hash->data = array_merge((array) $payment_hash->data, $this->stripe_request); + $payment_hash->save(); + $driver->setPaymentHash($payment_hash); + + $data = [ + 'payment_method' => $payment_hash->data->object->payment_method, + 'payment_type' => PaymentType::ACH, + 'amount' => $payment_hash->data->amount_with_fee, + 'transaction_reference' => $meta['transaction_reference'], + 'gateway_type_id' => GatewayType::BANK_TRANSFER, + ]; + + $payment = $driver->createPayment($data, Payment::STATUS_PENDING); + + SystemLogger::dispatch( + ['response' => $this->stripe_request, 'data' => $data], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_SUCCESS, + SystemLog::TYPE_STRIPE, + $client, + $client->company, + ); + + try { + + $customer = $driver->getCustomer($meta['customer']); + $method = $driver->getStripePaymentMethod($meta['payment_method']); + $payment_method = $meta['payment_method']; + + $token_exists = ClientGatewayToken::where([ + 'gateway_customer_reference' => $customer->id, + 'token' => $payment_method, + 'client_id' => $client->id, + 'company_id' => $client->company_id, + ])->exists(); + + /* Already exists return */ + if ($token_exists) { + return; + } + + $payment_meta = new \stdClass; + $payment_meta->brand = (string) \sprintf('%s (%s)', $method->us_bank_account['bank_name'], ctrans('texts.ach')); + $payment_meta->last4 = (string) $method->us_bank_account['last4']; + $payment_meta->type = GatewayType::BANK_TRANSFER; + $payment_meta->state = 'verified'; + + $data = [ + 'payment_meta' => $payment_meta, + 'token' => $payment_method, + 'payment_method_id' => GatewayType::BANK_TRANSFER, + ]; + + $additional_data = ['gateway_customer_reference' => $customer->id]; + + if ($customer->default_source === $method->id) { + $additional_data = ['gateway_customer_reference' => $customer->id, 'is_default' => 1]; + } + + $driver->storeGatewayToken($data, $additional_data); + + } + catch(\Exception $e){ + nlog("failed to import payment methods"); + nlog($e->getMessage()); + } + } + +} \ No newline at end of file diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index 7b127cfa3b50..9ca699c1f092 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -19,8 +19,8 @@ use App\Http\Requests\Payments\PaymentWebhookRequest; use App\Http\Requests\Request; use App\Jobs\Util\SystemLogger; use App\Models\ClientGatewayToken; -use App\Models\GatewayType; use App\Models\Country; +use App\Models\GatewayType; use App\Models\Payment; use App\Models\PaymentHash; use App\Models\PaymentType; @@ -29,8 +29,8 @@ use App\PaymentDrivers\Stripe\ACH; use App\PaymentDrivers\Stripe\ACSS; use App\PaymentDrivers\Stripe\Alipay; use App\PaymentDrivers\Stripe\ApplePay; -use App\PaymentDrivers\Stripe\Bancontact; use App\PaymentDrivers\Stripe\BECS; +use App\PaymentDrivers\Stripe\Bancontact; use App\PaymentDrivers\Stripe\BrowserPay; use App\PaymentDrivers\Stripe\Charge; use App\PaymentDrivers\Stripe\Connect\Verify; @@ -38,16 +38,17 @@ use App\PaymentDrivers\Stripe\CreditCard; use App\PaymentDrivers\Stripe\EPS; use App\PaymentDrivers\Stripe\FPX; use App\PaymentDrivers\Stripe\GIROPAY; -use App\PaymentDrivers\Stripe\Klarna; -use App\PaymentDrivers\Stripe\iDeal; use App\PaymentDrivers\Stripe\ImportCustomers; use App\PaymentDrivers\Stripe\Jobs\PaymentIntentFailureWebhook; +use App\PaymentDrivers\Stripe\Jobs\PaymentIntentProcessingWebhook; use App\PaymentDrivers\Stripe\Jobs\PaymentIntentWebhook; +use App\PaymentDrivers\Stripe\Klarna; use App\PaymentDrivers\Stripe\PRZELEWY24; use App\PaymentDrivers\Stripe\SEPA; use App\PaymentDrivers\Stripe\SOFORT; use App\PaymentDrivers\Stripe\UpdatePaymentMethods; use App\PaymentDrivers\Stripe\Utilities; +use App\PaymentDrivers\Stripe\iDeal; use App\Utils\Traits\MakesHash; use Exception; use Google\Service\ServiceConsumerManagement\CustomError; @@ -636,6 +637,12 @@ class StripePaymentDriver extends BaseDriver $ach->updateBankAccount($request->all()); } + if($request->type === 'payment_intent.processing') { + PaymentIntentProcessingWebhook::dispatch($request->data, $request->company_key, $this->company_gateway->id)->delay(now()->addSeconds(rand(5, 10))); + + return response()->json([], 200); + } + if ($request->type === 'payment_intent.succeeded') { PaymentIntentWebhook::dispatch($request->data, $request->company_key, $this->company_gateway->id)->delay(now()->addSeconds(rand(5, 10)));