|
@@ -0,0 +1,299 @@
|
|
|
|
|
+<?php
|
|
|
|
|
+
|
|
|
|
|
+namespace Longyi\Pay\AwxKlarna\Payment;
|
|
|
|
|
+
|
|
|
|
|
+use Illuminate\Support\Facades\Storage;
|
|
|
|
|
+use Webkul\Checkout\Facades\Cart;
|
|
|
|
|
+use Webkul\Payment\Payment\Payment;
|
|
|
|
|
+use GuzzleHttp\Client;
|
|
|
|
|
+use Webkul\Sales\Models\Order;
|
|
|
|
|
+use Webkul\Sales\Repositories\OrderRepository;
|
|
|
|
|
+
|
|
|
|
|
+class AwxKlarna extends Payment
|
|
|
|
|
+{
|
|
|
|
|
+
|
|
|
|
|
+ protected $clientId;
|
|
|
|
|
+ protected $apikey;
|
|
|
|
|
+ protected $secret;
|
|
|
|
|
+ protected $prefix = 'QQS';
|
|
|
|
|
+ protected $tokenCacheKey = 'airwallex_klarna_token';
|
|
|
|
|
+ protected $tokenUrl = 'https://api-demo.airwallex.com/api/v1/authentication/login';
|
|
|
|
|
+ protected $createPaymentUlr = 'https://api-demo.airwallex.com/api/v1/pa/payment_intents/create';
|
|
|
|
|
+ protected $confirmIntentsUlr = 'https://api-demo.airwallex.com/api/v1/pa/payment_intents/{id}/confirm';
|
|
|
|
|
+ protected $captureIntentsUlr = 'https://api-demo.airwallex.com/api/v1/pa/payment_intents/{id}/capture';
|
|
|
|
|
+ protected $paymentIntentsUlr = 'https://api-demo.airwallex.com/api/v1/pa/payment_intents/';
|
|
|
|
|
+
|
|
|
|
|
+ public function __construct()
|
|
|
|
|
+ {
|
|
|
|
|
+ if ($this->getConfigData('mode') == 'live') {
|
|
|
|
|
+ $this->tokenUrl = 'https://api.airwallex.com/api/v1/authentication/login';
|
|
|
|
|
+ $this->createPaymentUlr = 'https://api.airwallex.com/api/v1/pa/payment_intents/create';
|
|
|
|
|
+ $this->confirmIntentsUlr = 'https://api.airwallex.com/api/v1/pa/payment_intents/{id}/confirm';
|
|
|
|
|
+ $this->captureIntentsUlr = 'https://api.airwallex.com/api/v1/pa/payment_intents/{id}/capture';
|
|
|
|
|
+ $this->paymentIntentsUlr = 'https://api.airwallex.com/api/v1/pa/payment_intents/';
|
|
|
|
|
+ }
|
|
|
|
|
+ $this->clientId = $this->getConfigData('client_id');
|
|
|
|
|
+ $this->apikey = $this->getConfigData('secret_id');
|
|
|
|
|
+ $this->secret = $this->getConfigData('webhook_id');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Payment method code
|
|
|
|
|
+ *
|
|
|
|
|
+ * @var string
|
|
|
|
|
+ */
|
|
|
|
|
+ protected $code = 'awxklarna';
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Get redirect url.
|
|
|
|
|
+ */
|
|
|
|
|
+ public function getRedirectUrl()
|
|
|
|
|
+ {
|
|
|
|
|
+ return route('klarna.standard.placeOrder');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function createPayment($cart, $override)
|
|
|
|
|
+ {
|
|
|
|
|
+ $shop = $cart['shipping_address'];
|
|
|
|
|
+ $bill = $cart['billing_address'];
|
|
|
|
|
+ $telephone = $shop['phone'] ?: $bill['phone'];
|
|
|
|
|
+ $grandTotal = round($cart['grand_total'], 2);
|
|
|
|
|
+ $products[] = [
|
|
|
|
|
+ 'name' => 'total',
|
|
|
|
|
+ 'unit_price' => $grandTotal,
|
|
|
|
|
+ 'quantity' => 1
|
|
|
|
|
+ ];
|
|
|
|
|
+ $data = [
|
|
|
|
|
+ 'request_id' => $this->createUuid(),
|
|
|
|
|
+ 'amount' => $grandTotal,
|
|
|
|
|
+ 'descriptor' => $this->prefix,
|
|
|
|
|
+ 'return_url' => $this->getBaseUlr() . '/klarna/standard/return?orderId=' . $override['merchantOrderId'],
|
|
|
|
|
+ 'merchant_order_id' => $this->prefix . $override['merchantOrderId'],
|
|
|
|
|
+ 'currency' => $cart['order_currency_code'],
|
|
|
|
|
+ 'customer' => [
|
|
|
|
|
+ 'email' => $cart['customer_email'],
|
|
|
|
|
+ 'first_name' => $cart['customer_first_name'],
|
|
|
|
|
+ 'last_name' => $cart['customer_last_name'],
|
|
|
|
|
+ 'phone_number' => $telephone
|
|
|
|
|
+ ],
|
|
|
|
|
+// 'metadata' => $cart['items'],
|
|
|
|
|
+ 'order' => [
|
|
|
|
|
+ 'products' => $products,
|
|
|
|
|
+ 'shipping' => [
|
|
|
|
|
+ 'address' => [
|
|
|
|
|
+ 'city' => $shop['city'],
|
|
|
|
|
+ 'postcode' => $shop['postcode'],
|
|
|
|
|
+ 'state' => $shop['state'],
|
|
|
|
|
+ 'country_code' => $shop['country'],
|
|
|
|
|
+ 'street' => $shop['address'],
|
|
|
|
|
+ ],
|
|
|
|
|
+ 'first_name' => $shop['first_name'],
|
|
|
|
|
+ 'last_name' => $shop['last_name'],
|
|
|
|
|
+ 'phone_number' => $shop['phone'],
|
|
|
|
|
+ 'email' => $shop['email']
|
|
|
|
|
+ ],
|
|
|
|
|
+ ]
|
|
|
|
|
+ ];
|
|
|
|
|
+ $client = new Client();
|
|
|
|
|
+ $response = $client->request('POST', $this->createPaymentUlr, [
|
|
|
|
|
+ 'headers' => [
|
|
|
|
|
+ 'Accept' => 'application/json',
|
|
|
|
|
+ 'Content-Type' => 'application/json',
|
|
|
|
|
+ 'Authorization' => 'Bearer '.$this->getToken()
|
|
|
|
|
+ ],
|
|
|
|
|
+ 'json' => $data,
|
|
|
|
|
+ 'timeout' => 30,
|
|
|
|
|
+ 'verify' => false
|
|
|
|
|
+ ]);
|
|
|
|
|
+ $resultObject = json_decode($response->getBody()->getContents());
|
|
|
|
|
+ if (empty($resultObject->id)) {
|
|
|
|
|
+ throw new \Exception($resultObject->details->original_response_message ?:$resultObject->message);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $id = $resultObject->id;
|
|
|
|
|
+ $confirmResultObject = $this->confirmRequest($id, $cart);
|
|
|
|
|
+ if (empty($confirmResultObject->next_action->url)) {
|
|
|
|
|
+ throw new \Exception($confirmResultObject->details->original_response_message ?:$confirmResultObject->message);
|
|
|
|
|
+ }
|
|
|
|
|
+ return $confirmResultObject->next_action->url;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function confirmRequest($paymentIntentId, $cart)
|
|
|
|
|
+ {
|
|
|
|
|
+ $bill = $cart['billing_address'];
|
|
|
|
|
+ $data = [
|
|
|
|
|
+ 'request_id' => $this->createUuid(),
|
|
|
|
|
+ 'payment_method' => [
|
|
|
|
|
+ 'type' => 'klarna',
|
|
|
|
|
+ 'klarna' => [
|
|
|
|
|
+ 'country_code' => $bill['country'],
|
|
|
|
|
+ 'billing' => [
|
|
|
|
|
+ 'email' => $bill['email'],
|
|
|
|
|
+ 'first_name' => $bill['first_name'],
|
|
|
|
|
+ 'last_name' => $bill['last_name'],
|
|
|
|
|
+ 'phone_number' => $bill['phone'],
|
|
|
|
|
+ 'address' => [
|
|
|
|
|
+ 'country_code' => $bill['country'],
|
|
|
|
|
+ 'city' => $bill['city'],
|
|
|
|
|
+ 'street' => $bill['address'],
|
|
|
|
|
+ 'postcode' => $bill['postcode'],
|
|
|
|
|
+ 'state' => $bill['state']
|
|
|
|
|
+ ],
|
|
|
|
|
+ ],
|
|
|
|
|
+ ],
|
|
|
|
|
+ 'payment_method_options' => [
|
|
|
|
|
+ 'klarna' => [
|
|
|
|
|
+ 'auto_capture' => false
|
|
|
|
|
+ ]
|
|
|
|
|
+ ]
|
|
|
|
|
+ ]
|
|
|
|
|
+ ];
|
|
|
|
|
+ $client = new Client();
|
|
|
|
|
+ $response = $client->request('POST',
|
|
|
|
|
+ str_replace('{id}', $paymentIntentId, $this->confirmIntentsUlr),
|
|
|
|
|
+ [
|
|
|
|
|
+ 'headers' => [
|
|
|
|
|
+ 'Accept' => 'application/json',
|
|
|
|
|
+ 'Content-Type' => 'application/json',
|
|
|
|
|
+ 'Authorization' => 'Bearer '.$this->getToken()
|
|
|
|
|
+ ],
|
|
|
|
|
+ 'json' => $data,
|
|
|
|
|
+ 'timeout' => 30,
|
|
|
|
|
+ 'verify' => false
|
|
|
|
|
+ ]);
|
|
|
|
|
+ $result = json_decode($response->getBody()->getContents());
|
|
|
|
|
+ return $result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function getToken()
|
|
|
|
|
+ {
|
|
|
|
|
+ $token = cache()->get($this->tokenCacheKey);
|
|
|
|
|
+ if (!$token) {
|
|
|
|
|
+ $client = new Client();
|
|
|
|
|
+ $response = $client->request('POST', $this->tokenUrl, [
|
|
|
|
|
+ 'headers' => [
|
|
|
|
|
+ 'Accept' => 'application/json',
|
|
|
|
|
+ 'Content-Type' => 'application/json',
|
|
|
|
|
+ 'x-client-id' => $this->clientId,
|
|
|
|
|
+ 'x-api-key' => $this->apikey
|
|
|
|
|
+ ],
|
|
|
|
|
+ 'timeout' => 30,
|
|
|
|
|
+ 'verify' => false
|
|
|
|
|
+ ]);
|
|
|
|
|
+ $result = json_decode($response->getBody()->getContents());
|
|
|
|
|
+ $token = $result->token;
|
|
|
|
|
+ cache()->put($this->tokenCacheKey, $token, 20);
|
|
|
|
|
+ }
|
|
|
|
|
+ return $token;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //成功修改状态
|
|
|
|
|
+ public function payments_webhook_payment_intent_succeeded($orderId, $transactionId)
|
|
|
|
|
+ {
|
|
|
|
|
+ $order = app(OrderRepository::class)->find($orderId);
|
|
|
|
|
+
|
|
|
|
|
+ if (!$order) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($order->status != Order::STATUS_PENDING) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ $order->status = Order::STATUS_PROCESSING;
|
|
|
|
|
+ $order->save();
|
|
|
|
|
+ if ($order->payment) {
|
|
|
|
|
+ $order->payment->update([
|
|
|
|
|
+ 'transaction_id' => $transactionId,
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ //授权成功修改状态
|
|
|
|
|
+ public function payments_webhook_payment_intent_requires_capture($orderId, $transactionId)
|
|
|
|
|
+ {
|
|
|
|
|
+ $order = app(OrderRepository::class)->find($orderId);
|
|
|
|
|
+
|
|
|
|
|
+ if (!$order) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($order->status != Order::STATUS_PENDING) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ $order->status = Order::STATUS_PROCESSING;
|
|
|
|
|
+ $order->save();
|
|
|
|
|
+ if ($order->payment) {
|
|
|
|
|
+ $order->payment->update([
|
|
|
|
|
+ 'transaction_id' => $transactionId,
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取一个唯一的id
|
|
|
|
|
+ */
|
|
|
|
|
+ public function createUuid($prefix = "")
|
|
|
|
|
+ {
|
|
|
|
|
+ $chars = md5(uniqid(mt_rand(), true));
|
|
|
|
|
+ $uuid = substr($chars, 0, 8) . '-'
|
|
|
|
|
+ . substr($chars, 8, 4) . '-'
|
|
|
|
|
+ . substr($chars, 12, 4) . '-'
|
|
|
|
|
+ . substr($chars, 16, 4) . '-'
|
|
|
|
|
+ . substr($chars, 20, 12);
|
|
|
|
|
+ return $prefix . $uuid;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function getBaseUlr()
|
|
|
|
|
+ {
|
|
|
|
|
+ return config('app.url');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function getAwxKlarnaUrl()
|
|
|
|
|
+ {
|
|
|
|
|
+ return route('klarna.standard.redirect');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function checkSignature($data, $exp)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (empty($data)) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (hash_hmac('sha256', $data['timestamp'].$data['content'], $this->$exp) != $data['signature']) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function getPrefix()
|
|
|
|
|
+ {
|
|
|
|
|
+ return $this->prefix;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Get payment method image.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return array
|
|
|
|
|
+ */
|
|
|
|
|
+ public function getImage()
|
|
|
|
|
+ {
|
|
|
|
|
+ $url = $this->getConfigData('image');
|
|
|
|
|
+
|
|
|
|
|
+ return $url ? Storage::url($url) : bagisto_asset('images/cash-on-delivery.png', 'shop');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function isAvailable()
|
|
|
|
|
+ {
|
|
|
|
|
+ if (! parent::isAvailable()) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ $cart = Cart::getCart();
|
|
|
|
|
+ $billingCountry = $cart->billing_address->country;
|
|
|
|
|
+ $allowedCountries = ['AU', 'AT', 'BE', 'CA', 'CZ', 'DK', 'FI', 'FR', 'DE', 'GR', 'IE',
|
|
|
|
|
+ 'IT', 'NL', 'NO', 'PL', 'PT', 'ES', 'SE', 'CH', 'GB', 'US'
|
|
|
|
|
+ ];
|
|
|
|
|
+ return in_array($billingCountry, $allowedCountries);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function getDescription()
|
|
|
|
|
+ {
|
|
|
|
|
+ $cart = Cart::getCart();
|
|
|
|
|
+ return round($cart->grand_total / 4, 2);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|