API Magento - кредит-нота по счету-фактуре


Я использую magento soap api версии 2. С помощью api я могу успешно создавать кредитные заметки, и они отлично отображаются в бэкэнде magento. Они не отображаются в песочнице моих платежных систем, и я боюсь, что это потому, что они являются "автономными возвратами".

В интерфейсе magento, когда вы создаете кредит-ноту по заказу, это "автономный возврат". Вы должны создать кредит-ноту в счете-фактуре, чтобы возврат был "онлайн-возвратом", и фактически перейти до вашего процессора.

Поэтому я направился к документации и увидел, что нет аргумента для передачи номера счета. Вы можете создавать кредит-ноты только для заказа. Так что, возможно, я пропустил это, и есть способ сделать это в счете-фактуре. Или, может быть, я могу передать другой аргумент через api, чтобы принудительно вернуть деньги онлайн?

ВОПРОС Есть ли способ сделать онлайн-возврат средств (кредит-нота) через api?

Author: RightClick, 2015-06-05

3 answers

Изначально API Magento не поддерживает онлайн-возврат средств. Вы должны создать его локальную версию, которая реализует некоторые методы, которые обычно вызываются только при привлечении кредитных нот в администраторе.

Если вы не хотите читать логику этих изменений и вам просто нужно решение, прокрутите вниз до раздела TL;DR ниже.

Во-первых, давайте переопределим действие создания API кредитных нот. Предполагая, что у вас есть пользовательский модуль продаж для вашего переопределяет, вы добавите эту перезапись в его конфигурацию:

app/code/local/Mycompany/Sales/etc/config.xml :

<models>
    <sales>
        <rewrite>
            <order_creditmemo_api>Mycompany_Sales_Model_Order_Creditmemo_Api</order_creditmemo_api>
        </rewrite>
    </sales>
</models>

Затем давайте расширим эту модель и ее создадим метод:

app/code/local/Mycompany/Sales/Model/Order/Creditmemo/Api.php

<?php
class Mycompany_Sales_Model_Order_Creditmemo_Api extends Mage_Sales_Model_Order_Creditmemo_Api
{
    public function create($orderIncrementId, $creditmemoData = null, $comment = null, $notifyCustomer = false,
                           $includeComment = false, $refundToStoreCreditAmount = null)
    {
        /** @var $order Mage_Sales_Model_Order */
        $order = Mage::getModel('sales/order')->load($orderIncrementId, 'increment_id');
        if (!$order->getId()) {
            $this->_fault('order_not_exists');
        }
        if (!$order->canCreditmemo()) {
            $this->_fault('cannot_create_creditmemo');
        }
        $creditmemoData = $this->_prepareCreateData($creditmemoData);

        /** @var $service Mage_Sales_Model_Service_Order */
        $service = Mage::getModel('sales/service_order', $order);
        /** @var $creditmemo Mage_Sales_Model_Order_Creditmemo */
        $creditmemo = $service->prepareCreditmemo($creditmemoData);

        // refund to Store Credit
        if ($refundToStoreCreditAmount) {
            // check if refund to Store Credit is available
            if ($order->getCustomerIsGuest()) {
                $this->_fault('cannot_refund_to_storecredit');
            }
            $refundToStoreCreditAmount = max(
                0,
                min($creditmemo->getBaseCustomerBalanceReturnMax(), $refundToStoreCreditAmount)
            );
            if ($refundToStoreCreditAmount) {
                $refundToStoreCreditAmount = $creditmemo->getStore()->roundPrice($refundToStoreCreditAmount);
                $creditmemo->setBaseCustomerBalanceTotalRefunded($refundToStoreCreditAmount);
                $refundToStoreCreditAmount = $creditmemo->getStore()->roundPrice(
                    $refundToStoreCreditAmount*$order->getStoreToOrderRate()
                );
                // this field can be used by customer balance observer
                $creditmemo->setBsCustomerBalTotalRefunded($refundToStoreCreditAmount);
                // setting flag to make actual refund to customer balance after credit memo save
                $creditmemo->setCustomerBalanceRefundFlag(true);
            }
        }
        $creditmemo->setPaymentRefundDisallowed(true)->register();
        // add comment to creditmemo
        if (!empty($comment)) {
            $creditmemo->addComment($comment, $notifyCustomer);
        }
        try {
            Mage::getModel('core/resource_transaction')
                ->addObject($creditmemo)
                ->addObject($order)
                ->save();
            // send email notification
            $creditmemo->sendEmail($notifyCustomer, ($includeComment ? $comment : ''));
        } catch (Mage_Core_Exception $e) {
            $this->_fault('data_invalid', $e->getMessage());
        }
        return $creditmemo->getIncrementId();
    }
}

