Przeglądaj źródła

Merge branch 'dev' of http://gogs.hnwmzp.cn/chengwenliang/nshop into dev

chengwl 5 dni temu
rodzic
commit
9d66287d97

+ 70 - 68
bootstrap/cache/services.php

@@ -65,40 +65,41 @@
     61 => 'Longyi\\Pay\\Applepay\\Providers\\ApplepayServiceProvider',
     62 => 'Longyi\\Pay\\Airwallex\\Providers\\AirwallexServiceProvider',
     63 => 'Longyi\\Pay\\Afterpay\\Providers\\AfterpayServiceProvider',
-    64 => 'Webkul\\Attribute\\Providers\\AttributeServiceProvider',
-    65 => 'Webkul\\BookingProduct\\Providers\\BookingProductServiceProvider',
-    66 => 'Webkul\\CMS\\Providers\\CMSServiceProvider',
-    67 => 'Webkul\\CartRule\\Providers\\CartRuleServiceProvider',
-    68 => 'Webkul\\CatalogRule\\Providers\\CatalogRuleServiceProvider',
-    69 => 'Webkul\\Category\\Providers\\CategoryServiceProvider',
-    70 => 'Webkul\\Checkout\\Providers\\CheckoutServiceProvider',
-    71 => 'Webkul\\Core\\Providers\\CoreServiceProvider',
-    72 => 'Webkul\\Core\\Providers\\EnvValidatorServiceProvider',
-    73 => 'Webkul\\Customer\\Providers\\CustomerServiceProvider',
-    74 => 'Webkul\\DataGrid\\Providers\\DataGridServiceProvider',
-    75 => 'Webkul\\DataTransfer\\Providers\\DataTransferServiceProvider',
-    76 => 'Webkul\\DebugBar\\Providers\\DebugBarServiceProvider',
-    77 => 'Webkul\\FPC\\Providers\\FPCServiceProvider',
-    78 => 'Webkul\\GDPR\\Providers\\GDPRServiceProvider',
-    79 => 'Webkul\\Installer\\Providers\\InstallerServiceProvider',
-    80 => 'Webkul\\Inventory\\Providers\\InventoryServiceProvider',
-    81 => 'Webkul\\MagicAI\\Providers\\MagicAIServiceProvider',
-    82 => 'Webkul\\Marketing\\Providers\\MarketingServiceProvider',
-    83 => 'Webkul\\Notification\\Providers\\NotificationServiceProvider',
-    84 => 'Webkul\\Payment\\Providers\\PaymentServiceProvider',
-    85 => 'Webkul\\Paypal\\Providers\\PaypalServiceProvider',
-    86 => 'Webkul\\Product\\Providers\\ProductServiceProvider',
-    87 => 'Webkul\\Rule\\Providers\\RuleServiceProvider',
-    88 => 'Webkul\\Sales\\Providers\\SalesServiceProvider',
-    89 => 'Webkul\\Shipping\\Providers\\ShippingServiceProvider',
-    90 => 'Webkul\\Shop\\Providers\\ShopServiceProvider',
-    91 => 'Webkul\\Sitemap\\Providers\\SitemapServiceProvider',
-    92 => 'Webkul\\SocialLogin\\Providers\\SocialLoginServiceProvider',
-    93 => 'Webkul\\SocialShare\\Providers\\SocialShareServiceProvider',
-    94 => 'Webkul\\Tax\\Providers\\TaxServiceProvider',
-    95 => 'Webkul\\Theme\\Providers\\ThemeServiceProvider',
-    96 => 'Webkul\\User\\Providers\\UserServiceProvider',
-    97 => 'Webkul\\BagistoApi\\Providers\\BagistoApiServiceProvider',
+    64 => 'Longyi\\Pay\\Klarna\\Providers\\KlarnaServiceProvider',
+    65 => 'Webkul\\Attribute\\Providers\\AttributeServiceProvider',
+    66 => 'Webkul\\BookingProduct\\Providers\\BookingProductServiceProvider',
+    67 => 'Webkul\\CMS\\Providers\\CMSServiceProvider',
+    68 => 'Webkul\\CartRule\\Providers\\CartRuleServiceProvider',
+    69 => 'Webkul\\CatalogRule\\Providers\\CatalogRuleServiceProvider',
+    70 => 'Webkul\\Category\\Providers\\CategoryServiceProvider',
+    71 => 'Webkul\\Checkout\\Providers\\CheckoutServiceProvider',
+    72 => 'Webkul\\Core\\Providers\\CoreServiceProvider',
+    73 => 'Webkul\\Core\\Providers\\EnvValidatorServiceProvider',
+    74 => 'Webkul\\Customer\\Providers\\CustomerServiceProvider',
+    75 => 'Webkul\\DataGrid\\Providers\\DataGridServiceProvider',
+    76 => 'Webkul\\DataTransfer\\Providers\\DataTransferServiceProvider',
+    77 => 'Webkul\\DebugBar\\Providers\\DebugBarServiceProvider',
+    78 => 'Webkul\\FPC\\Providers\\FPCServiceProvider',
+    79 => 'Webkul\\GDPR\\Providers\\GDPRServiceProvider',
+    80 => 'Webkul\\Installer\\Providers\\InstallerServiceProvider',
+    81 => 'Webkul\\Inventory\\Providers\\InventoryServiceProvider',
+    82 => 'Webkul\\MagicAI\\Providers\\MagicAIServiceProvider',
+    83 => 'Webkul\\Marketing\\Providers\\MarketingServiceProvider',
+    84 => 'Webkul\\Notification\\Providers\\NotificationServiceProvider',
+    85 => 'Webkul\\Payment\\Providers\\PaymentServiceProvider',
+    86 => 'Webkul\\Paypal\\Providers\\PaypalServiceProvider',
+    87 => 'Webkul\\Product\\Providers\\ProductServiceProvider',
+    88 => 'Webkul\\Rule\\Providers\\RuleServiceProvider',
+    89 => 'Webkul\\Sales\\Providers\\SalesServiceProvider',
+    90 => 'Webkul\\Shipping\\Providers\\ShippingServiceProvider',
+    91 => 'Webkul\\Shop\\Providers\\ShopServiceProvider',
+    92 => 'Webkul\\Sitemap\\Providers\\SitemapServiceProvider',
+    93 => 'Webkul\\SocialLogin\\Providers\\SocialLoginServiceProvider',
+    94 => 'Webkul\\SocialShare\\Providers\\SocialShareServiceProvider',
+    95 => 'Webkul\\Tax\\Providers\\TaxServiceProvider',
+    96 => 'Webkul\\Theme\\Providers\\ThemeServiceProvider',
+    97 => 'Webkul\\User\\Providers\\UserServiceProvider',
+    98 => 'Webkul\\BagistoApi\\Providers\\BagistoApiServiceProvider',
   ),
   'eager' => 
   array (
@@ -149,40 +150,41 @@
     44 => 'Longyi\\Pay\\Applepay\\Providers\\ApplepayServiceProvider',
     45 => 'Longyi\\Pay\\Airwallex\\Providers\\AirwallexServiceProvider',
     46 => 'Longyi\\Pay\\Afterpay\\Providers\\AfterpayServiceProvider',
-    47 => 'Webkul\\Attribute\\Providers\\AttributeServiceProvider',
-    48 => 'Webkul\\BookingProduct\\Providers\\BookingProductServiceProvider',
-    49 => 'Webkul\\CMS\\Providers\\CMSServiceProvider',
-    50 => 'Webkul\\CartRule\\Providers\\CartRuleServiceProvider',
-    51 => 'Webkul\\CatalogRule\\Providers\\CatalogRuleServiceProvider',
-    52 => 'Webkul\\Category\\Providers\\CategoryServiceProvider',
-    53 => 'Webkul\\Checkout\\Providers\\CheckoutServiceProvider',
-    54 => 'Webkul\\Core\\Providers\\CoreServiceProvider',
-    55 => 'Webkul\\Core\\Providers\\EnvValidatorServiceProvider',
-    56 => 'Webkul\\Customer\\Providers\\CustomerServiceProvider',
-    57 => 'Webkul\\DataGrid\\Providers\\DataGridServiceProvider',
-    58 => 'Webkul\\DataTransfer\\Providers\\DataTransferServiceProvider',
-    59 => 'Webkul\\DebugBar\\Providers\\DebugBarServiceProvider',
-    60 => 'Webkul\\FPC\\Providers\\FPCServiceProvider',
-    61 => 'Webkul\\GDPR\\Providers\\GDPRServiceProvider',
-    62 => 'Webkul\\Installer\\Providers\\InstallerServiceProvider',
-    63 => 'Webkul\\Inventory\\Providers\\InventoryServiceProvider',
-    64 => 'Webkul\\MagicAI\\Providers\\MagicAIServiceProvider',
-    65 => 'Webkul\\Marketing\\Providers\\MarketingServiceProvider',
-    66 => 'Webkul\\Notification\\Providers\\NotificationServiceProvider',
-    67 => 'Webkul\\Payment\\Providers\\PaymentServiceProvider',
-    68 => 'Webkul\\Paypal\\Providers\\PaypalServiceProvider',
-    69 => 'Webkul\\Product\\Providers\\ProductServiceProvider',
-    70 => 'Webkul\\Rule\\Providers\\RuleServiceProvider',
-    71 => 'Webkul\\Sales\\Providers\\SalesServiceProvider',
-    72 => 'Webkul\\Shipping\\Providers\\ShippingServiceProvider',
-    73 => 'Webkul\\Shop\\Providers\\ShopServiceProvider',
-    74 => 'Webkul\\Sitemap\\Providers\\SitemapServiceProvider',
-    75 => 'Webkul\\SocialLogin\\Providers\\SocialLoginServiceProvider',
-    76 => 'Webkul\\SocialShare\\Providers\\SocialShareServiceProvider',
-    77 => 'Webkul\\Tax\\Providers\\TaxServiceProvider',
-    78 => 'Webkul\\Theme\\Providers\\ThemeServiceProvider',
-    79 => 'Webkul\\User\\Providers\\UserServiceProvider',
-    80 => 'Webkul\\BagistoApi\\Providers\\BagistoApiServiceProvider',
+    47 => 'Longyi\\Pay\\Klarna\\Providers\\KlarnaServiceProvider',
+    48 => 'Webkul\\Attribute\\Providers\\AttributeServiceProvider',
+    49 => 'Webkul\\BookingProduct\\Providers\\BookingProductServiceProvider',
+    50 => 'Webkul\\CMS\\Providers\\CMSServiceProvider',
+    51 => 'Webkul\\CartRule\\Providers\\CartRuleServiceProvider',
+    52 => 'Webkul\\CatalogRule\\Providers\\CatalogRuleServiceProvider',
+    53 => 'Webkul\\Category\\Providers\\CategoryServiceProvider',
+    54 => 'Webkul\\Checkout\\Providers\\CheckoutServiceProvider',
+    55 => 'Webkul\\Core\\Providers\\CoreServiceProvider',
+    56 => 'Webkul\\Core\\Providers\\EnvValidatorServiceProvider',
+    57 => 'Webkul\\Customer\\Providers\\CustomerServiceProvider',
+    58 => 'Webkul\\DataGrid\\Providers\\DataGridServiceProvider',
+    59 => 'Webkul\\DataTransfer\\Providers\\DataTransferServiceProvider',
+    60 => 'Webkul\\DebugBar\\Providers\\DebugBarServiceProvider',
+    61 => 'Webkul\\FPC\\Providers\\FPCServiceProvider',
+    62 => 'Webkul\\GDPR\\Providers\\GDPRServiceProvider',
+    63 => 'Webkul\\Installer\\Providers\\InstallerServiceProvider',
+    64 => 'Webkul\\Inventory\\Providers\\InventoryServiceProvider',
+    65 => 'Webkul\\MagicAI\\Providers\\MagicAIServiceProvider',
+    66 => 'Webkul\\Marketing\\Providers\\MarketingServiceProvider',
+    67 => 'Webkul\\Notification\\Providers\\NotificationServiceProvider',
+    68 => 'Webkul\\Payment\\Providers\\PaymentServiceProvider',
+    69 => 'Webkul\\Paypal\\Providers\\PaypalServiceProvider',
+    70 => 'Webkul\\Product\\Providers\\ProductServiceProvider',
+    71 => 'Webkul\\Rule\\Providers\\RuleServiceProvider',
+    72 => 'Webkul\\Sales\\Providers\\SalesServiceProvider',
+    73 => 'Webkul\\Shipping\\Providers\\ShippingServiceProvider',
+    74 => 'Webkul\\Shop\\Providers\\ShopServiceProvider',
+    75 => 'Webkul\\Sitemap\\Providers\\SitemapServiceProvider',
+    76 => 'Webkul\\SocialLogin\\Providers\\SocialLoginServiceProvider',
+    77 => 'Webkul\\SocialShare\\Providers\\SocialShareServiceProvider',
+    78 => 'Webkul\\Tax\\Providers\\TaxServiceProvider',
+    79 => 'Webkul\\Theme\\Providers\\ThemeServiceProvider',
+    80 => 'Webkul\\User\\Providers\\UserServiceProvider',
+    81 => 'Webkul\\BagistoApi\\Providers\\BagistoApiServiceProvider',
   ),
   'deferred' => 
   array (

+ 1 - 0
bootstrap/providers.php

@@ -22,6 +22,7 @@ return [
     Longyi\Pay\Applepay\Providers\ApplepayServiceProvider::class,
     Longyi\Pay\Airwallex\Providers\AirwallexServiceProvider::class,
     Longyi\Pay\Afterpay\Providers\AfterpayServiceProvider::class,
+    Longyi\Pay\Klarna\Providers\KlarnaServiceProvider::class,
     Webkul\Attribute\Providers\AttributeServiceProvider::class,
     Webkul\BookingProduct\Providers\BookingProductServiceProvider::class,
     Webkul\CMS\Providers\CMSServiceProvider::class,

+ 1 - 0
composer.json

@@ -89,6 +89,7 @@
             "Longyi\\Pay\\AwxKlarna\\": "packages/Longyi/Pay/AwxKlarna/src/",
             "Longyi\\Pay\\AwxAfterpay\\": "packages/Longyi/Pay/AwxAfterpay/src/",
             "Longyi\\Pay\\Afterpay\\": "packages/Longyi/Pay/Afterpay/src/",
+            "Longyi\\Pay\\Klarna\\": "packages/Longyi/Pay/Klarna/src/",
             "Webkul\\Admin\\": "packages/Webkul/Admin/src",
             "Webkul\\Attribute\\": "packages/Webkul/Attribute/src",
             "Webkul\\BookingProduct\\": "packages/Webkul/BookingProduct/src",

+ 6 - 0
packages/Longyi/Pay/Applepay/src/Payment/Applepay.php

@@ -113,6 +113,12 @@ class Applepay extends Payment
                         ],
                     ],
                 ]
