Transaction.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Sales\Model\ResourceModel\Order\Payment;
  7. use Magento\Sales\Model\ResourceModel\EntityAbstract;
  8. use Magento\Sales\Model\Spi\TransactionResourceInterface;
  9. /**
  10. * Sales transaction resource model
  11. *
  12. * @author Magento Core Team <core@magentocommerce.com>
  13. */
  14. class Transaction extends EntityAbstract implements TransactionResourceInterface
  15. {
  16. /**
  17. * Serializable field: additional_information
  18. *
  19. * @var array
  20. */
  21. protected $_serializableFields = ['additional_information' => [null, []]];
  22. /**
  23. * Initialize main table and the primary key field name
  24. *
  25. * @return void
  26. */
  27. protected function _construct()
  28. {
  29. $this->_init('sales_payment_transaction', 'transaction_id');
  30. }
  31. /**
  32. * Update transactions in database using provided transaction as parent for them
  33. * have to repeat the business logic to avoid accidental injection of wrong transactions
  34. *
  35. * @param \Magento\Sales\Model\Order\Payment\Transaction $transaction
  36. * @return void
  37. */
  38. public function injectAsParent(\Magento\Sales\Model\Order\Payment\Transaction $transaction)
  39. {
  40. $txnId = $transaction->getTxnId();
  41. if ($txnId &&
  42. \Magento\Sales\Model\Order\Payment\Transaction::TYPE_PAYMENT === $transaction->getTxnType() &&
  43. ($id = $transaction->getId())
  44. ) {
  45. $connection = $this->getConnection();
  46. // verify such transaction exists, determine payment and order id
  47. $verificationRow = $connection->fetchRow(
  48. $connection->select()->from(
  49. $this->getMainTable(),
  50. ['payment_id', 'order_id']
  51. )->where(
  52. "{$this->getIdFieldName()} = ?",
  53. (int)$id
  54. )
  55. );
  56. if (!$verificationRow) {
  57. return;
  58. }
  59. list($paymentId, $orderId) = array_values($verificationRow);
  60. // inject
  61. $where = [
  62. $connection->quoteIdentifier($this->getIdFieldName()) . '!=?' => $id,
  63. new \Zend_Db_Expr('parent_id IS NULL'),
  64. 'payment_id = ?' => (int)$paymentId,
  65. 'order_id = ?' => (int)$orderId,
  66. 'parent_txn_id = ?' => $txnId,
  67. ];
  68. $connection->update($this->getMainTable(), ['parent_id' => $id], $where);
  69. }
  70. }
  71. /**
  72. * Load the transaction object by specified txn_id
  73. *
  74. * @param \Magento\Sales\Model\Order\Payment\Transaction $transaction
  75. * @param int $orderId
  76. * @param int $paymentId
  77. * @param string $txnId
  78. * @return \Magento\Sales\Model\Order\Payment\Transaction
  79. */
  80. public function loadObjectByTxnId(
  81. \Magento\Sales\Model\Order\Payment\Transaction $transaction,
  82. $orderId,
  83. $paymentId,
  84. $txnId
  85. ) {
  86. $select = $this->_getLoadByUniqueKeySelect($orderId, $paymentId, $txnId);
  87. $data = $this->getConnection()->fetchRow($select);
  88. if (!$data) {
  89. return $transaction;
  90. }
  91. $transaction->setData($data);
  92. $this->unserializeFields($transaction);
  93. $this->_afterLoad($transaction);
  94. return $transaction;
  95. }
  96. /**
  97. * Retrieve order website id
  98. *
  99. * @param int $orderId
  100. * @return string
  101. */
  102. public function getOrderWebsiteId($orderId)
  103. {
  104. $connection = $this->getConnection();
  105. $bind = [':entity_id' => $orderId];
  106. $select = $connection->select()->from(
  107. ['so' => $this->getTable('sales_order')],
  108. 'cs.website_id'
  109. )->joinInner(
  110. ['cs' => $this->getTable('store')],
  111. 'cs.store_id = so.store_id'
  112. )->where(
  113. 'so.entity_id = :entity_id'
  114. );
  115. return $connection->fetchOne($select, $bind);
  116. }
  117. /**
  118. * Lookup for parent_id in already saved transactions of this payment by the order_id
  119. * Also serialize additional information, if any
  120. *
  121. * @param \Magento\Framework\Model\AbstractModel|\Magento\Sales\Model\Order\Payment\Transaction $transaction
  122. * @throws \Magento\Framework\Exception\LocalizedException
  123. * @return $this
  124. */
  125. protected function _beforeSave(\Magento\Framework\Model\AbstractModel $transaction)
  126. {
  127. $parentTxnId = $transaction->getData('parent_txn_id');
  128. $txnId = $transaction->getData('txn_id');
  129. $orderId = $transaction->getData('order_id');
  130. $paymentId = $transaction->getData('payment_id');
  131. $idFieldName = $this->getIdFieldName();
  132. if ($parentTxnId) {
  133. if (!$txnId || !$orderId || !$paymentId) {
  134. throw new \Magento\Framework\Exception\LocalizedException(
  135. __('We don\'t have enough information to save the parent transaction ID.')
  136. );
  137. }
  138. $parentId = (int)$this->_lookupByTxnId($orderId, $paymentId, $parentTxnId, $idFieldName);
  139. if ($parentId) {
  140. $transaction->setData('parent_id', $parentId);
  141. }
  142. }
  143. // make sure unique key won't cause trouble
  144. if ($transaction->isFailsafe()) {
  145. $autoincrementId = (int)$this->_lookupByTxnId($orderId, $paymentId, $txnId, $idFieldName);
  146. if ($autoincrementId) {
  147. $transaction->setData($idFieldName, $autoincrementId)->isObjectNew(false);
  148. }
  149. }
  150. return parent::_beforeSave($transaction);
  151. }
  152. /**
  153. * Load cell/row by specified unique key parts
  154. *
  155. * @param int $orderId
  156. * @param int $paymentId
  157. * @param string $txnId
  158. * @param mixed (array|string|object) $columns
  159. * @param bool $isRow
  160. * @param string $txnType
  161. * @return array|string
  162. */
  163. private function _lookupByTxnId($orderId, $paymentId, $txnId, $columns, $isRow = false, $txnType = null)
  164. {
  165. $select = $this->_getLoadByUniqueKeySelect($orderId, $paymentId, $txnId, $columns);
  166. if ($txnType) {
  167. $select->where('txn_type = ?', $txnType);
  168. }
  169. if ($isRow) {
  170. return $this->getConnection()->fetchRow($select);
  171. }
  172. return $this->getConnection()->fetchOne($select);
  173. }
  174. /**
  175. * Get select object for loading transaction by the unique key of order_id, payment_id, txn_id
  176. *
  177. * @param int $orderId
  178. * @param int $paymentId
  179. * @param string $txnId
  180. * @param string|array|\Zend_Db_Expr $columns
  181. * @return \Magento\Framework\DB\Select
  182. */
  183. private function _getLoadByUniqueKeySelect($orderId, $paymentId, $txnId, $columns = '*')
  184. {
  185. return $this->getConnection()->select()->from(
  186. $this->getMainTable(),
  187. $columns
  188. )->where(
  189. 'order_id = ?',
  190. $orderId
  191. )->where(
  192. 'payment_id = ?',
  193. $paymentId
  194. )->where(
  195. 'txn_id = ?',
  196. $txnId
  197. );
  198. }
  199. }