Чтобы создать онлайн-возврат средств, вам необходимо сопоставить вашу кредитную ноту со счетом. Поскольку вызов API предлагает только привлечение кредитных нот против заказа, самый простой способ - получить счет-фактура из заказа. Мы оставим запасной вариант предыдущего поведения для крайних случаев, когда вы не можете получить счета-фактуры из заказа.

Для этого давайте заменим:

$creditmemo = $service->prepareCreditmemo($creditmemoData);

Автор:

$invoices = $order->getInvoiceCollection();
if ($invoices) {
    $creditmemo = $service->prepareInvoiceCreditmemo($invoices->getFirstItem(), $creditmemoData);
} else {
    $creditmemo = $service->prepareCreditmemo($creditmemoData);
}

При регистрации кредит-ноты существует гарантия, которая предотвращает возврат средств. Давайте удалим его:

$creditmemo->setPaymentRefundDisallowed(true)->register();

Становится:

$creditmemo->register();

Поскольку мы прикрепили эту кредит-ноту к счету-фактуре, нам также потребуется сохранить счет-фактуру. Давайте заменим следующее:

Mage::getModel('core/resource_transaction')
    ->addObject($creditmemo)
    ->addObject($order)
    ->save();

Этим:

$transactionSave = Mage::getModel('core/resource_transaction')
    ->addObject($creditmemo)
    ->addObject($order);
if ($creditmemo->getInvoice()) {
    $transactionSave->addObject($creditmemo->getInvoice());
}
$transactionSave->save();

Теперь у вас все должно быть готово. Ваше окончательное переопределение должно выглядеть так:

TL;ДР

<?php
class Mycompany_Sales_Model_Order_Creditmemo_Api extends Mage_Sales_Model_Order_Creditmemo_Api
{
    public function create($orderIncrementId, $creditmemoData = null, $comment = null, $notifyCustomer = false,
                           $includeComment = false, $refundToStoreCreditAmount = null)
    {
        /** @var $order Mage_Sales_Model_Order */
        $order = Mage::getModel('sales/order')->load($orderIncrementId, 'increment_id');
        if (!$order->getId()) {
            $this->_fault('order_not_exists');
        }
        if (!$order->canCreditmemo()) {
            $this->_fault('cannot_create_creditmemo');
        }
        $creditmemoData = $this->_prepareCreateData($creditmemoData);

        /** @var $service Mage_Sales_Model_Service_Order */
        $service = Mage::getModel('sales/service_order', $order);
        /** @var $creditmemo Mage_Sales_Model_Order_Creditmemo */
        $invoices = $order->getInvoiceCollection();
        if ($invoices) {
            $creditmemo = $service->prepareInvoiceCreditmemo($invoices->getFirstItem(), $creditmemoData);
        } else {
            $creditmemo = $service->prepareCreditmemo($creditmemoData);
        }

        // refund to Store Credit
        if ($refundToStoreCreditAmount) {
            // check if refund to Store Credit is available
            if ($order->getCustomerIsGuest()) {
                $this->_fault('cannot_refund_to_storecredit');
            }
            $refundToStoreCreditAmount = max(
                0,
                min($creditmemo->getBaseCustomerBalanceReturnMax(), $refundToStoreCreditAmount)
            );
            if ($refundToStoreCreditAmount) {
                $refundToStoreCreditAmount = $creditmemo->getStore()->roundPrice($refundToStoreCreditAmount);
                $creditmemo->setBaseCustomerBalanceTotalRefunded($refundToStoreCreditAmount);
                $refundToStoreCreditAmount = $creditmemo->getStore()->roundPrice(
                    $refundToStoreCreditAmount*$order->getStoreToOrderRate()
                );
                // this field can be used by customer balance observer
                $creditmemo->setBsCustomerBalTotalRefunded($refundToStoreCreditAmount);
                // setting flag to make actual refund to customer balance after credit memo save
                $creditmemo->setCustomerBalanceRefundFlag(true);
            }
        }
        $creditmemo->register();
        // add comment to creditmemo
        if (!empty($comment)) {
            $creditmemo->addComment($comment, $notifyCustomer);
        }
        try {
            $transactionSave = Mage::getModel('core/resource_transaction')
                ->addObject($creditmemo)
                ->addObject($order);
            if ($creditmemo->getInvoice()) {
                $transactionSave->addObject($creditmemo->getInvoice());
            }
            $transactionSave->save();
            // send email notification
            $creditmemo->sendEmail($notifyCustomer, ($includeComment ? $comment : ''));
        } catch (Mage_Core_Exception $e) {
            $this->_fault('data_invalid', $e->getMessage());
        }
        return $creditmemo->getIncrementId();
    }
}
 3
