简体   繁体   English

Yii2 贝宝支付集成

[英]Yii2 paypal payment integration

I am using this https:\/\/www.yiiframework.com\/extension\/bitcko\/yii2-bitcko-paypal-api#usage<\/a> With yii2 to enable payments my code looks like this.我正在使用这个https:\/\/www.yiiframework.com\/extension\/bitcko\/yii2-bitcko-paypal-api#usage<\/a>使用 yii2 来启用付款,我的代码如下所示。

public function actionMakePayment(){
          if(!Yii::$app->user->getIsGuest()){
               // Setup order information array
              $params = [
                  'order'=>[
                      'description'=>'Payment description',
                      'subtotal'=>45,
                      'shippingCost'=>0,
                      'total'=>45,
                      'currency'=>'USD',
                  ]
              ];
            // In case of payment success this will return the payment object that contains all information about the order
            // In case of failure it will return Null

            Yii::$app->PayPalRestApi->processPayment($params);
        }else{
          Yii::$app->response->redirect(Url::to(['site/signup'], true));
        }

Update<\/strong>更新<\/strong>

Looks like the component class needs to be fully copied and edited before it can correctly override the checkOut()<\/code> method as the property $apiContext<\/code> accessed in the method is private<\/code> rather than being $protected<\/code> so either you copy that whole component and place it in you frontend\/components<\/code> directory and change it accordingly and then use.看起来组件类需要完全复制和编辑才能正确覆盖checkOut()<\/code>方法,因为在该方法中访问的属性$apiContext<\/code>是private<\/code>的而不是$protected<\/code>所以你要么复制整个组件并将其放入你frontend\/components<\/code>目录并相应地更改它然后使用。

Above all that class is poorly designed and written too, it would be better if you use the following component that i have been using in my Yii2 projects.最重要的是,该类的设计和编写也很糟糕,如果您使用我在 Yii2 项目中一直使用的以下组件会更好。 I havent removed the extra code and have pasted the file as is in the answer.我没有删除额外的代码并按照答案粘贴了文件。 you can remove\/comment the part related to the BalanceHistory<\/code> TransactionHistory<\/code> and the email part.您可以删除\/评论与BalanceHistory<\/code> TransactionHistory<\/code>和电子邮件部分相关的部分。 you need to install paypal checkout sdk via composer or add below in your composer.json<\/code>您需要通过 composer 安装 paypal checkout sdk 或在您的composer.json<\/code>中添加以下内容

"paypal\/paypal-checkout-sdk": "1.0.1"<\/code>

Paypal Component贝宝组件

<?php

namespace frontend\components;

use Yii;
use common\models\{
    User,
    BalanceHistory,
    TransactionHistory
};
use yii\base\Component;
use common\components\Helper;
use PayPalCheckoutSdk\Core\{
    PayPalHttpClient,
    SandboxEnvironment,
    ProductionEnvironment
};
use PayPalCheckoutSdk\Orders\{
    OrdersGetRequest,
    OrdersCreateRequest,
    OrdersCaptureRequest
};

class Paypal extends Component
{

    /**
     * The Pyapal Client Id
     *
     * @var mixed
     */
    public $clientId;

    /**
     * The Paypal client Secret
     *
     * @var mixed
     */
    public $clientSecret;

    /**
     * API context object
     *
     * @var mixed
     */
    private $httpClient; // paypal's http client

    /**
     * @var mixed
     */
    private $user_id;

    /**
     * Override Yii's object init()
     *
     * @return null
     */
    public function init()
    {
        $this->httpClient = new PayPalHttpClient(
            Yii::$app->params['paypal']['mode'] == 'sandbox' ?
                new SandboxEnvironment($this->clientId, $this->clientSecret) :
                new ProductionEnvironment($this->clientId, $this->clientSecret)
        );

        $this->user_id = Yii::$app->user->id;

        Yii::info("User: {$this->user_id} Init PayPal", 'paypal');
    }

    /**
     * Returns the context object
     *
     * @return object
     */
    public function getClient()
    {
        return $this->httpClient;
    }

    /**
     * Set the payment methods and other objects necessary for making the payment
     *
     * @param decimal $price the amount to be charged
     *
     * @return string $approvalUrl
     */
    public function createOrder($price)
    {
        //create order request
        $request = new OrdersCreateRequest();
        $request->prefer('return=representation');

        setlocale(LC_MONETARY, 'en_US.UTF-8');

        $price = sprintf('%01.2f', $price);

        Yii::info("User: {$this->user_id} Setting payment for amount: {$price}", 'paypal');

        //build the request body
        $requestBody = [
            'intent' => 'CAPTURE',
            'purchase_units' =>
            [
                0 =>
                [
                    'amount' =>
                    [
                        'currency_code' => 'USD',
                        'value' => $price,
                    ],
                ],
            ],
            'application_context' => [
                'shipping_preference' => 'NO_SHIPPING'
            ]
        ];

        $request->body = $requestBody;

        //call PayPal to set up a transaction
        $client = $this->getClient();
        $response = $client->execute($request);

        return json_encode($response->result, JSON_PRETTY_PRINT);
    }

    /**
     * @param $orderId
     */
    public function getOrder($orderId)
    {

        // 3. Call PayPal to get the transaction details
        $request = new OrdersGetRequest($orderId);
        $client = $this->getClient();
        $response = $client->execute($request);

        return json_encode($response->result, JSON_PRETTY_PRINT);
    }

    /**
     * Retrieves Order Capture Details for the given order ID
     *
     * @param string $orderId the payment id of the transaction
     *
     * @return mixed
     */
    public function captureOrder($orderId)
    {
        $request = new OrdersCaptureRequest($orderId);
        //Call PayPal to capture an authorization
        $client = $this->getClient();

        $transaction = Yii::$app->db->beginTransaction();
        try {
            $response = $client->execute($request);

            //get payment variables for email
            $paymentId = $response->result->id;
            $paymentStatus = $response->result->status;
            $paypalTransaction = $response->result->purchase_units[0]->payments->captures[0];
            $payedAmount = $paypalTransaction->amount->value;
            $txnId = $paypalTransaction->id;
            $userId = $this->user_id;

            //get the user
            $model = User::findOne($userId);
            $profile = $model->businessProfile;
            $prevBalance = $profile->balance;

            if ($paymentStatus == 'COMPLETED') {
                Yii::info("User: {$userId} payment amount:{$payedAmount} approved updating balance.", 'paypal');
                //update balance
                $newBalance = $profile->updateBalance($payedAmount);

                Yii::info("User: {$userId} balance updated.", 'paypal');

                $data = [
                    'amount' => $payedAmount,
                    'type' => TransactionHistory::BALANCE_ADDED,
                    'description' => "Funds added to account",
                    'user' => [
                        'id' => $userId,
                        'balance' => $newBalance,
                    ],
                ];

                Yii::info("User: {$userId} adding transaction history.", 'paypal');

                TransactionHistory::add($data);

                //update subscription status if required
                if ($profile->subscription_status !== 'active') {
                    $profile->updateStatus('active');
                }

                Yii::info("User: {$userId} adding balance history:{$payedAmount}.", 'paypal');

                //send the success email to the user and admin
                $this->sendNotification($model, $response->result);

                //set session flash with success
                Yii::$app->session->setFlash(
                    'success',
                    'Your Payment is processed and you will receive an email with the details shortly'
                );
            } else {
                Yii::warning("User: {$userId} payment amount:{$payedAmount} NOT approved.", 'paypal');
                //send the error email to the user and admin

                $this->sendNotification($model, $response->result, 'error');
                //set session flash with error
                Yii::$app->session->setFlash(
                    'danger',
                    'Your Payment was not approved, an email has been sent with the details.'
                );
            }

            //update balance history
            BalanceHistory::add(
                $profile->user_id,
                $prevBalance,
                $payedAmount,
                $paymentId,
                $paymentStatus,
                $txnId,
                $response
            );

            //commit the transaction
            $transaction->commit();

            Yii::info(
                "User: {$userId} payment Success prevBalance: {$prevBalance} payedAmount:{$payedAmount}.",
                'paypal'
            );
            return json_encode($response->result, JSON_PRETTY_PRINT);
        } catch (\Exception $e) {
            //roll back the transaction
            $transaction->rollBack();

            Yii::error("ERROR EXCEPTION", 'paypal');
            Yii::error($e->getMessage(), 'paypal');
            Yii::error($e->getTraceAsString(), 'paypal');

            //send error email to the developers
            Helper::sendExceptionEmail(
                "TC : Exception on PayPal Balance",
                $e->getMessage(),
                $e->getTraceAsString()
            );

            //set session flash with error
            Yii::$app->session->setFlash('danger', $e->getMessage());
        }
    }

    /**
     * Sends Success Email for the transaction
     *
     * @param \common\models\User $model the user model object
     * @param  $response the paypal Order Capture object
     * @param string $type the type of the notification to be sent
     *
     * @return null
     */
    public function sendNotification(
        \common\models\User $model,
        $response,
        $type = 'success'
    ) {
        Yii::info("User: {$this->user_id} Sending notifications type:{$type}", 'paypal');

        $paymentId = $response->id;
        $paymentStatus = $response->status;
        $paypalTransaction = $response->purchase_units[0]->payments->captures[0];
        $payedAmount = $paypalTransaction->amount->value;

        //payment creation time
        $paymentCreateTime = new \DateTime(
            $paypalTransaction->create_time,
            new \DateTimeZone('UTC')
        );

        //payment update time
        $paymentUpdateTime = new \DateTime(
            $paypalTransaction->update_time,
            new \DateTimeZone('UTC')
        );

        //payer/billing info for email
        $payerInfo = $response->payer;
        $payerEmail = $payerInfo->email_address;
        $payerFirstName = $payerInfo->name->given_name;
        $payerLastName = $payerInfo->name->surname;
        $billingInfo = [
            'billing_info' => [
                'email' => $payerEmail,
                'full_name' => "$payerFirstName $payerLastName",
            ],
        ];

        if (property_exists($response->purchase_units[0], 'shipping')) {
            $payerAddress = property_exists($response->purchase_units[0]->shipping->address, 'address_line_1');
            $isStateAvailable = property_exists($response->purchase_units[0]->shipping->address, 'admin_area_1');
            $isPostCodeAvailable = property_exists($response->purchase_units[0]->shipping->address, 'postal_code');
            $iscountryCodeAvailable = property_exists($response->purchase_units[0]->shipping->address, 'country_code');
            //@codingStandardsIgnoreStart
            $payerState =  $isStateAvailable ? $response->purchase_units[0]->shipping->address->admin_area_1 : 'NA';
            $payerPostalCode = $isPostCodeAvailable ? $response->purchase_units[0]->shipping->address->postal_code : 'NA';
            $payerCountryCode = $iscountryCodeAvailable ? $response->purchase_units[0]->shipping->address->country_code : 'NA';
            //@codingStandardsIgnoreEnd
            $billingInfo['billing_info'] = array_merge(
                $billingInfo['billing_info'],
                [
                    'address' => $payerAddress,
                    'state' => $payerState,
                    'country' => $payerCountryCode,
                    'post_code' => $payerPostalCode,
                ]
            );
        }

        //email params
        $data = [
            'user' => [
                'email' => $model->email,
                'name' => $model->username,
            ],
            'payment_id' => $paymentId,
            'amount' => $payedAmount,
            'status' => $paymentStatus,
            'create_time_utc' => $paymentCreateTime,
            'update_time_utc' => $paymentUpdateTime,
        ];

        $data = array_merge($data, $billingInfo);

        //check the notification email type and set params accordingly
        if ($type == 'success') {
            $txnId = $paypalTransaction->id;
            $data['txn_id'] = $txnId;
            $subject = Yii::$app->id . ': Your Account has been recharged.';
            $view = '@frontend/views/user/mail/payment-complete';
        } else {
            $subject = Yii::$app->id . ': Transaction failed.';
            $view = '@frontend/views/user/mail/payment-failed';
        }

        Yii::info("User: {$this->user_id} Sending email to user:{$model->email} type: {$type}", 'paypal');
        //send email to user
        $model->sendEmail($subject, $view, $data, $model->email);

        //send notification to admin for Payment Received
        $data['user']['email'] = Yii::$app->params['adminEmail'];

        $subject = ($type == 'success') ?
            Yii::$app->id . ': New Transaction in Account.' :
            Yii::$app->user->id . ': A Transaction Failed for the user.';

        Yii::info(
            "User: {$this->user_id} Sending email to admin " . Yii::$app->params['adminEmail'] . " type: {$type}",
            'paypal'
        );
        //send admin email
        $model->sendEmail($subject, $view, $data, Yii::$app->params['adminEmail']);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM