SimpleMagento - Magento tutorials, tips and discussions with simplicity in mind
  • Magento 2
  • Frontend
  • Dev Talk
  • Checkout
  • UI components
  • Online Marketing
  • eCommerce Talk
  • Magento 2
  • Frontend
  • Dev Talk
  • Checkout
  • UI components
  • Online Marketing
  • eCommerce Talk
SimpleMagento - Magento tutorials, tips and discussions with simplicity in mind
No Result
View All Result
Home Integration

Implementing payment gateway in Magento 2 – Sample 1

by freelancer
April 22, 2022
0 0
Share on FacebookShare on Twitter

This is a revised article initially written in September 2014 once I began to play with Magento 2 for the primary time. Since there have been numerous adjustments in Magento 2, this article additionally needed some refreshment. We will look over the backend, and proceed with the development of a easy module. For this activity, I picked up the payment gateway API integration. This comparatively easy activity will assist us display some key adjustments in Magento 2.

More exactly, we can be specializing in implementation of Stripe payment gateway. Even although Stripe has a wealthy set of options, right here we can be focusing solely on most elementary functionalities to get you began with Magento 2 extension development.

NOTE: Magento 2 source code is underneath fixed adjustments. Although code was examined on early Magento 2.1., it’s now outdated. Stay tuned for an replace.

Module setup

As you in all probability already know, lots has modified in Magento 2, and Module setup and code structure just isn’t an exception. One of the primary issues you will discover is absence of code pools that we’re used to from earlier version. Inside the app/code folder we’ll create our namespace folder. In the tip, our file/folder structure would seem like this:

Stripe folder structure

Before we proceed, there’s another factor that must be taken care of. Stripe comes with its own set of PHP libraries for integration, and so they must be included as properly. This, nevertheless, ought to be managed by Composer. If you check out composer.json, you will discover require line. By putting in this pattern extension by means of composer, Stripe library can be positioned underneath vendor/stripe folder, and can be out there by means of autoloader in our code.

Next huge change has been launched in XML configuration files. Magento 2 has launched XML scheme for every configuration type that must be adopted, or in any other case the module won’t work. First one that we are going to create, is module.xml that replaces configuration which was beforehand positioned underneath app/etc/modules/namespace_modulename.xml. As in magento 1, it’s used to declare module and its dependencies:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd">
    <module name="Simplemagento_Stripe" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Sales" />
            <module name="Magento_Payment" />
            <module name="Magento_Directory" />
            <module name="Magento_Config" />
        </sequence>
    </module>
</config>

There are additionally some adjustments in different config files, however I’ll let you have enjoyable exploring them yourselves.

Payment implementation

So far, we have now created our module file structure, we have now created module configuration files and we have now built-in our library files. It is now time to proceed with the payment integration.
Anyone who built-in payment gateway in Magento is aware of the significance of implementing correct admin settings, for the reason that system will deal with a lot of the issues mechanically. Lets check out our etc/adminhtml/system.xml file:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../Magento/Config/etc/system_file.xsd">
    <system>
        <section id="payment">
            <group id="Simplemagento_stripe" translate="label" type="text" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>Stripe</label>
                <comment>
                    <![CDATA[<a href="https://stripe.com/" target="_blank">Click here to sign up for Stripe account</a>]]>
                </comment>
                <field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" presentInWebsite="1" showInStore="0">
                    <label>Enabled</label>
                    <source_model>MagentoConfigModelConfigSourceYesno</source_model>
                </field>
                <field id="title" translate="label" type="text" sortOrder="2" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Title</label>
                </field>
                <field id="api_key" translate="label" type="obscure" sortOrder="3" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Api Key</label>
                    <backend_model>MagentoConfigModelConfigBackendEncrypted</backend_model>
                </field>
                <field id="debug" translate="label" type="select" sortOrder="4" showInDefault="1" presentInWebsite="1" showInStore="0">
                    <label>Debug</label>
                    <source_model>MagentoConfigModelConfigSourceYesno</source_model>
                </field>
                <field id="cctypes" translate="label" type="multiselect" sortOrder="5" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Credit Card Types</label>
                    <source_model>SimplemagentoStripeModelSourceCctype</source_model>
                </field>
                <field id="sort_order" translate="label" type="text" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Sort Order</label>
                </field>
                <field id="allowspecific" translate="label" type="allowspecific" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Payment from Applicable Countries</label>
                    <source_model>MagentoPaymentModelConfigSourceAllspecificcountries</source_model>
                </field>
                <field id="specificcountry" translate="label" type="multiselect" sortOrder="51" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Payment from Specific Countries</label>
                    <source_model>MagentoDirectoryModelConfigSourceCountry</source_model>
                </field>
                <field id="min_order_total" translate="label" type="text" sortOrder="98" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Minimum Order Total</label>
                </field>
                <field id="max_order_total" translate="label" type="text" sortOrder="99" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Maximum Order Total</label>
                    <comment>Leave empty to disable limit</comment>
                </field>
            </group>
        </section>
    </system>
</config>