+            ],
+            'payment_source' => [
+                'apple_pay' => [
+                    'name' => $order->customer_full_name,
+                    'email_address' => $order->customer_email
+                ]
             ]
         ];
         $client = new Client();

+ 12 - 0
packages/Longyi/Pay/Klarna/src/Config/payment-methods.php

@@ -0,0 +1,12 @@
+<?php
+
+return [
+    'klarna'  => [
+        'code'        => 'klarna',
+        'title'       => 'Klarna',
+        'description' => 'Klarna',
+        'class'       => 'Longyi\Pay\Klarna\Payment\Klarna',
+        'active'      => true,
+        'sort'        => 1,
+    ],
+];

+ 74 - 0
packages/Longyi/Pay/Klarna/src/Config/system.php

@@ -0,0 +1,74 @@
+<?php
+
+return [
+    [
+        'key'    => 'sales.payment_methods.klarna',
+        'name'   => 'Klarna', // use translation
+        'info'   => 'Information about Klarna', // use translation
+        'sort'   => 10,
+        'fields' => [
+            [
+                'name'          => 'title',
+                'title'         => 'Title', // use translation
+                'type'          => 'text',
+                'validation'    => 'required',
+                'channel_based' => false,
+                'locale_based'  => true,
+            ], [
+                'name'          => 'description',
+                'title'         => 'Description', // use translation
+                'type'          => 'textarea',
+                'channel_based' => false,
+                'locale_based'  => true,
+            ],[
+                'name' => 'mode',
+                'title' => 'Mode',
+                'type' => 'select',
+                'options' => [
+                    [
+                        'title' => 'live',
+                        'value' => 'live',
+                    ], [
+                        'title' => 'test',
+                        'value' => 'test',
+                    ],
+                ],
+                'depend' => 'active:1',
+                'validation' => 'required_if:active,1',
+                'channel_based' => false,
+                'locale_based' => true,
+            ], [
+                'name' => 'client_id',
+                'title' => 'username',
+                'type' => 'text',
+                'depend' => 'active:1',
+                'validation' => 'required_if:active,1',
+                'channel_based' => false,
+                'locale_based' => true,
+            ], [
+                'name' => 'secret_id',
+                'title' => 'password',
+                'type' => 'password',
+                'depend' => 'active:1',
+                'validation' => 'required_if:active,1',
+                'channel_based' => false,
+                'locale_based' => true,
+            ], [
+                'name'          => 'sort',
+                'title'         => 'Sort Order',
+                'type'          => 'text',
+                'validation'    => 'numeric',
+                'channel_based' => true,
+                'locale_based'  => false,
+                'default'       => 5,
+            ], [
+                'name'          => 'active',
+                'title'         => 'Status', // use translation
+                'type'          => 'boolean',
+                'validation'    => 'required',
+                'channel_based' => false,
+                'locale_based'  => true,
+            ]
+        ]
+    ]
+];

