Magento付款审核/疑似欺诈工作流程

时间:2011-03-23 20:20:09

标签: php magento status

我正在Magento商店工作,客户在订单上请求了一些自定义过滤器,以便在被发送到履行之前对其进行人工审核。出现这些情况时,订单会标有内置的付款审核 / 疑似欺诈状态/状态。

我的问题是,在管理界面中,您似乎无法对付款审核状态下的订单做多少工作。我添加了一个自定义的“批准”类型按钮,用于手动批准订单,但如果它被审核并确认为欺诈,那么预期采取的措施是什么?我想取消或退还订单,但似乎不允许。检查订单上的canCancelcanCreditmemo会返回false。对于这样的场景,使用保留状态或付款审核更好吗?

4 个答案:

答案 0 :(得分:8)

我没有覆盖Mage_Sales_Model_Order对象(不是非常理想),而是在Magento工具包中发现了一些现有的钩子,它们可以在使用可疑欺诈状态标记订单后启用管理员操作。要启用这些,需要执行以下步骤:

在您的付款方式(继承自Mage_Payment_Model_Method_Abstract)中,添加以下内容:

    protected $_canReviewPayment  = true;

    public function acceptPayment(Mage_Payment_Model_Info $payment) {
        parent::acceptPayment($payment);
        //perform gateway actions to remove Fraud flags. Capture should not occur here
        return true;
        //returning true will trigger a capture on any existing invoices, otherwise the admin can manually Invoice the order
    }

    public function denyPayment(Mage_Payment_Model_Info $payment) {
        parent::denyPayment($payment);
        //if your payment gateway supports it, you should probably void any pre-auth
        return true;  
    }

Magento的订单视图块将检查$order->canReviewPayment(),它将查看付款方式上的_canReviewPayment变量,如果为true,则在订单视图上显示两个按钮:"接受付款"和#34;拒绝付款"。点击后,我们刚刚添加的两个新的付款方式功能将被调用。

如果您已经有与订单相关联的发票,则可以是pay' d或cancel' d。有关更多详细信息,请查看Mage_Sales_Model_Order_Payment::registerPaymentReviewAction

答案 1 :(得分:3)

我们的客户有关于此可疑欺诈或发票付款的“欺诈”标志的paygate问题,其中付款人在手动批准付款后未通知Magento。这似乎是authorize.net和某些paypal授权和响应配置的问题。

以下是我开发的三部分解决方案,用于操纵订单至少足以允许创建贷项通知单,并清除欺诈状态。此过程还会创建订单发货并将订单推送到“正在处理”,然后“完成”。

我在核心代码文件的本地副本中进行了这三项修改/public_html/app/code/local/Mage/Adminhtml/Block/Sales/Order/View.php

(1)注释代码行,并替换为允许在订单处于处理或完成状态时出现贷项凭证按钮的代码行,即使$ order-> canCreditmemo()未正确设置为等于true。 / p>