There are solely three fields that we need to deal with by means of our code: api_key, min_order_total and max_order_total. As I beforehand mentioned, Magento will deal with the remaining by means of abstract classes by default.

Speaking of classes, it’s lastly time to implement our Payment class. Due to the character of Stripe, we can be extending MagentoPaymentModelMethodCc. Besides setting common config by means of protected variables, we additionally need to go Stripe library to our class to respect dependency injection and testability. Therefore we’ll start our class with the next snippet:

namespace SimplemagentoStripeModel;
 
class Payment extends MagentoPaymentModelMethodCc
{
    const CODE = 'Simplemagento_stripe';
 
    protected $_code = self::CODE;
 
    protected $_isGateway                   = true;
    protected $_canCapture                  = true;
    protected $_canCapturePartial           = true;
    protected $_canRefund                   = true;
    protected $_canRefundInvoicePartial     = true;
 
    protected $_stripeApi = false;
 
    protected $_countryFactory;
 
    protected $_minAmount = null;
    protected $_maxAmount = null;
    protected $_supportedCurrencyCodes = array('USD');
 
    protected $_debugReplacePrivateDataKeys = ['number', 'exp_month', 'exp_year', 'cvc'];
 
    public function __construct(
        MagentoFrameworkModelContext $context,
        MagentoFrameworkRegistry $registry,
        MagentoFrameworkApiExtensionAttributesFactory $extensionFactory,
        MagentoFrameworkApiAttributeValueFactory $customAttributeFactory,
        MagentoPaymentHelperData $paymentData,
        MagentoFrameworkAppConfigScopeConfigInterface $scopeConfig,
        MagentoPaymentModelMethodLogger $logger,
        MagentoFrameworkModuleModuleListInterface $moduleList,
        MagentoFrameworkStdlibDateTimeTimezoneInterface $localeDate,
        MagentoDirectoryModelCountryFactory $countryFactory,
        StripeStripe $stripe,
        array $data = array()
    ) 
        parent::__construct(
            $context,
            $registry,
            $extensionFactory,
            $customAttributeFactory,
            $paymentData,
            $scopeConfig,
            $logger,
            $moduleList,
            $localeDate,
            null,
            null,
            $data
        );
 
        $this->_countryFactory = $countryFactory;
 
        $this->_stripeApi = $stripe;
        $this->_stripeApi->setApiKey(
            $this->getConfigData('api_key')
        );
 
        $this->_minAmount = $this->getConfigData('min_order_total');
        $this->_maxAmount = $this->getConfigData('max_order_total');
    

At this level, we have now covered nearly all variations in module development between Magento 2 and 1. From this level on, a lot of the code can be the identical between these two variations, so far as our Stripe integration is anxious.

Lets proceed with implementation of our most vital function, seize():

/**
 * Payment capturing
 *
 * @param MagentoPaymentModelInfoInterface $payment
 * @param float $amount
 * @return $this
 * @throws MagentoFrameworkValidatorException
 */
public function capture(MagentoPaymentModelInfoInterface $payment, $amount)
{
  //throw new MagentoFrameworkValidatorException(__('Inside Stripe, throwing donuts :]'));
 
  /** @var MagentoSalesModelOrder $order */
  $order = $payment->getOrder();
 
  /** @var MagentoSalesModelOrderAddress $billing */
  $billing = $order->getBillingAddress();
 
  try 
      $requestData = [
          'amount'        => $amount * 100,
          'currency'      => strtolower($order->getBaseCurrencyCode()),
          'description'   => sprintf('#%s, %s', $order->getIncrementId(), $order->getCustomerEmail()),
          'card'          => [
              'number'            => $payment->getCcNumber(),
              'exp_month'         => sprintf('%02d',$payment->getCcExpMonth()),
              'exp_year'          => $payment->getCcExpYear(),
              'cvc'               => $payment->getCcCid(),
              'name'              => $billing->getName(),
              'address_line1'     => $billing->getStreetLine(1),
              'address_line2'     => $billing->getStreetLine(2),
              'address_city'      => $billing->getCity(),
              'address_zip'       => $billing->getPostcode(),
              'address_state'     => $billing->getRegion(),
              'address_country'   => $billing->getCountryId(),
              // To get full localized country name, use this instead:
              // 'address_country'   => $this->_countryFactory->create()->loadByCode($billing->getCountryId())->getName(),
          ]
      ];
 
      $charge = StripeCharge::create($requestData);
      $payment
          ->setTransactionId($charge->id)
          ->setIsTransactionClosed(0);
 
   catch (Exception $e) {
      $this->debugData(['request' => $requestData, 'exception' => $e->getMessage()]);
      $this->_logger->error(__('Payment capturing error.'));
      throw new MagentoFrameworkValidatorException(__('Payment capturing error.'));
  }
 
  return $this;
}

As common, we’ll fetch billing info by means of payment object. Credit card information is than handed to Stripes API which handles the remaining. In case of success, we’ll add this transaction to Magento’s list of transactions, and we’re principally finished right here. It is vital to notice right here, that transaction id ought to be set to transaction ID obtained by the payment gateway, since this can be used in a while.

Another vital function for payment method is potential to challenge a refund from Magento admin. So lets proceed and implement our refund() function:

/**
 * Payment refund
 *
 * @param MagentoPaymentModelInfoInterface $payment
 * @param float $amount
 * @return $this
 * @throws MagentoFrameworkValidatorException
 */
public function refund(MagentoPaymentModelInfoInterface $payment, $amount)
{
  $transactionId = $payment->getParentTransactionId();
 
  try {
      StripeCharge::retrieve($transactionId)->refund();
  } catch (Exception $e) {
      $this->debugData((*2*));
      $this->_logger->error(__('Payment refunding error.'));
      throw new MagentoFrameworkValidatorException(__('Payment refunding error.'));
  }
 
  $payment
      ->setTransactionId($transactionId . '-' . MagentoSalesModelOrderPaymentTransaction::TYPE_REFUND)
      ->setParentTransactionId($transactionId)
      ->setIsTransactionClosed(1)
      ->setShouldCloseParentTransaction(1);
 
  return $this;
}

Basically, we’re fetching transaction ID, which is then handed to API which handles refund communications. All we need to do right here is to correctly deal with errors and mark transactions. And sure, by dealing with errors I do imply throwing Exception from inside catch block, in order to inform Magento of an error. Reason for try..catch block in the primary place was to sanitize data, since response from server may need delicate info. This additionally applies to seize performance.

In Magento 2, checkout has been rewritten as JS consumer facet application, that’s speaking with core system by means of API. Considering that, PHP half itself just isn’t sufficient for integration to work. We will proceed by including two extra JS files by means of layout update XML(verify hyperlink, it’s to massive to be listed right here). Following files have been added:

  • view/frontend/web/js/view/payment/stripe-payments.js
  • view/frontend/web/js/view/payment/method-renderer/stripe-method.js

Their goal is to offer configuration for UI part used in checkout. For now, we’ll go away like that, explaining how this works, requires its own article.

And that’s principally it. There could also be just a few extra issues to tune up, however our module is prepared. Full code may be retrieved at our GIT repository here. An don’t overlook to regulate our repository. We plan to implement integration with tokens to keep away from sending bank card information to server.

So far we have now covered a lot of the basic items which can be required for module development. However, our module is absolutely easy: it lacks any template files, controllers, blocks, composer config, etc. But we’ll cover all that in our future articles. This is only a warmup to get you began. I hope it was helpful, and that you just loved studying it.

Tags: ProgrammingIntegrationMagento 2 PaymentMagento 2
Previous Post

Routing in Magento 2 – Sample 1

Next Post

Implementing payment gateway in Magento 2 Spinned – Sample 1

freelancer

freelancer

Related Posts

Magento 2

Implementing payment gateway in Magento 2 – Sample 1

April 22, 2022
Magento 2

Implementing payment gateway in Magento 2 Spinned – Sample 1

April 22, 2022
Magento 2

Routing in Magento 2 – Sample 1

April 22, 2022
MVC Magento 2

Magento 2 Controllers – Sample 1

April 22, 2022
Magento 2

How to create a basic module in Magento 2 – Sample 1

April 22, 2022
Frontend

Magento 2 frontend architecture – Sample 1

April 22, 2022

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Categories

  • Administration
  • Search
  • Configuration
  • Starting Up
  • Extensions
  • News
  • PWA
  • Magento 2 API
  • Programming
  • MVC Magento 2
  • UX/UI Design
  • Shipping Magento 2
  • Database
  • Magento 2 Payment
  • Magento 2
  • Cache
  • Frontend
  • Integration
  • Dev Talk
  • Life at Inchoo
  • Checkout
  • Tips
  • UI components
  • Products
  • Online Marketing
  • Debugging
  • Magento
  • Search Magento 2
  • Upgrading Magento 2
  • Marketing
  • eCommerce Talk
  • Events & Observers
  • Uncategorized

Popular Post

Frontend

Magento 2 frontend architecture – Sample 1

April 22, 2022
UX/UI Design

Magento 2 Luma Theme Under The Scope

March 27, 2022
Integration

Implementing payment gateway in Magento 2 – Sample 1

April 22, 2022
Magento 2

Moving the validation error message, this time globally

March 25, 2022
No Result
View All Result
[vc_row full_width="stretch_row" vc_row_background="" css=".vc_custom_1516082354216{margin-top: 30px !important;padding-top: 22px !important;padding-bottom: 22px !important;}"][vc_column el_class=".footer_center" offset="vc_col-lg-offset-3 vc_col-lg-6"]
[vc_empty_space height="15px"][vc_column_text css=".vc_custom_1516083863519{margin-bottom: 0px !important;}" el_class=".copyright"]Copyright © 2018 JNews. Photography Blog theme by Jegtheme.[/vc_column_text][/vc_column][/vc_row]
No Result
View All Result
  • Magento 2
  • Frontend
  • Dev Talk
  • Checkout
  • UI components
  • Online Marketing
  • eCommerce Talk

© 2023 JNews - Premium WordPress news & magazine theme by Jegtheme.

Welcome Back!

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In