+ 12 - 0
packages/Longyi/Pay/Klarna/src/Http/Controllers/Controller.php

@@ -0,0 +1,12 @@
+<?php
+
+namespace Longyi\Pay\Klarna\Http\Controllers;
+
+use Illuminate\Foundation\Bus\DispatchesJobs;
+use Illuminate\Foundation\Validation\ValidatesRequests;
+use Illuminate\Routing\Controller as BaseController;
+
+class Controller extends BaseController
+{
+    use DispatchesJobs, ValidatesRequests;
+}

+ 66 - 0
packages/Longyi/Pay/Klarna/src/Http/Controllers/KlarnaController.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace Longyi\Pay\Klarna\Http\Controllers;
+
+use Longyi\Pay\Klarna\Payment\Klarna;
+use Webkul\Checkout\Facades\Cart;
+use Webkul\Sales\Models\Order;
+use Webkul\Sales\Repositories\OrderRepository;
+use Webkul\Sales\Transformers\OrderResource;
+use Longyi\Pay\AwxKlarna\Payment\AwxKlarna;
+
+class KlarnaController extends Controller
+{
+    /**
+     * Create a new controller instance.
+     *
+     * @return void
+     */
+    public function __construct(
+        protected OrderRepository $orderRepository,
+        protected Klarna $klarna,
+    ) {}
+
+
+    public function hook()
+    {
+        $param = @file_get_contents('php://input');
+        $header = $this->getAllHeaders();
+        $data = [
+            'timestamp' => $header['x-timestamp'],
+            'signature' => $header['x-signature'],
+            'content' => $param
+        ];
+        $result = $this->airwallex->checkSignature($data, 'secret');
+        if (!$result) {
+            @header("HTTP/1.0 400 Bad Request");
+            exit;
+        }
+        $notifyData = json_decode($param, true);
+        $orderNo = $notifyData['data']['object']['merchant_order_id'] ?: 0;
+        if (empty($orderNo)) {
+            @header("HTTP/1.0 400 Bad Request");
+            exit;
+        }
+        $prefix = $this->airwallex->getPrefix();
+        if (strpos($orderNo, $prefix) === false) {
+            @header("HTTP/1.0 200 ok");
+            exit;
+        }
+        $type = $notifyData['name'];
+        $orderId = str_replace($prefix, '', $orderNo);
+        $transactionId = $notifyData['data']['object']['id'] ?: '';
+        switch ($type) {
+            case 'payment_intent.requires_capture':
+            case 'payment_intent.succeeded':
+                $this->airwallex->paymentSucceeded($orderId, $transactionId);
+                @header("HTTP/1.0 200 ok");
+                break;
+            default:
+                // 对于未知事件类型,记录日志但仍返回成功
+                @header("HTTP/1.0 200 ok");
+                break;
+        }
+    }
+
+}