Author: Alexandre Leprêtre, 2015-09-07 15:33:14

К сожалению, я не смог найти способ сделать это через API. Я прибегнул к кодированию его за пределами api, но это в конечном итоге приводит к запуску "онлайн-возврата" и использует платежные крючки для возврата средств через мой платежный процессор.

        $service = Mage::getModel('sales/service_order', $order);
        $creditmemo = $service->prepareInvoiceCreditmemo($invoice, $salesOrderCreditmemoData)->register();
        $transactionSave = Mage::getModel('core/resource_transaction')->addObject($creditmemo)->addObject($order)->addObject($invoice);
        $transactionSave->save();
        $creditMemoId=$creditmemo->getIncrementId();

В этом коде $order - это объект заказа mage, ala $order = Mage::getModel('sales/order')->loadByIncrementId($increment_id); и $invoice - это объект счета-фактуры, а $salesordercreditmemodata - это массив product_line_ids =>количество. Работа над этим спасла мне жизнь, к сожалению, теперь у меня есть проект, который это 95 % api и 5 % это. Эй, это работает.

 0
Author: RightClick, 2015-06-09 16:30:12

У меня возникли трудности с реализацией решения, которое вы создали. Я скопировал /app/code/core/Mage/Sales/Model/Order/Creditmemo/Api.php чтобы /app/code/local/Mage/Sales/Model/Order/Creditmemo/Api.php и модифицированный

    /** @var $service Mage_Sales_Model_Service_Order */
    $service = Mage::getModel('sales/service_order', $order);
    /** @var $creditmemo Mage_Sales_Model_Order_Creditmemo  */
    $creditmemo = $service->prepareCreditmemo($creditmemoData);

К следующему

/** @var $service Mage_Sales_Model_Service_Order */
    $service = Mage::getModel('sales/service_order', $order);
    /** @var $creditmemo Mage_Sales_Model_Order_Creditmemo */
    $creditmemo = $service->prepareInvoiceCreditmemo($invoice, $salesOrderCreditmemoData)->register();
    $transactionSave = Mage::getModel('core/resource_transaction')->addObject($creditmemo)->addObject($order)->addObject($invoice);
    $transactionSave->save();
    $creditMemoId=$creditmemo->getIncrementId();

Сейчас я получаю следующий ответ от моего запроса API

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
  <SOAP-ENV:Fault>
     <faultcode>SOAP-ENV:Server</faultcode>
     <faultstring>Call to a member function getOrder() on a non-object</faultstring>
  </SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Пожалуйста, простите мое невежество, я новичок в API Magento.

 0
Author: The Smart Dude, 2015-07-08 03:47:07