Airwallex.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <?php
  2. namespace Longyi\Pay\Airwallex\Payment;
  3. use GuzzleHttp\Client;
  4. use Illuminate\Support\Facades\Storage;
  5. use Webkul\Checkout\Facades\Cart;
  6. use Webkul\Payment\Payment\Payment;
  7. use Webkul\Sales\Models\Order;
  8. use Webkul\Sales\Repositories\OrderRepository;
  9. class Airwallex extends Payment
  10. {
  11. /**
  12. * Payment method code
  13. *
  14. * @var string
  15. */
  16. protected $code = 'airwallex';
  17. protected $clientId;
  18. protected $apikey;
  19. protected $secret;
  20. protected $currentOrder;
  21. protected $prefix = 'AS';
  22. protected $tokenCacheKey = 'airwallex_airwallex_token';
  23. protected $tokenUrl = 'https://api-demo.airwallex.com/api/v1/authentication/login';
  24. protected $createPaymentUlr = 'https://api-demo.airwallex.com/api/v1/pa/payment_intents/create';
  25. protected $confirmIntentsUlr = 'https://api-demo.airwallex.com/api/v1/pa/payment_intents/{id}/confirm';
  26. protected $captureIntentsUlr = 'https://api-demo.airwallex.com/api/v1/pa/payment_intents/{id}/capture';
  27. protected $paymentIntentsUlr = 'https://api-demo.airwallex.com/api/v1/pa/payment_intents/';
  28. public function __construct()
  29. {
  30. if ($this->getConfigData('mode') == 'live') {
  31. $this->tokenUrl = 'https://api.airwallex.com/api/v1/authentication/login';
  32. $this->createPaymentUlr = 'https://api.airwallex.com/api/v1/pa/payment_intents/create';
  33. $this->confirmIntentsUlr = 'https://api.airwallex.com/api/v1/pa/payment_intents/{id}/confirm';
  34. $this->captureIntentsUlr = 'https://api.airwallex.com/api/v1/pa/payment_intents/{id}/capture';
  35. $this->paymentIntentsUlr = 'https://api.airwallex.com/api/v1/pa/payment_intents/';
  36. }
  37. $this->clientId = $this->getConfigData('client_id');
  38. $this->apikey = $this->getConfigData('secret_id');
  39. $this->secret = $this->getConfigData('webhook_id');
  40. }
  41. /**
  42. * Get redirect url.
  43. */
  44. public function getRedirectUrl()
  45. {
  46. }
  47. public function setOrder($order = null): self
  48. {
  49. $this->currentOrder = $order;
  50. return $this;
  51. }
  52. public function getOrder()
  53. {
  54. return $this->currentOrder;
  55. }
  56. public function createGatewayOrder()
  57. {
  58. return $this->createIntents($this->getOrder(), ['merchantOrderId' => $this->getOrder()->increment_id]);
  59. }
  60. public function createIntents($order, $override)
  61. {
  62. $shop = $order->shipping_address;
  63. $products = [];
  64. foreach ($order->items as $item) {
  65. $data = [
  66. 'name' => $item->name,
  67. 'desc' => $item->name,
  68. 'unit_price' => (float) $item->price,
  69. 'sku' => $item->sku,
  70. 'quantity' => $item->qty_ordered
  71. ];
  72. array_push($products, $data);
  73. }
  74. $grandTotal = round($order->grand_total, 2);
  75. $data = [
  76. 'request_id' => $this->createUuid(),
  77. 'amount' => $grandTotal,
  78. 'descriptor' => $this->prefix,
  79. 'merchant_order_id' => $this->prefix . $override['merchantOrderId'],
  80. 'currency' => $order->order_currency_code,
  81. 'customer' => [
  82. 'email' => $order->customer_email,
  83. 'first_name' => $order->customer_first_name,
  84. 'last_name' => $order->customer_last_name
  85. ],
  86. 'order' => [
  87. 'products' => $products,
  88. 'shipping' => [
  89. 'address' => [
  90. 'city' => $shop->city,
  91. 'postcode' => $shop->postcode,
  92. 'state' => $shop->state,
  93. 'country_code'=> $shop->country,
  94. 'street' => $shop->address,
  95. ],
  96. 'first_name' => $shop->first_name,
  97. 'last_name' => $shop->last_name,
  98. 'phone_number' => $shop->phone,
  99. 'email' => $shop->email
  100. ],
  101. ],
  102. ];
  103. $client = new Client();
  104. $response = $client->request('POST', $this->createPaymentUlr, [
  105. 'headers' => [
  106. 'Accept' => 'application/json',
  107. 'Content-Type' => 'application/json',
  108. 'Authorization' => 'Bearer '.$this->getToken()
  109. ],
  110. 'json' => $data,
  111. 'timeout' => 30,
  112. 'verify' => false
  113. ]);
  114. $resultObject = json_decode($response->getBody()->getContents());
  115. if ($resultObject->status != 'SUCCESS') {
  116. throw new \Exception('airwallex api is error');
  117. }
  118. $id = $resultObject->id;
  119. $client_secret = $resultObject->client_secret;
  120. return $id . ':' . $client_secret;
  121. }
  122. public function getToken()
  123. {
  124. $token = cache()->get($this->tokenCacheKey);
  125. if (!$token) {
  126. $client = new Client();
  127. $response = $client->request('POST', $this->tokenUrl, [
  128. 'headers' => [
  129. 'Accept' => 'application/json',
  130. 'Content-Type' => 'application/json',
  131. 'x-client-id' => $this->clientId,
  132. 'x-api-key' => $this->apikey
  133. ],
  134. 'timeout' => 30,
  135. 'verify' => false
  136. ]);
  137. $result = json_decode($response->getBody()->getContents());
  138. $token = $result->token;
  139. cache()->put($this->tokenCacheKey, $token, 20);
  140. }
  141. return $token;
  142. }
  143. //成功修改状态
  144. public function payments_webhook_payment_intent_succeeded($orderId, $transactionId)
  145. {
  146. $order = app(OrderRepository::class)->find($orderId);
  147. if (!$order) {
  148. return false;
  149. }
  150. if ($order->status != Order::STATUS_PENDING) {
  151. return false;
  152. }
  153. $order->status = Order::STATUS_PROCESSING;
  154. $order->save();
  155. if ($order->payment) {
  156. $order->payment->update([
  157. 'transaction_id' => $transactionId,
  158. ]);
  159. }
  160. }
  161. //授权成功修改状态
  162. public function payments_webhook_payment_intent_requires_capture($orderId, $transactionId)
  163. {
  164. $order = app(OrderRepository::class)->find($orderId);
  165. if (!$order) {
  166. return false;
  167. }
  168. if ($order->status != Order::STATUS_PENDING) {
  169. return false;
  170. }
  171. $order->status = Order::STATUS_PROCESSING;
  172. $order->save();
  173. if ($order->payment) {
  174. $order->payment->update([
  175. 'transaction_id' => $transactionId,
  176. ]);
  177. }
  178. }
  179. /**
  180. * 获取一个唯一的id
  181. */
  182. public function createUuid($prefix = "")
  183. {
  184. $chars = md5(uniqid(mt_rand(), true));
  185. $uuid = substr($chars, 0, 8) . '-'
  186. . substr($chars, 8, 4) . '-'
  187. . substr($chars, 12, 4) . '-'
  188. . substr($chars, 16, 4) . '-'
  189. . substr($chars, 20, 12);
  190. return $prefix . $uuid;
  191. }
  192. public function checkSignature($data, $exp)
  193. {
  194. if (empty($data)) {
  195. return false;
  196. }
  197. if (hash_hmac('sha256', $data['timestamp'].$data['content'], $this->$exp) != $data['signature']) {
  198. return false;
  199. }
  200. return true;
  201. }
  202. public function getPrefix()
  203. {
  204. return $this->prefix;
  205. }
  206. /**
  207. * Get payment method image.
  208. *
  209. * @return array
  210. */
  211. public function getImage()
  212. {
  213. $url = $this->getConfigData('image');
  214. return $url ? Storage::url($url) : bagisto_asset('images/cash-on-delivery.png', 'shop');
  215. }
  216. public function isAvailable()
  217. {
  218. if (! parent::isAvailable()) {
  219. return false;
  220. }
  221. $cart = Cart::getCart();
  222. $billingCountry = $cart->billing_address->country;
  223. $allowedCountries = ['AU', 'CA', 'NZ', 'GB', 'US'];
  224. return in_array($billingCountry, $allowedCountries);
  225. }
  226. }