承認して、いくつかのサードパーティAPI呼び出しを行う必要があります。それらの呼び出しから何が返されるかに基づいて、承認を取得またはキャンセルします。
現在、authorize.netのみを使用していますが、できるだけ多くの支払いゲートウェイでこれを使用できるようにしたいと考えています。authorize.netをAuthorize Onlyに設定しました。私のオブザーバーはsales_order_payment_place_endイベントを実行します。
これが私のオブザーバーでやっていることです(まだ抽象化されていませんが、まだ概念実証が必要です)。
if(/*API calls return ok*/)
{
$observer->getPayment()->getMethod_instance()->capture($observer->getPayment(),$observer->getPayment()->getAmount());
}
else
{
Mage::dispatchEvent('Mainstreethost_MicrosOrder_Failure');
$observer->getPayment()->getMethod_instance()->cancel($observer->getPayment());
}
capture()を呼び出すと、支払いが事前承認されたかどうかが確認されます。これは、私たちが達成しようとしていることです。
public function capture(Varien_Object $payment, $amount)
{
if ($amount <= 0) {
Mage::throwException(Mage::helper('paygate')->__('Invalid amount for capture.'));
}
$this->_initCardsStorage($payment);
if ($this->_isPreauthorizeCapture($payment)) {
$this->_preauthorizeCapture($payment, $amount);
} else if ($this->isPartialAuthorization($payment)) {
$this->_partialAuthorization($payment, $amount, self::REQUEST_TYPE_AUTH_CAPTURE);
} else {
$this->_place($payment, $amount, self::REQUEST_TYPE_AUTH_CAPTURE);
}
$payment->setSkipTransactionCreation(true);
return $this;
}
_isPreauthorizedCapture()は$ lastTransactionを割り当てようとします:
protected function _isPreauthorizeCapture($payment)
{
if ($this->getCardsStorage()->getCardsCount() <= 0) {
return false;
}
foreach($this->getCardsStorage()->getCards() as $card) {
$lastTransaction = $payment->getTransaction($card->getLastTransId());
if (!$lastTransaction
|| $lastTransaction->getTxnType() != Mage_Sales_Model_Order_Payment_Transaction::TYPE_AUTH
) {
return false;
}
}
return true;
}
$ lastTransactionは常にfalseを返します。これは、$ payment-> getTransaction()が最終的に_lookupTransaction()を呼び出すためです。
protected function _lookupTransaction($txnId, $txnType = false)
{
if (!$txnId) {
if ($txnType && $this->getId()) {
$collection = Mage::getModel('sales/order_payment_transaction')->getCollection()
->setOrderFilter($this->getOrder())
->addPaymentIdFilter($this->getId())
->addTxnTypeFilter($txnType)
->setOrder('created_at', Varien_Data_Collection::SORT_ORDER_DESC)
->setOrder('transaction_id', Varien_Data_Collection::SORT_ORDER_DESC);
foreach ($collection as $txn) {
$txn->setOrderPaymentObject($this);
$this->_transactionsLookup[$txn->getTxnId()] = $txn;
return $txn;
}
}
return false;
}
if (isset($this->_transactionsLookup[$txnId])) {
return $this->_transactionsLookup[$txnId];
}
$txn = Mage::getModel('sales/order_payment_transaction')
->setOrderPaymentObject($this)
->loadByTxnId($txnId);
if ($txn->getId()) {
$this->_transactionsLookup[$txnId] = $txn;
} else {
$this->_transactionsLookup[$txnId] = false;
}
return $this->_transactionsLookup[$txnId];
}
現在、このメソッドは2回呼び出されます。1回は認証のため、もう1回はオブザーバーでcapture()を呼び出すときに呼び出されます。承認呼び出しはこの行にスキップします:
$txn = Mage::getModel('sales/order_payment_transaction')
->setOrderPaymentObject($this)
->loadByTxnId($txnId);
そして、nullデータを含むトランザクションオブジェクトを返します。なぜこれが起こるのですか?
Mage_Sales_Model_Resource_Order_Payment_TransactionのメソッドloadObjectByTxnId()が$ dataをfalseに割り当てているため:
public function loadObjectByTxnId(Mage_Sales_Model_Order_Payment_Transaction $transaction, $orderId, $paymentId,
$txnId)
{
$select = $this->_getLoadByUniqueKeySelect($orderId, $paymentId, $txnId);
$data = $this->_getWriteAdapter()->fetchRow($select);
$transaction->setData($data);
$this->unserializeFields($transaction);
$this->_afterLoad($transaction);
}
$ dataは、_lookupTransaction()の$ txnクラスオブジェクトをハイドレートするものです!ご参考までに、これは実際のSQLクエリです。
SELECT `sales_payment_transaction`.* FROM `sales_payment_transaction` WHERE (order_id = '38') AND (payment_id = '38') AND (txn_id = '2217720876')
ところで、そのテーブルは常に空です。
ちょっと待って!もっともっと失敗します!
_lookupTransaction()への2番目の呼び出し(キャプチャー呼び出し)で、これが作動した場合:
if (isset($this->_transactionsLookup[$txnId])) {
return $this->_transactionsLookup[$txnId];
}
しかし、その値はfalseです。つまり、_isPreauthorizeCapture()がfalseを返し、capture()がエラーをスローして、クレジットカード番号が必要であることを通知します。