mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Upgrades for Square
This commit is contained in:
parent
5bb40840d9
commit
cb9c3a0a77
@ -17,7 +17,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
* App\Models\PaymentHash
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $hash
|
||||
* @property string $hash 32 char length AlphaNum
|
||||
* @property float $fee_total
|
||||
* @property int|null $fee_invoice_id
|
||||
* @property \stdClass $data
|
||||
@ -41,6 +41,7 @@ class PaymentHash extends Model
|
||||
/**
|
||||
* @class \App\Models\PaymentHash $this
|
||||
* @property \App\Models\PaymentHash $data
|
||||
* @property \App\Modes\PaymentHash $hash 32 char length AlphaNum
|
||||
* @class \stdClass $data
|
||||
* @property string $raw_value
|
||||
*/
|
||||
|
@ -263,6 +263,8 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
public function setClient(Client $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
|
||||
return $this;
|
||||
}
|
||||
/************************** Helper methods *************************************/
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
namespace App\PaymentDrivers\Square;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\SystemLog;
|
||||
use Illuminate\View\View;
|
||||
@ -107,6 +108,14 @@ class CreditCard implements MethodInterface
|
||||
$token = $cgt->token;
|
||||
}
|
||||
|
||||
$invoice = Invoice::query()->whereIn('id', $this->transformKeys(array_column($this->square_driver->payment_hash->invoices(), 'invoice_id')))->withTrashed()->first();
|
||||
|
||||
if ($invoice) {
|
||||
$description = "Invoice {$invoice->number} for {$amount} for client {$this->square_driver->client->present()->name()}";
|
||||
} else {
|
||||
$description = "Payment with no invoice for amount {$amount} for client {$this->square_driver->client->present()->name()}";
|
||||
}
|
||||
|
||||
$amount_money = new \Square\Models\Money();
|
||||
$amount_money->setAmount($amount);
|
||||
$amount_money->setCurrency($this->square_driver->client->currency()->code);
|
||||
@ -116,8 +125,9 @@ class CreditCard implements MethodInterface
|
||||
|
||||
$body->setAutocomplete(true);
|
||||
$body->setLocationId($this->square_driver->company_gateway->getConfigField('locationId'));
|
||||
$body->setReferenceId(Str::random(16));
|
||||
|
||||
$body->setReferenceId($this->square_driver->payment_hash->hash);
|
||||
$body->setNote($description);
|
||||
|
||||
if ($request->shouldUseToken()) {
|
||||
$body->setCustomerId($cgt->gateway_customer_reference);
|
||||
}elseif ($request->has('verificationToken') && $request->input('verificationToken')) {
|
||||
|
@ -36,10 +36,62 @@ class SquareWebhook implements ShouldQueue
|
||||
|
||||
public CompanyGateway $company_gateway;
|
||||
|
||||
private array $source_type = [
|
||||
'CARD' => PaymentType::CREDIT_CARD_OTHER,
|
||||
'BANK_ACCOUNT' => PaymentType::ACH,
|
||||
'WALLET' => PaymentType::CREDIT_CARD_OTHER,
|
||||
'BUY_NOW_PAY_LATER' => PaymentType::CREDIT_CARD_OTHER,
|
||||
'SQUARE_ACCOUNT' => PaymentType::CREDIT_CARD_OTHER,
|
||||
'CASH' => PaymentType::CASH,
|
||||
'EXTERNAL' =>PaymentType::CREDIT_CARD_OTHER
|
||||
];
|
||||
|
||||
public function __construct(public array $webhook_array, public string $company_key, public int $company_gateway_id)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {
|
||||
* "merchant_id": "6SSW7HV8K2ST5",
|
||||
* "type": "payment.created",
|
||||
* "event_id": "13b867cf-db3d-4b1c-90b6-2f32a9d78124",
|
||||
* "created_at": "2020-02-06T21:27:30.792Z",
|
||||
* "data": {
|
||||
* "type": "payment",
|
||||
* "id": "KkAkhdMsgzn59SM8A89WgKwekxLZY",
|
||||
* "object": {
|
||||
* "payment": {
|
||||
* "id": "hYy9pRFVxpDsO1FB05SunFWUe9JZY",
|
||||
* "created_at": "2020-11-22T21:16:51.086Z",
|
||||
* "updated_at": "2020-11-22T21:16:51.198Z",
|
||||
* "amount_money": {
|
||||
* "amount": 100,
|
||||
* "currency": "USD"
|
||||
* },
|
||||
* "status": "APPROVED",
|
||||
* "delay_duration": "PT168H",
|
||||
* "source_type": "CARD",
|
||||
* "card_details": {
|
||||
* "status": "AUTHORIZED",
|
||||
* "card": {
|
||||
* "card_brand": "MASTERCARD",
|
||||
* "last_4": "9029",
|
||||
* "exp_month": 11,
|
||||
* "exp_year": 2022,
|
||||
* "fingerprint": "sq-1-Tvruf3vPQxlvI6n0IcKYfBukrcv6IqWr8UyBdViWXU2yzGn5VMJvrsHMKpINMhPmVg",
|
||||
* "card_type": "CREDIT",
|
||||
* "prepaid_type": "NOT_PREPAID",
|
||||
* "bin": "540988"
|
||||
* },
|
||||
* "entry_method": "KEYED",
|
||||
* "cvv_status": "CVV_ACCEPTED",
|
||||
* "avs_status": "AVS_ACCEPTED",
|
||||
* "statement_description": "SQ *DEFAULT TEST ACCOUNT",
|
||||
* "card_payment_timeline": {
|
||||
* "authorized_at": "2020-11-22T21:16:51.198Z"
|
||||
*
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
nlog("Square Webhook");
|
||||
@ -48,6 +100,25 @@ class SquareWebhook implements ShouldQueue
|
||||
|
||||
$this->company_gateway = CompanyGateway::withTrashed()->find($this->company_gateway_id);
|
||||
|
||||
$status = $this->webhook_array['data']['object']['payment']['status'] ?? false;
|
||||
$payment_id = $this->webhook_array['data']['object']['payment']['id'] ?? null;
|
||||
|
||||
$payment = $this->retrieveOrCreatePayment($payment_id);
|
||||
|
||||
// APPROVED, PENDING, COMPLETED, CANCELED, or FAILED
|
||||
if(in_array($status, ['APPROVED', 'COMPLETED'])){
|
||||
|
||||
}
|
||||
elseif(in_array($status, ['PENDING'])){
|
||||
|
||||
}
|
||||
elseif(in_array($status, ['CANCELED', 'FAILED'])){
|
||||
|
||||
}
|
||||
else{
|
||||
nlog("Square Webhook status not handled: $status");
|
||||
}
|
||||
|
||||
// if(!isset($this->webhook_array['type']))
|
||||
// nlog("Checkout Webhook type not set");
|
||||
|
||||
@ -56,4 +127,122 @@ class SquareWebhook implements ShouldQueue
|
||||
// };
|
||||
|
||||
}
|
||||
|
||||
private function retrieveOrCreatePayment(?string $payment_reference): \App\Models\Payment
|
||||
{
|
||||
|
||||
$payment = Payment::withTrashed()->where('transaction_reference', $payment_reference)->first();
|
||||
|
||||
if($payment)
|
||||
return $payment;
|
||||
|
||||
$square = $this->company_gateway->driver()->init();
|
||||
$apiResponse = $square->getPaymentsApi()->getPayment($payment_reference);
|
||||
|
||||
// {
|
||||
// "payment": {
|
||||
// "id": "bP9mAsEMYPUGjjGNaNO5ZDVyLhSZY",
|
||||
// "created_at": "2021-10-13T19:34:33.524Z",
|
||||
// "updated_at": "2021-10-13T19:34:34.339Z",
|
||||
// "amount_money": {
|
||||
// "amount": 555,
|
||||
// "currency": "USD"
|
||||
// },
|
||||
// "status": "COMPLETED",
|
||||
// "delay_duration": "PT168H",
|
||||
// "source_type": "CARD",
|
||||
// "card_details": {
|
||||
// "status": "CAPTURED",
|
||||
// "card": {
|
||||
// "card_brand": "VISA",
|
||||
// "last_4": "1111",
|
||||
// "exp_month": 11,
|
||||
// "exp_year": 2022,
|
||||
// "fingerprint": "sq-1-Hxim77tbdcbGejOejnoAklBVJed2YFLTmirfl8Q5XZzObTc8qY_U8RkwzoNL8dCEcQ",
|
||||
// "card_type": "DEBIT",
|
||||
// "prepaid_type": "NOT_PREPAID",
|
||||
// "bin": "411111"
|
||||
// },
|
||||
// "entry_method": "KEYED",
|
||||
// "cvv_status": "CVV_ACCEPTED",
|
||||
// "avs_status": "AVS_ACCEPTED",
|
||||
// "auth_result_code": "2Nkw7q",
|
||||
// "statement_description": "SQ *EXAMPLE TEST GOSQ.C",
|
||||
// "card_payment_timeline": {
|
||||
// "authorized_at": "2021-10-13T19:34:33.680Z",
|
||||
// "captured_at": "2021-10-13T19:34:34.340Z"
|
||||
// }
|
||||
// },
|
||||
// "location_id": "L88917AVBK2S5",
|
||||
// "order_id": "d7eKah653Z579f3gVtjlxpSlmUcZY",
|
||||
// "processing_fee": [
|
||||
// {
|
||||
// "effective_at": "2021-10-13T21:34:35.000Z",
|
||||
// "type": "INITIAL",
|
||||
// "amount_money": {
|
||||
// "amount": 34,
|
||||
// "currency": "USD"
|
||||
// }
|
||||
// }
|
||||
// ],
|
||||
// "note": "Test Note",
|
||||
// "total_money": {
|
||||
// "amount": 555,
|
||||
// "currency": "USD"
|
||||
// },
|
||||
// "approved_money": {
|
||||
// "amount": 555,
|
||||
// "currency": "USD"
|
||||
// },
|
||||
// "employee_id": "TMoK_ogh6rH1o4dV",
|
||||
// "receipt_number": "bP9m",
|
||||
// "receipt_url": "https://squareup.com/receipt/preview/bP9mAsEMYPUGjjGNaNO5ZDVyLhSZY",
|
||||
// "delay_action": "CANCEL",
|
||||
// "delayed_until": "2021-10-20T19:34:33.524Z",
|
||||
// "team_member_id": "TMoK_ogh6rH1o4dV",
|
||||
// "application_details": {
|
||||
// "square_product": "VIRTUAL_TERMINAL",
|
||||
// "application_id": "sq0ids-Pw67AZAlLVB7hsRmwlJPuA"
|
||||
// },
|
||||
// "version_token": "56pRkL3slrzet2iQrTp9n0bdJVYTB9YEWdTNjQfZOPV6o"
|
||||
// }
|
||||
// }
|
||||
|
||||
if($apiResponse->isSuccess()){
|
||||
|
||||
$payment_hash_id = $apiResponse->getPayment()->getReferenceId() ?? false;
|
||||
$square_payment = $apiResponse->getPayment()->jsonSerialize();
|
||||
$payment_hash = PaymentHash::where('hash',$payment_hash_id)->first();
|
||||
|
||||
$payment_hash->data = array_merge((array) $payment_hash->data, (array)$square_payment);
|
||||
$payment_hash->save();
|
||||
|
||||
$square->setPaymentHash($payment_hash);
|
||||
$square->setClient($payment_hash->fee_invoice->client);
|
||||
|
||||
$data = [
|
||||
'payment_type' => $this->source_type[$square_payment->source_type],
|
||||
'amount' => $payment_hash->amount_with_fee,
|
||||
'transaction_reference' => $square_payment->id,
|
||||
'gateway_type_id' => GatewayType::BANK_TRANSFER,
|
||||
];
|
||||
|
||||
$payment = $square->createPayment($data, Payment::STATUS_COMPLETED);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => $this->webhook_array, 'data' => $square_payment],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_SQUARE,
|
||||
$square->client,
|
||||
$square->client->company,
|
||||
);
|
||||
|
||||
return $payment;
|
||||
|
||||
}
|
||||
else{
|
||||
nlog("Square Webhook Payment not found: $payment_reference");
|
||||
}
|
||||
}
|
||||
}
|
@ -20,8 +20,12 @@ use App\Models\PaymentType;
|
||||
use Square\Http\ApiResponse;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Square\Utils\WebhooksHelper;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use Square\Models\WebhookSubscription;
|
||||
use App\PaymentDrivers\Square\CreditCard;
|
||||
use App\PaymentDrivers\Square\SquareWebhook;
|
||||
use Square\Models\CreateWebhookSubscriptionRequest;
|
||||
use App\Http\Requests\Payments\PaymentWebhookRequest;
|
||||
use Square\Models\Builders\RefundPaymentRequestBuilder;
|
||||
|
||||
@ -230,6 +234,8 @@ class SquarePaymentDriver extends BaseDriver
|
||||
$body = new \Square\Models\CreatePaymentRequest($cgt->token, \Illuminate\Support\Str::random(32), $amount_money);
|
||||
$body->setCustomerId($cgt->gateway_customer_reference);
|
||||
$body->setAmountMoney($amount_money);
|
||||
$body->setReferenceId($payment_hash->hash);
|
||||
$body->setNote(substr($description,0,500));
|
||||
|
||||
/** @var ApiResponse */
|
||||
$response = $this->square->getPaymentsApi()->createPayment($body);
|
||||
@ -284,17 +290,35 @@ class SquarePaymentDriver extends BaseDriver
|
||||
$this->init();
|
||||
|
||||
$event_types = ['payment.created', 'payment.updated'];
|
||||
$subscription = new \Square\Models\WebhookSubscription();
|
||||
$subscription->setName('Invoice Ninja Webhook Subscription');
|
||||
$subscription = new WebhookSubscription();
|
||||
$subscription->setName('Invoice_Ninja_Webhook_Subscription');
|
||||
$subscription->setEventTypes($event_types);
|
||||
$subscription->setNotificationUrl($this->company_gateway->webhookUrl());
|
||||
// $subscription->setApiVersion('2021-12-15');
|
||||
|
||||
$body = new \Square\Models\CreateWebhookSubscriptionRequest($subscription);
|
||||
$body = new CreateWebhookSubscriptionRequest($subscription);
|
||||
$body->setIdempotencyKey(\Illuminate\Support\Str::uuid());
|
||||
|
||||
$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()) {
|
||||
$result = $api_response->getResult();
|
||||
} else {
|
||||
@ -303,21 +327,29 @@ class SquarePaymentDriver extends BaseDriver
|
||||
|
||||
}
|
||||
|
||||
public function processWebhookRequest(PaymentWebhookRequest $request, Payment $payment = null)
|
||||
public function processWebhookRequest(PaymentWebhookRequest $request)
|
||||
{
|
||||
|
||||
$signature_key = $this->company_gateway->getConfigField('signatureKey');
|
||||
$notification_url = $this->company_gateway->webhookUrl();
|
||||
|
||||
// header('Content-Type: text/plain');
|
||||
// $webhook_payload = file_get_contents('php://input');
|
||||
|
||||
// if($request->header('cko-signature') == hash_hmac('sha256', $webhook_payload, $this->company_gateway->company->company_key)) {
|
||||
// CheckoutWebhook::dispatch($request->all(), $request->company_key, $this->company_gateway->id)->delay(10);
|
||||
// } else {
|
||||
// nlog("Hash Mismatch = {$request->header('cko-signature')} ".hash_hmac('sha256', $webhook_payload, $this->company_gateway->company->company_key));
|
||||
// nlog($request->all());
|
||||
// }
|
||||
$body = '';
|
||||
$handle = fopen('php://input', 'r');
|
||||
while(!feof($handle)) {
|
||||
$body .= fread($handle, 1024);
|
||||
}
|
||||
|
||||
// return response()->json(['success' => true]);
|
||||
if (WebhooksHelper::isValidWebhookEventSignature($body, $request->header('x-square-hmacsha256-signature'), $signature_key, $notification_url)) {
|
||||
SquareWebhook::dispatch($request->all(), $request->company_key, $this->company_gateway->id)->delay(5);
|
||||
} else {
|
||||
nlog("Square Hash Mismatch");
|
||||
nlog($request->all());
|
||||
}
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ class PaymentLibrariesSeeder extends Seeder
|
||||
['id' => 53, 'name' => 'PagSeguro', 'provider' => 'PagSeguro', 'key' => 'ef498756b54db63c143af0ec433da803', 'fields' => '{"email":"","token":"","sandbox":false}'],
|
||||
['id' => 54, 'name' => 'PAYMILL', 'provider' => 'Paymill', 'key' => 'ca52f618a39367a4c944098ebf977e1c', 'fields' => '{"apiKey":""}'],
|
||||
['id' => 55, 'name' => 'Custom', 'provider' => 'Custom', 'is_offsite' => true, 'sort_order' => 21, 'key' => '54faab2ab6e3223dbe848b1686490baa', 'fields' => '{"name":"","text":""}'],
|
||||
['id' => 57, 'name' => 'Square', 'provider' => 'Square', 'is_offsite' => false, 'sort_order' => 21, 'key' => '65faab2ab6e3223dbe848b1686490baz', 'fields' => '{"accessToken":"","applicationId":"","locationId":"","testMode":false}'],
|
||||
['id' => 57, 'name' => 'Square', 'provider' => 'Square', 'is_offsite' => false, 'sort_order' => 21, 'key' => '65faab2ab6e3223dbe848b1686490baz', 'fields' => '{"accessToken":"","applicationId":"","locationId":"","signatureKey":"","testMode":false}'],
|
||||
['id' => 58, 'name' => 'Razorpay', 'provider' => 'Razorpay', 'is_offsite' => false, 'sort_order' => 21, 'key' => 'hxd6gwg3ekb9tb3v9lptgx1mqyg69zu9', 'fields' => '{"apiKey":"","apiSecret":""}'],
|
||||
['id' => 59, 'name' => 'Forte', 'provider' => 'Forte', 'is_offsite' => false, 'sort_order' => 21, 'key' => 'kivcvjexxvdiyqtj3mju5d6yhpeht2xs', 'fields' => '{"testMode":false,"apiLoginId":"","apiAccessId":"","secureKey":"","authOrganizationId":"","organizationId":"","locationId":""}'],
|
||||
['id' => 60, 'name' => 'PayPal REST', 'provider' => 'PayPal_Rest', 'key' => '80af24a6a691230bbec33e930ab40665', 'fields' => '{"clientId":"","secret":"","signature":"","testMode":false}'],
|
||||
|
Loading…
x
Reference in New Issue
Block a user