woocommerce-vs-magento-2
WooCommerce VS Magento ¿Cuál es la mejor plataforma eCommerce?
20 septiembre, 2018
¿Qué es el blockchain y para qué sirve?
¿Qué es el blockchain y para qué sirve?
20 noviembre, 2018
Mostrar todos

Como Crear una pasarela de pago en Magento 2

Configuración del módulo

La configuración del Módulo se hace dentro de la  carpeta de app/code crearemos nuestro espacio de carpetas. Al final nuestra estructura de archivos/carpetas se vería así:

Estructura de carpeta de la raya

Antes de continuar, hay una cosa más que debe ser atendida. Stripe viene con su propio conjunto de bibliotecas PHP para la integración, y también deben incluirse. Esto, sin embargo, debe ser gestionado por Composer. Si echa un vistazo a composer.json , notará línea requerida . Al instalar esta extensión se muestra a través del compositor, la biblioteca Stripe se colocará en la carpeta vendor/stripe y estará disponible a través del autoloader en nuestro código.

El siguiente gran cambio se ha introducido en los archivos de configuración XML. Magento 2 ha introducido un esquema XML para cada tipo de configuración que se debe seguir, o de lo contrario el módulo no funcionará. El primero que crearemos es module.xml que reemplaza la configuración que se colocó anteriormente en app/etc/modules/namespace_modulename.xml . Se utiliza para declarar el módulo y sus dependencias:

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

Implementación de pago

Hasta ahora, hemos creado nuestra estructura de archivos de módulos, hemos creado archivos de configuración de módulos y hemos integrado nuestros archivos de biblioteca. Ahora es el momento de proceder con la integración de pago.
Cualquiera que haya integrado la pasarela de pago en Magento sabe la importancia de implementar la configuración de administración adecuada, ya que el sistema manejará la mayoría de las cosas automáticamente. Veamos nuestro archivo  etc/adminhtml/system.xml :

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../Magento/Config/etc/system_file.xsd"><br />
    <system></p>
<section id="payment">
            <group id="inchoo_stripe" translate="label" type="text" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1"><br />
                <label>Stripe</label><br />
                <comment><br />
                    <!&#91;CDATA&#91;<a href="https://stripe.com/" target="_blank">Click here to sign up for Stripe account</a>&#93;&#93;><br />
                </comment><br />
                <field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0"><br />
                    <label>Enabled</label><source_model>Magento\Config\Model\Config\Source\Yesno</source_model><br />
                </field><br />
                <field id="title" translate="label" type="text" sortOrder="2" showInDefault="1" showInWebsite="1" showInStore="1"><br />
                    <label>Title</label><br />
                </field><br />
                <field id="api_key" translate="label" type="obscure" sortOrder="3" showInDefault="1" showInWebsite="1" showInStore="0"><br />
                    <label>Api Key</label><br />
                    <backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model><br />
                </field><br />
                <field id="debug" translate="label" type="select" sortOrder="4" showInDefault="1" showInWebsite="1" showInStore="0"><br />
                    <label>Debug</label><source_model>Magento\Config\Model\Config\Source\Yesno</source_model><br />
                </field><br />
                <field id="cctypes" translate="label" type="multiselect" sortOrder="5" showInDefault="1" showInWebsite="1" showInStore="0"><br />
                    <label>Credit Card Types</label><source_model>Inchoo\Stripe\Model\Source\Cctype</source_model><br />
                </field><br />
                <field id="sort_order" translate="label" type="text" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="0"><br />
                    <label>Sort Order</label><br />
                </field><br />
                <field id="allowspecific" translate="label" type="allowspecific" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="0"><br />
                    <label>Payment from Applicable Countries</label><source_model>Magento\Payment\Model\Config\Source\Allspecificcountries</source_model><br />
                </field><br />
                <field id="specificcountry" translate="label" type="multiselect" sortOrder="51" showInDefault="1" showInWebsite="1" showInStore="0"><br />
                    <label>Payment from Specific Countries</label><source_model>Magento\Directory\Model\Config\Source\Country</source_model><br />
                </field><br />
                <field id="min_order_total" translate="label" type="text" sortOrder="98" showInDefault="1" showInWebsite="1" showInStore="0"><br />
                    <label>Minimum Order Total</label><br />
                </field><br />
                <field id="max_order_total" translate="label" type="text" sortOrder="99" showInDefault="1" showInWebsite="1" showInStore="0"><br />
                    <label>Maximum Order Total</label><br />
                    <comment>Leave empty to disable limit</comment><br />
                </field><br />
            </group><br />
        </section>
