mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 12:27:31 -04:00 
			
		
		
		
	Update payment methods for Stripe
This commit is contained in:
		
							parent
							
								
									6f06e3b268
								
							
						
					
					
						commit
						0347ca00f5
					
				
							
								
								
									
										35
									
								
								app/Http/Controllers/StripeController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								app/Http/Controllers/StripeController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://opensource.org/licenses/AAL | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\Http\Controllers; | ||||||
|  | 
 | ||||||
|  | use App\Jobs\Util\StripeUpdatePaymentMethods; | ||||||
|  | 
 | ||||||
|  | class StripeController extends BaseController | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | 	public function update() | ||||||
|  | 	{ | ||||||
|  | 		if(auth()->user()->isAdmin()) | ||||||
|  | 		{ | ||||||
|  | 
 | ||||||
|  | 			StripeUpdatePaymentMethods::dispatch(auth()->user()->getCompany()); | ||||||
|  | 
 | ||||||
|  | 			return response()->json(['message' => 'Processing'], 403); | ||||||
|  | 
 | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		 | ||||||
|  | 		return response()->json(['message' => 'Unauthorized'], 403); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										68
									
								
								app/Jobs/Util/StripeUpdatePaymentMethods.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								app/Jobs/Util/StripeUpdatePaymentMethods.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://opensource.org/licenses/AAL | ||||||
|  |  */ | ||||||
|  | namespace App\Jobs\Util; | ||||||
|  | 
 | ||||||
|  | use App\Libraries\MultiDB; | ||||||
|  | use App\Models\Client; | ||||||
|  | use App\Models\CompanyGateway; | ||||||
|  | use Illuminate\Bus\Queueable; | ||||||
|  | use Illuminate\Contracts\Queue\ShouldQueue; | ||||||
|  | use Illuminate\Foundation\Bus\Dispatchable; | ||||||
|  | use Illuminate\Queue\InteractsWithQueue; | ||||||
|  | use Illuminate\Queue\SerializesModels; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class StripeUpdatePaymentMethods implements ShouldQueue | ||||||
|  | { | ||||||
|  |     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||||||
|  | 
 | ||||||
|  |     public $company; | ||||||
|  | 
 | ||||||
|  |     private $stripe_keys = ['d14dd26a47cecc30fdd65700bfb67b34', 'd14dd26a37cecc30fdd65700bfb55b23']; | ||||||
|  |     /** | ||||||
|  |      * Create a new job instance. | ||||||
|  |      * | ||||||
|  |      * @param $event_id | ||||||
|  |      * @param $entity | ||||||
|  |      */ | ||||||
|  |     public function __construct($company) | ||||||
|  |     { | ||||||
|  |         $this->company = $company; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Execute the job. | ||||||
|  |      * | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public function handle() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |     	MultiDB::setDb($this->company->db); | ||||||
|  | 
 | ||||||
|  |     	$cgs = CompanyGateway::where('company_id', $this->company->id) | ||||||
|  |     						->whereIn('gateway_key', $this->stripe_keys) | ||||||
|  |     						->get(); | ||||||
|  | 
 | ||||||
|  | 		$cgs->each(function ($company_gateway){ | ||||||
|  | 
 | ||||||
|  | 			$company_gateway->driver(new Client)->updateAllPaymentMethods(); | ||||||
|  | 
 | ||||||
|  | 		}); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function failed($exception) | ||||||
|  |     { | ||||||
|  |     	nlog("Stripe update payment methods exception"); | ||||||
|  |         nlog($exception->getMessage()); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										168
									
								
								app/PaymentDrivers/Stripe/UpdatePaymentMethods.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								app/PaymentDrivers/Stripe/UpdatePaymentMethods.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,168 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://opensource.org/licenses/AAL | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\PaymentDrivers\Stripe; | ||||||
|  | 
 | ||||||
|  | use App\Factory\ClientGatewayTokenFactory; | ||||||
|  | use App\Models\ClientGatewayToken; | ||||||
|  | use App\Models\GatewayType; | ||||||
|  | use App\PaymentDrivers\StripePaymentDriver; | ||||||
|  | use App\Utils\Traits\MakesHash; | ||||||
|  | use Stripe\Customer; | ||||||
|  | use Stripe\PaymentMethod; | ||||||
|  | 
 | ||||||
|  | class UpdatePaymentMethods | ||||||
|  | { | ||||||
|  |     use MakesHash; | ||||||
|  | 
 | ||||||
|  |     /** @var StripePaymentDriver */ | ||||||
|  |     public $stripe; | ||||||
|  | 
 | ||||||
|  |     public function __construct(StripePaymentDriver $stripe) | ||||||
|  |     { | ||||||
|  |         $this->stripe = $stripe; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function run() | ||||||
|  |     { | ||||||
|  |         $this->stripe->init(); | ||||||
|  | 
 | ||||||
|  |         $this->stripe | ||||||
|  |              ->company_gateway | ||||||
|  |              ->client_gateway_tokens | ||||||
|  |              ->each(function ($token){ | ||||||
|  | 
 | ||||||
|  |                 $card_methods = PaymentMethod::all([ | ||||||
|  |                     'customer' => $token->gateway_customer_reference, | ||||||
|  |                     'type' => 'card', | ||||||
|  |                     ], | ||||||
|  |                      $this->stripe->stripe_connect_auth); | ||||||
|  | 
 | ||||||
|  |                 foreach($card_methods as $method)  | ||||||
|  |                 { | ||||||
|  |                     $this->addOrUpdateCard($method, $token, GatewayType::CREDIT_CARD); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 $alipay_methods = PaymentMethod::all([ | ||||||
|  |                     'customer' => $token->gateway_customer_reference, | ||||||
|  |                     'type' => 'alipay', | ||||||
|  |                     ], | ||||||
|  |                      $this->stripe->stripe_connect_auth); | ||||||
|  | 
 | ||||||
|  |                 foreach($alipay_methods as $method)  | ||||||
|  |                 { | ||||||
|  |                     $this->addOrUpdateCard($method, $token, GatewayType::ALIPAY); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 $sofort_methods = PaymentMethod::all([ | ||||||
|  |                     'customer' => $token->gateway_customer_reference, | ||||||
|  |                     'type' => 'sofort', | ||||||
|  |                     ], | ||||||
|  |                      $this->stripe->stripe_connect_auth); | ||||||
|  | 
 | ||||||
|  |                 foreach($alipay_methods as $method)  | ||||||
|  |                 { | ||||||
|  |                     $this->addOrUpdateCard($method, $token, GatewayType::SOFORT); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 $bank_accounts = Customer::allSources( | ||||||
|  |                     $token->gateway_customer_reference, | ||||||
|  |                     ['object' => 'bank_account', 'limit' => 300] | ||||||
|  |                 ); | ||||||
|  | 
 | ||||||
|  |                 foreach($bank_accounts as $bank_account) | ||||||
|  |                 { | ||||||
|  |                     $this->addOrUpdateBankAccount($bank_account, $token); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function addOrUpdateBankAccount($bank_account, ClientGatewayToken $token) | ||||||
|  |     { | ||||||
|  |         $token_exists = ClientGatewayToken::where([ | ||||||
|  |             'gateway_customer_reference' => $token->gateway_customer_reference, | ||||||
|  |             'token' => $bank_account->id, | ||||||
|  |         ])->exists(); | ||||||
|  | 
 | ||||||
|  |         /* Already exists return */ | ||||||
|  |         if($token_exists) | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         $cgt = ClientGatewayTokenFactory::create($token->company_id); | ||||||
|  |         $cgt->client_id = $token->client_id; | ||||||
|  |         $cgt->token = $bank_account->id; | ||||||
|  |         $cgt->gateway_customer_reference = $token->gateway_customer_reference; | ||||||
|  |         $cgt->company_gateway_id = $token->company_gateway_id; | ||||||
|  |         $cgt->gateway_type_id = GatewayType::BANK_TRANSFER | ||||||
|  |         $cgt->meta = new \stdClass; | ||||||
|  |         $cgt->routing_number = $bank_account->routing_number; | ||||||
|  |         $cgt->save(); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function addOrUpdateCard(PaymentMethod $method, ClientGatewayToken $token, GatewayType $type_id) | ||||||
|  |     { | ||||||
|  |          | ||||||
|  |         $token_exists = ClientGatewayToken::where([ | ||||||
|  |             'gateway_customer_reference' => $token->gateway_customer_reference, | ||||||
|  |             'token' => $method->id, | ||||||
|  |         ])->exists(); | ||||||
|  | 
 | ||||||
|  |         /* Already exists return */ | ||||||
|  |         if($token_exists) | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         /* Ignore Expired cards */ | ||||||
|  |         if($method->card->exp_year <= date('Y') && $method->card->exp_month < date('m')) | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         $cgt = ClientGatewayTokenFactory::create($token->company_id); | ||||||
|  |         $cgt->client_id = $token->client_id; | ||||||
|  |         $cgt->token = $method->id; | ||||||
|  |         $cgt->gateway_customer_reference = $token->gateway_customer_reference; | ||||||
|  |         $cgt->company_gateway_id = $token->company_gateway_id; | ||||||
|  |         $cgt->gateway_type_id = $type_id; | ||||||
|  |         $cgt->meta = $this->buildPaymentMethodMeta($method, $type_id); | ||||||
|  |         $cgt->save(); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function buildPaymentMethodMeta(PaymentMethod $method, GatewayType $type_id) | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         switch ($type_id) { | ||||||
|  |             case GatewayType::CREDIT_CARD: | ||||||
|  | 
 | ||||||
|  |                 $payment_meta = new \stdClass; | ||||||
|  |                 $payment_meta->exp_month = (string) $method->card->exp_month; | ||||||
|  |                 $payment_meta->exp_year = (string) $method->card->exp_year; | ||||||
|  |                 $payment_meta->brand = (string) $method->card->brand; | ||||||
|  |                 $payment_meta->last4 = (string) $method->card->last4; | ||||||
|  |                 $payment_meta->type = GatewayType::CREDIT_CARD; | ||||||
|  |                 return $payment_meta; | ||||||
|  | 
 | ||||||
|  |                 break; | ||||||
|  |              | ||||||
|  |             case GatewayType::ALIPAY: | ||||||
|  |             case GatewayType::SOFORT: | ||||||
|  | 
 | ||||||
|  |                 return new \stdClass; | ||||||
|  | 
 | ||||||
|  |             default: | ||||||
|  |                  | ||||||
|  | 
 | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -26,6 +26,7 @@ use App\PaymentDrivers\Stripe\Alipay; | |||||||
| use App\PaymentDrivers\Stripe\Charge; | use App\PaymentDrivers\Stripe\Charge; | ||||||
| use App\PaymentDrivers\Stripe\CreditCard; | use App\PaymentDrivers\Stripe\CreditCard; | ||||||
| use App\PaymentDrivers\Stripe\SOFORT; | use App\PaymentDrivers\Stripe\SOFORT; | ||||||
|  | use App\PaymentDrivers\Stripe\UpdatePaymentMethods; | ||||||
| use App\PaymentDrivers\Stripe\Utilities; | use App\PaymentDrivers\Stripe\Utilities; | ||||||
| use App\Utils\Traits\MakesHash; | use App\Utils\Traits\MakesHash; | ||||||
| use Exception; | use Exception; | ||||||
| @ -493,4 +494,29 @@ class StripePaymentDriver extends BaseDriver | |||||||
| 
 | 
 | ||||||
|         return Account::all(); |         return Account::all(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Pull all client payment methods and update | ||||||
|  |      * the respective tokens in the system. | ||||||
|  |      *      | ||||||
|  |      */ | ||||||
|  |     public function updateAllPaymentMethods() | ||||||
|  |     { | ||||||
|  |         return (new UpdatePaymentMethods($this))->run(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Imports stripe customers and their payment methods | ||||||
|  |      * Matches users in the system based on the $match_on_record  | ||||||
|  |      * ie. email | ||||||
|  |      *      | ||||||
|  |      * Phone | ||||||
|  |      * Email | ||||||
|  |      */ | ||||||
|  |     public function importAndUpdateCustomers() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         //match clients based on the gateway_customer_reference column
 | ||||||
|  | 
 | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -183,6 +183,8 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a | |||||||
|     // Route::post('hooks', 'SubscriptionController@subscribe')->name('hooks.subscribe');
 |     // Route::post('hooks', 'SubscriptionController@subscribe')->name('hooks.subscribe');
 | ||||||
|     // Route::delete('hooks/{subscription_id}', 'SubscriptionController@unsubscribe')->name('hooks.unsubscribe');
 |     // Route::delete('hooks/{subscription_id}', 'SubscriptionController@unsubscribe')->name('hooks.unsubscribe');
 | ||||||
| 
 | 
 | ||||||
|  |     Route::post('stripe/update_payment_methods', 'StripeController@update')->middleware('password_protected')->name('stripe.update'); | ||||||
|  | 
 | ||||||
|     Route::resource('subscriptions', 'SubscriptionController'); |     Route::resource('subscriptions', 'SubscriptionController'); | ||||||
|     Route::post('subscriptions/bulk', 'SubscriptionController@bulk')->name('subscriptions.bulk'); |     Route::post('subscriptions/bulk', 'SubscriptionController@bulk')->name('subscriptions.bulk'); | ||||||
| 
 | 
 | ||||||
| @ -193,9 +195,7 @@ Route::match(['get', 'post'], 'payment_webhook/{company_key}/{company_gateway_id | |||||||
|     ->name('payment_webhook'); |     ->name('payment_webhook'); | ||||||
| 
 | 
 | ||||||
| Route::post('api/v1/postmark_webhook', 'PostMarkController@webhook'); | Route::post('api/v1/postmark_webhook', 'PostMarkController@webhook'); | ||||||
| 
 |  | ||||||
| Route::get('token_hash_router', 'OneTimeTokenController@router'); | Route::get('token_hash_router', 'OneTimeTokenController@router'); | ||||||
| 
 |  | ||||||
| Route::get('webcron', 'WebCronController@index'); | Route::get('webcron', 'WebCronController@index'); | ||||||
| 
 | 
 | ||||||
| Route::fallback('BaseController@notFound'); | Route::fallback('BaseController@notFound'); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user