API Magento - кредит-нота по счету-фактуре
Я использую magento soap api версии 2. С помощью api я могу успешно создавать кредитные заметки, и они отлично отображаются в бэкэнде magento. Они не отображаются в песочнице моих платежных систем, и я боюсь, что это потому, что они являются "автономными возвратами".
В интерфейсе magento, когда вы создаете кредит-ноту по заказу, это "автономный возврат". Вы должны создать кредит-ноту в счете-фактуре, чтобы возврат был "онлайн-возвратом", и фактически перейти до вашего процессора.
Поэтому я направился к документации и увидел, что нет аргумента для передачи номера счета. Вы можете создавать кредит-ноты только для заказа. Так что, возможно, я пропустил это, и есть способ сделать это в счете-фактуре. Или, может быть, я могу передать другой аргумент через api, чтобы принудительно вернуть деньги онлайн?
ВОПРОС Есть ли способ сделать онлайн-возврат средств (кредит-нота) через api?
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();
}
}
К сожалению, я не смог найти способ сделать это через 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 % это. Эй, это работает.
У меня возникли трудности с реализацией решения, которое вы создали. Я скопировал /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.