<p>    </system><br />
</config><br />

Solo hay tres campos que debemos manejar a través de nuestro código: api_key , min_order_total y max_order_total . Como dije anteriormente, Magento manejará el resto a través de clases abstractas por defecto.

Hablando de clases, finalmente es hora de implementar nuestra clase de Pago. Debido a la naturaleza de Stripe, estaremos extendiendo \Magento\Payment\Model\Method\Cc . Además de configurar la configuración habitual a través de variables protegidas, también tenemos que pasar la biblioteca Stripe a nuestra clase para respetar la inyección de dependencias y la capacidad de prueba. Por lo tanto comenzaremos nuestra clase con el siguiente fragmento de código:

namespace Inchoo\Stripe\Model;</p>
<p>class Payment extends \Magento\Payment\Model\Method\Cc<br />
{<br />
    const CODE = 'inchoo_stripe';</p>
<p>    protected $_code = self::CODE;</p>
<p>    protected $_isGateway                   = true;<br />
    protected $_canCapture                  = true;<br />
    protected $_canCapturePartial           = true;<br />
    protected $_canRefund                   = true;<br />
    protected $_canRefundInvoicePartial     = true;</p>
<p>    protected $_stripeApi = false;</p>
<p>    protected $_countryFactory;</p>
<p>    protected $_minAmount = null;<br />
    protected $_maxAmount = null;<br />
    protected $_supportedCurrencyCodes = array('USD');</p>
<p>    protected $_debugReplacePrivateDataKeys = ['number', 'exp_month', 'exp_year', 'cvc'];</p>
<p>    public function __construct(<br />
        \Magento\Framework\Model\Context $context,<br />
        \Magento\Framework\Registry $registry,<br />
        \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,<br />
        \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory,<br />
        \Magento\Payment\Helper\Data $paymentData,<br />
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,<br />
        \Magento\Payment\Model\Method\Logger $logger,<br />
        \Magento\Framework\Module\ModuleListInterface $moduleList,<br />
        \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,<br />
        \Magento\Directory\Model\CountryFactory $countryFactory,<br />
        \Stripe\Stripe $stripe,<br />
        array $data = array()<br />
    ) {<br />
        parent::__construct(<br />
            $context,<br />
            $registry,<br />
            $extensionFactory,<br />
            $customAttributeFactory,<br />
            $paymentData,<br />
            $scopeConfig,<br />
            $logger,<br />
            $moduleList,<br />
            $localeDate,<br />
            null,<br />
            null,<br />
            $data<br />
        );</p>
<p>        $this->_countryFactory = $countryFactory;</p>
<p>        $this->_stripeApi = $stripe;<br />
        $this->_stripeApi->setApiKey(<br />
            $this->getConfigData('api_key')<br />
        );</p>
<p>        $this->_minAmount = $this->getConfigData('min_order_total');<br />
        $this->_maxAmount = $this->getConfigData('max_order_total');<br />
    }<br />

Continuemos con la implementación de nuestra función más importante, capture() :

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

Como de costumbre, buscaremos información de facturación a través del objeto de payment . La información de la tarjeta de crédito se pasa a la API Stripe que se encarga del resto. En caso de éxito, agregaremos esta transacción a la lista de transacciones de Magento, y básicamente hemos terminado aquí. Es importante tener en cuenta que el ID de transacción debe configurarse como el ID de transacción recibido por la pasarela de pago, ya que se usará más adelante.

Otra característica importante del método de pago es la capacidad de emitir un reembolso del administrador de Magento. Así que vamos a proceder e implementar nuestra función de refund() :

/**<br />
 * Payment refund<br />
 *<br />
 * @param \Magento\Payment\Model\InfoInterface $payment<br />
 * @param float $amount<br />
 * @return $this<br />
 * @throws \Magento\Framework\Validator\Exception<br />
 */<br />
public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount)<br />
{<br />
  $transactionId = $payment->getParentTransactionId();</p>
<p>  try {<br />
      \Stripe\Charge::retrieve($transactionId)->refund();<br />
  } catch (\Exception $e) {<br />
      $this->debugData(['transaction_id' => $transactionId, 'exception' => $e->getMessage()]);<br />
      $this->_logger->error(__('Payment refunding error.'));<br />
      throw new \Magento\Framework\Validator\Exception(__('Payment refunding error.'));<br />
  }</p>
<p>  $payment<br />
      ->setTransactionId($transactionId . '-' . \Magento\Sales\Model\Order\Payment\Transaction::TYPE_REFUND)<br />
      ->setParentTransactionId($transactionId)<br />
      ->setIsTransactionClosed(1)<br />
      ->setShouldCloseParentTransaction(1);</p>
<p>  return $this;<br />
}<br />