// if ($this->_isAllowedAction('creditmemo') && $order->canCreditmemo()) {
if ($this->_isAllowedAction('creditmemo') && ($order->getState() == 'complete' || $order->getState() == 'processing')) {

(2)创建一个清除欺诈状态的按钮,调用#3

中引用的功能
// 06/10/2014 Rand created button on Admin panel to clear fraud AFTER payment is authorized manually.
if ($order->getStatus() === 'fraud') {
$message = Mage::helper('sales')->__('*** CAUTION *** Payment must FIRST be authorized manually. Are you sure you want to clear this fraud status?');
$this->addButton('clear_fraud', array(
    'label'     => Mage::helper('sales')->__('Clear Fraud'),
    'onclick'   => 'setLocation(\'' . $this->clearFraud($order) . '\')',
));
}

(3)创建公共职能clearFraud($ order)以完成清算发票到付款,创建发货(如果需要),以及清算$ order状态从'欺诈'到完成。

public function clearFraud($order)
{
// THIS FUNCTION IS CREATED BY RAND TO HANDLE CLEARING INCOMPLETED RECORDS
// CREATED BY AUTHORIZE.NET FRAUD PROTECTION PROCESS

// setState of order invoice(s) to one that will accept order completion, and save it.
if ($order->hasInvoices()) {
    foreach ($order->getInvoiceCollection() as $invoice) {
        $invoice->setState('2');
        $invoice->save();
    }
}

// Handle Shipment: Create it (if needed) and save the transaction.
if (!$order->hasShipments()) {
    $shipment = $order->prepareShipment();
    $shipment->register();
    $order->setIsInProcess(true);
    $transactionSave = Mage::getModel('core/resource_transaction')
        ->addObject($shipment)
        ->addObject($shipment->getOrder())
        ->save();
    $order->save();
}

// Set order to complete, and save the order
$order->setState(Mage_Sales_Model_Order::STATE_PROCESSING, true);
$order->save();
$order->setState(Mage_Sales_Model_Order::STATE_COMPLETE, true);
$order->save();

return $this->getUrl('*/sales_order');
}

这应该为解决如何使Magento按照你想要的方式行事提供一些帮助。

答案 2 :(得分:2)

我认为在语义上区分保留状态和付款审核非常重要,因此我建议您保持单独的状态/状态并使其在客户工作流程。

您可以覆盖canCancel()canCreditmemo()功能,以便在订单处于付款审核状态时允许这些操作。在扩展Mage_Sales_Model_Order的类中,重新定义这些函数以检查您的自定义状态/状态。

HTH,
JD

答案 3 :(得分:0)

在搜索此问题的解决方案后,B.Sharp的选项是我找到的唯一解决方案。我将其与此https://www.hummingbirduk.com/suspected-fraud-transactions-magento/混合并添加了$ invoice-> sendEmail();将电子邮件发送给客户。

在我们的情况下,“涉嫌欺诈”的状态是随机发生的,同一个篮子和同一个PayPal帐户的同一个客户可能会得到它。与舍入,税收或货币无关。

class Mage_Adminhtml_Block_Sales_Order_View extends Mage_Adminhtml_Block_Widget_Form_Container

{

public function __construct()
{
    $this->_objectId    = 'order_id';
    $this->_controller  = 'sales_order';
    $this->_mode        = 'view';

    parent::__construct();

    $this->_removeButton('delete');
    $this->_removeButton('reset');
    $this->_removeButton('save');
    $this->setId('sales_order_view');
    $order = $this->getOrder();
    $coreHelper = Mage::helper('core');

    if ($this->_isAllowedAction('edit') && $order->canEdit()) {
        $confirmationMessage = $coreHelper->jsQuoteEscape(
            Mage::helper('sales')->__('Are you sure? This order will be canceled and a new one will be created instead')
        );
        $onclickJs = 'deleteConfirm(\'' . $confirmationMessage . '\', \'' . $this->getEditUrl() . '\');';
        $this->_addButton('order_edit', array(
            'label'    => Mage::helper('sales')->__('Edit'),
            'onclick'  => $onclickJs,
        ));
        // see if order has non-editable products as items
        $nonEditableTypes = array_keys($this->getOrder()->getResource()->aggregateProductsByTypes(
            $order->getId(),
            array_keys(Mage::getConfig()
                ->getNode('adminhtml/sales/order/create/available_product_types')
                ->asArray()
            ),
            false
        ));
        if ($nonEditableTypes) {
            $confirmationMessage = $coreHelper->jsQuoteEscape(
                Mage::helper('sales')
                    ->__('This order contains (%s) items and therefore cannot be edited through the admin interface at this time, if you wish to continue editing the (%s) items will be removed, the order will be canceled and a new order will be placed.',
                    implode(', ', $nonEditableTypes), implode(', ', $nonEditableTypes))
            );
            $this->_updateButton('order_edit', 'onclick',
                'if (!confirm(\'' . $confirmationMessage . '\')) return false;' . $onclickJs
            );
        }
    }

    if ($this->_isAllowedAction('cancel') && $order->canCancel()) {
        $confirmationMessage = $coreHelper->jsQuoteEscape(
            Mage::helper('sales')->__('Are you sure you want to cancel this order?')
        );
        $this->_addButton('order_cancel', array(
            'label'     => Mage::helper('sales')->__('Cancel'),
            'onclick'   => 'deleteConfirm(\'' . $confirmationMessage . '\', \'' . $this->getCancelUrl() . '\')',
        ));
    }

    if ($this->_isAllowedAction('emails') && !$order->isCanceled()) {
        $confirmationMessage = $coreHelper->jsQuoteEscape(
            Mage::helper('sales')->__('Are you sure you want to send order email to customer?')
        );
        $this->addButton('send_notification', array(
            'label'     => Mage::helper('sales')->__('Send Email'),
            'onclick'   => "confirmSetLocation('{$confirmationMessage}', '{$this->getEmailUrl()}')",
        ));
    }

    //if ($this->_isAllowedAction('creditmemo') && $order->canCreditmemo()) {
    if ($this->_isAllowedAction('creditmemo') && ($order->getState() == 'complete' || $order->getState() == 'processing')) {
        $confirmationMessage = $coreHelper->jsQuoteEscape(
            Mage::helper('sales')->__('This will create an offline refund. To create an online refund, open an invoice and create credit memo for it. Do you wish to proceed?')
        );
        $onClick = "setLocation('{$this->getCreditmemoUrl()}')";
        if ($order->getPayment()->getMethodInstance()->isGateway()) {
            $onClick = "confirmSetLocation('{$confirmationMessage}', '{$this->getCreditmemoUrl()}')";
        }
        $this->_addButton('order_creditmemo', array(
            'label'     => Mage::helper('sales')->__('Credit Memo'),
            'onclick'   => $onClick,
            'class'     => 'go'
        ));
    }

    // invoice action intentionally
    if ($this->_isAllowedAction('invoice') && $order->canVoidPayment()) {
        $confirmationMessage = $coreHelper->jsQuoteEscape(
            Mage::helper('sales')->__('Are you sure you want to void the payment?')
        );
        $this->addButton('void_payment', array(
            'label'     => Mage::helper('sales')->__('Void'),
            'onclick'   => "confirmSetLocation('{$confirmationMessage}', '{$this->getVoidPaymentUrl()}')",
        ));
    }

    if ($this->_isAllowedAction('hold') && $order->canHold()) {
        $this->_addButton('order_hold', array(
            'label'     => Mage::helper('sales')->__('Hold'),
            'onclick'   => 'setLocation(\'' . $this->getHoldUrl() . '\')',
        ));
    }

    if ($this->_isAllowedAction('unhold') && $order->canUnhold()) {
        $this->_addButton('order_unhold', array(
            'label'     => Mage::helper('sales')->__('Unhold'),
            'onclick'   => 'setLocation(\'' . $this->getUnholdUrl() . '\')',
        ));
    }

    if ($this->_isAllowedAction('review_payment')) {
        if ($order->canReviewPayment()) {
            $confirmationMessage = $coreHelper->jsQuoteEscape(
                Mage::helper('sales')->__('Are you sure you want to accept this payment?')
            );
            $onClick = "confirmSetLocation('{$confirmationMessage}', '{$this->getReviewPaymentUrl('accept')}')";
            $this->_addButton('accept_payment', array(
                'label'     => Mage::helper('sales')->__('Accept Payment'),
                'onclick'   => $onClick,
            ));
            $confirmationMessage = $coreHelper->jsQuoteEscape(
                Mage::helper('sales')->__('Are you sure you want to deny this payment?')
            );
            $onClick = "confirmSetLocation('{$confirmationMessage}', '{$this->getReviewPaymentUrl('deny')}')";
            $this->_addButton('deny_payment', array(
                'label'     => Mage::helper('sales')->__('Deny Payment'),
                'onclick'   => $onClick,
            ));
        }
        if ($order->canFetchPaymentReviewUpdate()) {
            $this->_addButton('get_review_payment_update', array(
                'label'     => Mage::helper('sales')->__('Get Payment Update'),
                'onclick'   => 'setLocation(\'' . $this->getReviewPaymentUrl('update') . '\')',
            ));
        }
    }

    if ($this->_isAllowedAction('invoice') && $order->canInvoice()) {
        $_label = $order->getForcedDoShipmentWithInvoice() ?
            Mage::helper('sales')->__('Invoice and Ship') :
            Mage::helper('sales')->__('Invoice');
        $this->_addButton('order_invoice', array(
            'label'     => $_label,
            'onclick'   => 'setLocation(\'' . $this->getInvoiceUrl() . '\')',
            'class'     => 'go'
        ));
    }

    if ($this->_isAllowedAction('ship') && $order->canShip()
        && !$order->getForcedDoShipmentWithInvoice()) {
        $this->_addButton('order_ship', array(
            'label'     => Mage::helper('sales')->__('Ship'),
            'onclick'   => 'setLocation(\'' . $this->getShipUrl() . '\')',
            'class'     => 'go'
        ));
    }

    if ($this->_isAllowedAction('reorder')
        && $this->helper('sales/reorder')->isAllowed($order->getStore())
        && $order->canReorderIgnoreSalable()
    ) {
        $this->_addButton('order_reorder', array(
            'label'     => Mage::helper('sales')->__('Reorder'),
            'onclick'   => 'setLocation(\'' . $this->getReorderUrl() . '\')',
            'class'     => 'go'
        ));
    }


    // 06/10/2014 Rand created button on Admin panel to clear fraud AFTER payment is authorized manually.
    if ($order->getStatus() === 'fraud') {
            $message = Mage::helper('sales')->__('*** CAUTION *** Payment must FIRST be authorized manually. Are you sure you want to clear this fraud status?');
                $this->addButton('clear_fraud', array(
                    'label'     => Mage::helper('sales')->__('Clear Fraud'),
                    'onclick'   => 'setLocation(\'' . $this->clearFraud($order) . '\')',
                    'class'     => 'go'
                ));
        }



}

/**
 * Retrieve order model object
 *
 * @return Mage_Sales_Model_Order
 */
public function getOrder()
{
    return Mage::registry('sales_order');
}

/**
 * Retrieve Order Identifier
 *
 * @return int
 */
public function getOrderId()
{
    return $this->getOrder()->getId();
}

public function getHeaderText()
{
    if ($_extOrderId = $this->getOrder()->getExtOrderId()) {
        $_extOrderId = '[' . $_extOrderId . '] ';
    } else {
        $_extOrderId = '';
    }
    return Mage::helper('sales')->__('Order # %s %s | %s', $this->getOrder()->getRealOrderId(), $_extOrderId, $this->formatDate($this->getOrder()->getCreatedAtDate(), 'medium', true));
}

public function getUrl($params='', $params2=array())
{
    $params2['order_id'] = $this->getOrderId();
    return parent::getUrl($params, $params2);
}

public function getEditUrl()
{
    return $this->getUrl('*/sales_order_edit/start');
}

public function getEmailUrl()
{
    return $this->getUrl('*/*/email');
}

public function getCancelUrl()
{
    return $this->getUrl('*/*/cancel');
}

public function getInvoiceUrl()
{
    return $this->getUrl('*/sales_order_invoice/start');
}

public function getCreditmemoUrl()
{
    return $this->getUrl('*/sales_order_creditmemo/start');
}

public function getHoldUrl()
{
    return $this->getUrl('*/*/hold');
}

public function getUnholdUrl()
{
    return $this->getUrl('*/*/unhold');
}

public function getShipUrl()
{
    return $this->getUrl('*/sales_order_shipment/start');
}

public function getCommentUrl()
{
    return $this->getUrl('*/*/comment');
}

public function getReorderUrl()
{
    return $this->getUrl('*/sales_order_create/reorder');
}

/**
 * Payment void URL getter
 */
public function getVoidPaymentUrl()
{
    return $this->getUrl('*/*/voidPayment');
}

protected function _isAllowedAction($action)
{
    return Mage::getSingleton('admin/session')->isAllowed('sales/order/actions/' . $action);
}

/**
 * Return back url for view grid
 *
 * @return string
 */
public function getBackUrl()
{
    if ($this->getOrder()->getBackUrl()) {
        return $this->getOrder()->getBackUrl();
    }

    return $this->getUrl('*/*/');
}

public function getReviewPaymentUrl($action)
{
    return $this->getUrl('*/*/reviewPayment', array('action' => $action));
}


public function clearFraud($order)
{


    $order->setState(Mage_Sales_Model_Order::STATE_PROCESSING, true);
    $order->setStatus('processing', false);
    $order->save();
    try {
        if(!$order->canInvoice()) {
            Mage::throwException(Mage::helper('core')->__('Cannot create an invoice.'));
        }
        $invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice();
        if (!$invoice->getTotalQty()) {
            Mage::throwException(Mage::helper('core')->__('Cannot create an invoice without products.'));
        }
        $invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_OFFLINE);
        $invoice->register();
        $invoice->sendEmail();
        $transactionSave = Mage::getModel('core/resource_transaction')->addObject($invoice)->addObject($invoice->getOrder());
        $transactionSave->save();
        } catch (Mage_Core_Exception $e) {
    }





    return $this->getUrl('*/sales_order');
}

}