+ 7 - 0
packages/Longyi/Pay/Klarna/src/Http/routes.php

@@ -0,0 +1,7 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use Longyi\Pay\Klarna\Http\Controllers\KlarnaController;
+
+// Webhook 路由(独立于 web 中间件,避免 CSRF 验证)
+Route::post('klarna/webhook/hook', [KlarnaController::class, 'hook'])->name('airwallex.webhook.hook');

+ 241 - 0
packages/Longyi/Pay/Klarna/src/Payment/Klarna.php

@@ -0,0 +1,241 @@
+<?php
+
+namespace Longyi\Pay\Klarna\Payment;
+
+use GuzzleHttp\Client;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\Storage;
+use Webkul\Checkout\Facades\Cart;
+use Webkul\Payment\Payment\Payment;
+use Webkul\Sales\Models\Order;
+use Webkul\Sales\Repositories\OrderRepository;
+use Webkul\Sales\Repositories\InvoiceRepository;
+
+class Klarna extends Payment
+{
+    /**
+     * Payment method code
+     *
+     * @var string
+     */
+    protected $code  = 'klarna';
+    protected $clientId;
+    protected $apikey;
+    protected $secret;
+    protected $currentOrder;
+    protected $currentInput;
+    protected $createSessionUlr = 'https://api-na.playground.klarna.com/payments/v1/sessions';
+    protected $createOrderUlr = 'https://api-na.playground.klarna.com/payments/v1/authorizations/{authorizationToken}/order';
+
+    public function __construct(
+        protected InvoiceRepository $invoiceRepository,
+        protected OrderRepository $orderRepository,
+    )
+    {
+        if ($this->getConfigData('mode') == 'live') {
+            $this->createSessionUlr = 'https://api.klarna.com/payments/v1/sessions';
+            $this->createOrderUlr = 'https://api.klarna.com/payments/v1/authorizations/{authorizationToken}/order';
+        }
+        $this->clientId = $this->getConfigData('client_id');
+        $this->apikey = $this->getConfigData('secret_id');
+    }
+
+
+    /**
+     * Get redirect url.
+     */
+    public function getRedirectUrl()
+    {
+    }
+    public function setOrder($order = null): self
+    {
+        $this->currentOrder = $order;
+        return $this;
+    }
+    public function getOrder()
+    {
+        return $this->currentOrder;
+    }
+
+    public function setInput($input = null): self
+    {
+        $this->currentInput = $input;
+        return $this;
+    }
+
+    public function getInput()
+    {
+        return $this->currentInput;
+    }
+    public function createGatewayOrder()
+    {
+        try {
+            return $this->createIntents($this->getOrder(), ['merchantOrderId' => $this->getOrder()->increment_id], $this->getInput());
+        } catch (\Exception $e) {
+            throw new \Exception($e->getMessage());
+        }
+    }
+
+    public function createIntents($order, $override, $input = null)
+    {
+        $shop = $order->shipping_address;
+        $bill = $order->billing_address;
+        $products = [];
+        foreach ($order->items as $item) {
+            $data = [
+                'name' => $item->name,
+                'unit_price' => (float) $item->price,
+                'quantity' => $item->qty_ordered,
+                'total_amount' => $item->qty_ordered * $item->price
+            ];
+            array_push($products, $data);
+        }
+        $grandTotal = round($order->grand_total, 2);
+        $data = [
+            'order_amount' => $grandTotal,
+            'merchant_reference1' => $override['merchantOrderId'],
+            'merchant_urls' => [
+                'confirmation_url' => $input->paymentSuccessUrl . '?orderId=' . $order->id,
+                'push_url' => $input->paymentSuccessUrl . '?orderId=' . $order->id,
+            ],
+            'order_lines' => $products,
+            'purchase_country' => $bill->country,
+            'purchase_currency' => $order->order_currency_code,
+            'shipping_address' => [
+                'given_name' => $shop->first_name,
+                'family_name' => $shop->last_name,
+                'email' => $order->customer_email,
+                'phone' => $shop->phone,
+                'street_address' => $shop->address,
+                'city' => $shop->city,
+                'postal_code' => $shop->postcode,
+                'region' => $shop->state,
+                'country' => $shop->country
+            ]
+        ];
+        $client = new Client();
+        $response = $client->request('POST', $this->createSessionUlr, [
+            'headers' => [
+                'Accept' => 'application/json',
+                'Content-Type' => 'application/json',
+                'Authorization' =>  'Basic '.base64_encode("{$this->clientId}:{$this->apikey}")
+            ],
+            'json' => $data,
+            'timeout' => 30,
+            'verify' => false
+        ]);
+        $responseBody = $response->getBody()->getContents();
+        Log::channel('payment')->info('klarna createIntents response', [
+            'order'  => $order->increment_id ?? null,
+            'status'    => $response->getStatusCode(),
+            'body'      => $responseBody,
+        ]);
+        $resultObject = json_decode($responseBody);
+        if (empty($resultObject->client_token)) {
+            throw new \Exception('klarna api is error');
+        }
+        return $resultObject->client_token;
+    }
+
+    /**
+     * 获取一个唯一的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 captureAndVerify($order, $authorizationToken)
+    {
+        if ($order->status != Order::STATUS_PENDING) {
+            return new \Exception('order status is error');
+        }
+        return $this->createOrder($order, $authorizationToken);
+    }
+
+    public function createOrder($order, $authorizationToken )
+    {
+        $products = [];
+        foreach ($order->items as $item) {
+            $data = [
+                'name' => $item->name,
+                'unit_price' => (float) $item->price,
+                'quantity' => $item->qty_ordered,
+                'total_amount' => $item->qty_ordered * $item->price
+            ];
+            array_push($products, $data);
+        }
+        $bill = $order->billing_address;
+        $data = [
+            'billing_address' => [
+                'given_name' => $bill->first_name,
+                'family_name' => $bill->last_name,
+                'email' => $bill->customer_email,
+                'phone' => $bill->phone,
+                'street_address' => $bill->address,
+                'city' => $bill->city,
+                'postal_code' => $bill->postcode,
+                'region' => $bill->state,
+                'country' => $bill->country
+            ],
+            'order_amount' => round($order->grand_total, 2),
+            'purchase_country' => $bill->country,
+            'purchase_currency' => $order->order_currency_code,
+            'order_lines' => $products
+        ];
+        $client = new Client();
+        $response = $client->request('POST', str_replace('{authorizationToken}', $authorizationToken, $this->createOrderUlr), [
+            'headers' => [
+                'Accept' => 'application/json',
+                'Content-Type' => 'application/json',
+                'Authorization' =>  'Basic '.base64_encode("{$this->clientId}:{$this->apikey}")
+            ],
+            'json' => $data,
+            'timeout' => 30,
+            'verify' => false
+        ]);
+        $responseBody = $response->getBody()->getContents();
+        Log::channel('payment')->info('klarna Create an order response', [
+            'data'     => $data,
+            'status'    => $response->getStatusCode(),
+            'body'      => $responseBody,
+        ]);
+
+        $resultObject = json_decode($responseBody);
+        if ($resultObject->fraud_status == 'ACCEPTED') {
+            return ['transaction_id' => $resultObject->order_id];
+        } else {
+            throw new \Exception('klarna Create an order  is error');
+        }
+    }
+    /**
+     * 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;
+        }
+        $info = $this->getOrder() ?: Cart::getCart();
+        if ($info && $billingCountry = $info->billing_address->country ?? false) {
+            $allowedCountries = ['AU', 'CA', 'NZ', 'GB', 'US'];
+            return in_array($billingCountry, $allowedCountries);
+        }
+        return true;
+    }
+}

+ 41 - 0
packages/Longyi/Pay/Klarna/src/Providers/KlarnaServiceProvider.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace Longyi\Pay\Klarna\Providers;
+
+use Illuminate\Support\ServiceProvider;
+
+class KlarnaServiceProvider extends ServiceProvider
+{
+    /**
+     * Register services.
+     */
+    public function register(): void
+    {
+        $this->registerConfig();
+    }
+
+    /**
+     * Bootstrap services.
+     */
+    public function boot(): void
+    {
+        // 加载路由
+        $this->loadRoutesFrom(__DIR__ . '/../Http/routes.php');
+    }
+
+    /**
+     * Register package config.
+     *
+     * @return void
+     */
+    protected function registerConfig()
+    {
+        $this->mergeConfigFrom(
+            dirname(__DIR__) . '/Config/payment-methods.php', 'payment_methods'
+        );
+
+        $this->mergeConfigFrom(
+            dirname(__DIR__) . '/Config/system.php', 'core'
+        );
+    }
+}