Básicamente, estamos obteniendo el ID de la transacción, que luego se pasa a la API que maneja las comunicaciones de reembolso. Todo lo que necesitamos hacer aquí es manejar adecuadamente los errores y marcar las transacciones. Y sí, al manejar los errores me refiero a lanzar Excepción desde el bloque catch interno, para notificar un error a Magento. La razón para el bloque try..catch en primer lugar fue para limpiar los datos, ya que la respuesta del servidor podría tener información confidencial. Esto también se aplica a la funcionalidad de captura.

En Magento 2, el proceso de pago se ha reescrito como una aplicación del lado del cliente JS, que se comunica con el sistema central a través de la API. Teniendo en cuenta eso, la parte de PHP en sí no es suficiente para que la integración funcione. Continuaremos agregando dos archivos JS más a través de la  actualización de diseño XML (ver enlace, es demasiado grande para ser listado aquí). Se han agregado los siguientes archivos:

Descargar Archivo del tutorial

Cotiza Ahora

Lima, Perú

Calle Grimaldo del Solar 162, Oficina 807
Miraflores, Lima
+51 6057735
+51 970771094

New York, USA

70 E 116 St Manhattan, NY 10029
Cel: +1 347-531-7864
Tel: +1 212-860-3202

Los Angeles, USA

9454 Rendalia St. Bellflower,
Los Angeles, California, 90706
Tel: +1 (562) 616-4315

Valencia, España

Carrer de José Iturbi, 1,
46950 Xirivella, Valencia
Cel: +34 605839188

Yucatan, México

Calle 33ᴮ 544
García Ginerés
97070 Mérida, Yuc.
Tel: +52 9993541743

Buenos Aires, Argentina

Avenida Constituyentes 4457,
Piso 6 Dpto4
Cel: +54 1134121888

Montevideo, Uruguay

Saldanha da Gama
622 oficina 312
Tel: +598 26226350
Cel 1: +598 097542294
Cel 2: +598 097496911

Vex Soluciones es una reconocida empresa tecnológica dedicado a la venta de productos y servicios de software como: Aulas Virtuales, Tiendas Virtuales Online, Desarrollo de Software a medida, Apps Moviles para Android e iOS, ERP / CRM, Realidad Virtual, Realidad Aumentada Inteligencia Artificial, Inteligencia de Negocios con presencia internacional. Perú, España, USA, Canada, México, Chile, Colombia, Argentina, Uruguay, Bolivia, Costa Rica, Puerto Rico, Republica Dominicana, Ecuador.