mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Handling square webhook events
This commit is contained in:
parent
b35b8210ac
commit
5fb51656a6
@ -221,6 +221,22 @@ class CompanyGateway extends BaseModel
|
|||||||
{
|
{
|
||||||
$this->config = encrypt(json_encode($config));
|
$this->config = encrypt(json_encode($config));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setConfigField
|
||||||
|
*
|
||||||
|
* @param mixed $field
|
||||||
|
* @param mixed $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setConfigField($field, $value): void
|
||||||
|
{
|
||||||
|
$config = $this->getConfig();
|
||||||
|
$config->{$field} = $value;
|
||||||
|
|
||||||
|
$this->setConfig($config);
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return mixed
|
* @return mixed
|
||||||
|
@ -20,9 +20,11 @@ use App\Models\PaymentType;
|
|||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use App\Models\CompanyGateway;
|
use App\Models\CompanyGateway;
|
||||||
use App\Jobs\Util\SystemLogger;
|
use App\Jobs\Util\SystemLogger;
|
||||||
|
use App\Jobs\Mail\PaymentFailedMailer;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use App\PaymentDrivers\Stripe\Utilities;
|
use App\PaymentDrivers\Stripe\Utilities;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use App\PaymentDrivers\SquarePaymentDriver;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
@ -36,6 +38,10 @@ class SquareWebhook implements ShouldQueue
|
|||||||
|
|
||||||
public CompanyGateway $company_gateway;
|
public CompanyGateway $company_gateway;
|
||||||
|
|
||||||
|
public SquarePaymentDriver $driver;
|
||||||
|
|
||||||
|
public \Square\SquareClient $square;
|
||||||
|
|
||||||
private array $source_type = [
|
private array $source_type = [
|
||||||
'CARD' => PaymentType::CREDIT_CARD_OTHER,
|
'CARD' => PaymentType::CREDIT_CARD_OTHER,
|
||||||
'BANK_ACCOUNT' => PaymentType::ACH,
|
'BANK_ACCOUNT' => PaymentType::ACH,
|
||||||
@ -98,22 +104,56 @@ class SquareWebhook implements ShouldQueue
|
|||||||
|
|
||||||
MultiDB::findAndSetDbByCompanyKey($this->company_key);
|
MultiDB::findAndSetDbByCompanyKey($this->company_key);
|
||||||
|
|
||||||
$this->company_gateway = CompanyGateway::withTrashed()->find($this->company_gateway_id);
|
$this->company_gateway = CompanyGateway::queyr()->withTrashed()->find($this->company_gateway_id);
|
||||||
|
$this->driver = $this->company_gateway->driver()->init();
|
||||||
|
$this->square = $this->driver->square;
|
||||||
|
|
||||||
$status = $this->webhook_array['data']['object']['payment']['status'] ?? false;
|
$status = $this->webhook_array['data']['object']['payment']['status'] ?? false;
|
||||||
$payment_id = $this->webhook_array['data']['object']['payment']['id'] ?? null;
|
$payment_id = $this->webhook_array['data']['object']['payment']['id'] ?? null;
|
||||||
|
|
||||||
match($status){
|
match($status){
|
||||||
'APPROVED' => $payment_status = Payment::STATUS_COMPLETED,
|
'APPROVED' => $payment_status = false,
|
||||||
'COMPLETED' => $payment_status = Payment::STATUS_COMPLETED,
|
'COMPLETED' => $payment_status = Payment::STATUS_COMPLETED,
|
||||||
'PENDING' => $payment_status = Payment::STATUS_PENDING,
|
'PENDING' => $payment_status = Payment::STATUS_PENDING,
|
||||||
'CANCELED' => $payment_status = Payment::STATUS_CANCELLED,
|
'CANCELED' => $payment_status = Payment::STATUS_CANCELLED,
|
||||||
'FAILED' => $payment_status = Payment::STATUS_FAILED,
|
'FAILED' => $payment_status = Payment::STATUS_FAILED,
|
||||||
default => $payment_status = Payment::STATUS_FAILED,
|
default => $payment_status = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(!$payment_status){
|
||||||
|
nlog("Square Webhook - Payment Status Not Found or not worthy of processing");
|
||||||
|
nlog($this->webhook_array);
|
||||||
|
}
|
||||||
|
|
||||||
$payment = $this->retrieveOrCreatePayment($payment_id, $payment_status);
|
$payment = $this->retrieveOrCreatePayment($payment_id, $payment_status);
|
||||||
|
|
||||||
|
/** If the status was pending and now is reporting as Failed / Cancelled - process failure path */
|
||||||
|
if($payment->status_id == Payment::STATUS_PENDING && in_array($payment_status, [Payment::STATUS_CANCELLED, Payment::STATUS_FAILED])){
|
||||||
|
$payment->service()->deletePayment();
|
||||||
|
|
||||||
|
|
||||||
|
if ($this->driver->payment_hash) {
|
||||||
|
$error = ctrans('texts.client_payment_failure_body', [
|
||||||
|
'invoice' => implode(',', $payment->invoices->pluck('number')->toArray()),
|
||||||
|
'amount' => array_sum(array_column($this->driver->payment_hash->invoices(), 'amount')) + $this->driver->payment_hash->fee_total,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$error = 'Payment for '.$payment->client->present()->name()." for {$payment->amount} failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
PaymentFailedMailer::dispatch(
|
||||||
|
$this->driver->payment_hash,
|
||||||
|
$this->driver->client->company,
|
||||||
|
$this->driver->client,
|
||||||
|
$error
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
elseif($payment->status_id == Payment::STATUS_PENDING && in_array($payment_status, [Payment::STATUS_COMPLETED, Payment::STATUS_COMPLETED])){
|
||||||
|
$payment->status_id = Payment::STATUS_COMPLETED;
|
||||||
|
$payment->save();
|
||||||
|
}
|
||||||
|
|
||||||
//toggle pending to completed.
|
//toggle pending to completed.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,8 +165,8 @@ class SquareWebhook implements ShouldQueue
|
|||||||
if($payment)
|
if($payment)
|
||||||
return $payment;
|
return $payment;
|
||||||
|
|
||||||
$square = $this->company_gateway->driver()->init();
|
/** Handles the edge case where for some reason the payment has not yet been recorded in Invoice Ninja */
|
||||||
$apiResponse = $square->getPaymentsApi()->getPayment($payment_reference);
|
$apiResponse = $this->square->getPaymentsApi()->getPayment($payment_reference);
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// "payment": {
|
// "payment": {
|
||||||
@ -201,13 +241,13 @@ class SquareWebhook implements ShouldQueue
|
|||||||
|
|
||||||
$payment_hash_id = $apiResponse->getPayment()->getReferenceId() ?? false;
|
$payment_hash_id = $apiResponse->getPayment()->getReferenceId() ?? false;
|
||||||
$square_payment = $apiResponse->getPayment()->jsonSerialize();
|
$square_payment = $apiResponse->getPayment()->jsonSerialize();
|
||||||
$payment_hash = PaymentHash::where('hash',$payment_hash_id)->first();
|
$payment_hash = PaymentHash::where('hash', $payment_hash_id)->firstOrFail();
|
||||||
|
|
||||||
$payment_hash->data = array_merge((array) $payment_hash->data, (array)$square_payment);
|
$payment_hash->data = array_merge((array) $payment_hash->data, (array)$square_payment);
|
||||||
$payment_hash->save();
|
$payment_hash->save();
|
||||||
|
|
||||||
$square->setPaymentHash($payment_hash);
|
$this->driver->setPaymentHash($payment_hash);
|
||||||
$square->setClient($payment_hash->fee_invoice->client);
|
$this->driver->setClient($payment_hash->fee_invoice->client);
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'payment_type' => $this->source_type[$square_payment->source_type],
|
'payment_type' => $this->source_type[$square_payment->source_type],
|
||||||
@ -216,22 +256,23 @@ class SquareWebhook implements ShouldQueue
|
|||||||
'gateway_type_id' => GatewayType::BANK_TRANSFER,
|
'gateway_type_id' => GatewayType::BANK_TRANSFER,
|
||||||
];
|
];
|
||||||
|
|
||||||
$payment = $square->createPayment($data, $payment_status);
|
$payment = $this->driver->createPayment($data, $payment_status);
|
||||||
|
|
||||||
SystemLogger::dispatch(
|
SystemLogger::dispatch(
|
||||||
['response' => $this->webhook_array, 'data' => $square_payment],
|
['response' => $this->webhook_array, 'data' => $square_payment],
|
||||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||||
SystemLog::TYPE_SQUARE,
|
SystemLog::TYPE_SQUARE,
|
||||||
$square->client,
|
$this->driver->client,
|
||||||
$square->client->company,
|
$this->driver->client->company,
|
||||||
);
|
);
|
||||||
|
|
||||||
return $payment;
|
return $payment;
|
||||||
|
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
nlog("Square Webhook Payment not found: $payment_reference");
|
nlog("Square Webhook - Payment not found: $payment_reference");
|
||||||
|
nlog($apiResponse->getErrors());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -25,6 +25,7 @@ use App\Models\ClientGatewayToken;
|
|||||||
use Square\Models\WebhookSubscription;
|
use Square\Models\WebhookSubscription;
|
||||||
use App\PaymentDrivers\Square\CreditCard;
|
use App\PaymentDrivers\Square\CreditCard;
|
||||||
use App\PaymentDrivers\Square\SquareWebhook;
|
use App\PaymentDrivers\Square\SquareWebhook;
|
||||||
|
use Square\Models\ListWebhookSubscriptionsRequest;
|
||||||
use Square\Models\CreateWebhookSubscriptionRequest;
|
use Square\Models\CreateWebhookSubscriptionRequest;
|
||||||
use App\Http\Requests\Payments\PaymentWebhookRequest;
|
use App\Http\Requests\Payments\PaymentWebhookRequest;
|
||||||
use Square\Models\Builders\RefundPaymentRequestBuilder;
|
use Square\Models\Builders\RefundPaymentRequestBuilder;
|
||||||
@ -197,9 +198,9 @@ class SquarePaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
SystemLogger::dispatch(
|
SystemLogger::dispatch(
|
||||||
[
|
[
|
||||||
'server_response' => $data,
|
'server_response' => $data,
|
||||||
'data' => request()->all()
|
'data' => request()->all()
|
||||||
],
|
],
|
||||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||||
SystemLog::TYPE_SQUARE,
|
SystemLog::TYPE_SQUARE,
|
||||||
@ -285,15 +286,64 @@ class SquarePaymentDriver extends BaseDriver
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createWebhooks()
|
public function checkWebhooks(): bool
|
||||||
{
|
{
|
||||||
$this->init();
|
$this->init();
|
||||||
|
|
||||||
|
$api_response = $this->square->getWebhookSubscriptionsApi()->listWebhookSubscriptions();
|
||||||
|
|
||||||
|
if ($api_response->isSuccess()) {
|
||||||
|
|
||||||
|
//array of WebhookSubscription objects
|
||||||
|
foreach($api_response->getResult()->getSubscriptions() as $subscription)
|
||||||
|
{
|
||||||
|
if($subscription->getName() == 'Invoice_Ninja_Webhook_Subscription')
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$errors = $api_response->getErrors();
|
||||||
|
nlog($errors);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// {
|
||||||
|
// "subscription": {
|
||||||
|
// "id": "wbhk_b35f6b3145074cf9ad513610786c19d5",
|
||||||
|
// "name": "Example Webhook Subscription",
|
||||||
|
// "enabled": true,
|
||||||
|
// "event_types": [
|
||||||
|
// "payment.created",
|
||||||
|
// "order.updated",
|
||||||
|
// "invoice.created"
|
||||||
|
// ],
|
||||||
|
// "notification_url": "https://example-webhook-url.com",
|
||||||
|
// "api_version": "2021-12-15",
|
||||||
|
// "signature_key": "1k9bIJKCeTmSQwyagtNRLg",
|
||||||
|
// "created_at": "2022-08-17 23:29:48 +0000 UTC",
|
||||||
|
// "updated_at": "2022-08-17 23:29:48 +0000 UTC"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public function createWebhooks(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
if($this->checkWebhooks())
|
||||||
|
return;
|
||||||
|
|
||||||
|
$this->init();
|
||||||
|
|
||||||
$event_types = ['payment.created', 'payment.updated'];
|
$event_types = ['payment.created', 'payment.updated'];
|
||||||
$subscription = new WebhookSubscription();
|
$subscription = new WebhookSubscription();
|
||||||
$subscription->setName('Invoice_Ninja_Webhook_Subscription');
|
$subscription->setName('Invoice_Ninja_Webhook_Subscription');
|
||||||
$subscription->setEventTypes($event_types);
|
$subscription->setEventTypes($event_types);
|
||||||
$subscription->setNotificationUrl($this->company_gateway->webhookUrl());
|
|
||||||
|
$subscription->setNotificationUrl('https://invoicing.co');
|
||||||
|
|
||||||
|
// $subscription->setNotificationUrl($this->company_gateway->webhookUrl());
|
||||||
// $subscription->setApiVersion('2021-12-15');
|
// $subscription->setApiVersion('2021-12-15');
|
||||||
|
|
||||||
$body = new CreateWebhookSubscriptionRequest($subscription);
|
$body = new CreateWebhookSubscriptionRequest($subscription);
|
||||||
@ -301,28 +351,15 @@ class SquarePaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
$api_response = $this->square->getWebhookSubscriptionsApi()->createWebhookSubscription($body);
|
$api_response = $this->square->getWebhookSubscriptionsApi()->createWebhookSubscription($body);
|
||||||
|
|
||||||
// {
|
|
||||||
// "subscription": {
|
|
||||||
// "id": "wbhk_b35f6b3145074cf9ad513610786c19d5",
|
|
||||||
// "name": "Example Webhook Subscription",
|
|
||||||
// "enabled": true,
|
|
||||||
// "event_types": [
|
|
||||||
// "payment.created",
|
|
||||||
// "order.updated",
|
|
||||||
// "invoice.created"
|
|
||||||
// ],
|
|
||||||
// "notification_url": "https://example-webhook-url.com",
|
|
||||||
// "api_version": "2021-12-15",
|
|
||||||
// "signature_key": "1k9bIJKCeTmSQwyagtNRLg",
|
|
||||||
// "created_at": "2022-08-17 23:29:48 +0000 UTC",
|
|
||||||
// "updated_at": "2022-08-17 23:29:48 +0000 UTC"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
if ($api_response->isSuccess()) {
|
if ($api_response->isSuccess()) {
|
||||||
$result = $api_response->getResult();
|
$subscription = $api_response->getResult()->getSubscription();
|
||||||
|
$signatureKey = $subscription->getSignatureKey();
|
||||||
|
|
||||||
|
$this->company_gateway->setConfigField('signatureKey', $signatureKey);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$errors = $api_response->getErrors();
|
$errors = $api_response->getErrors();
|
||||||
|
nlog($errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user