protected function constructFinancialTransactionResult(FinancialTransactionInterface $transaction, $status, $reasonCode) { $this->financialTransaction = $transaction; $this->credit = $transaction->getCredit(); $this->payment = $transaction->getPayment(); $this->paymentInstruction = null !== $this->credit ? $this->credit->getPaymentInstruction() : $this->payment->getPaymentInstruction(); $this->status = $status; $this->reasonCode = $reasonCode; $this->recoverable = false; }
protected function doReverseCredit(CreditInterface $credit, $amount) { $instruction = $credit->getPaymentInstruction(); if (PaymentInstructionInterface::STATE_VALID !== $instruction->getState()) { throw new InvalidPaymentInstructionException('PaymentInstruction must be in STATE_VALID.'); } if (CreditInterface::STATE_CREDITED !== $credit->getState()) { throw new InvalidCreditException('Credit must be in STATE_CREDITED.'); } if (false === $credit->isIndependent()) { $payment = $credit->getPayment(); if (PaymentInterface::STATE_APPROVED !== $payment->getState() && PaymentInterface::STATE_EXPIRED !== $payment->getState()) { throw new InvalidPaymentException('Payment must be in STATE_APPROVED, or STATE_EXPIRED.'); } } $transaction = $instruction->getPendingTransaction(); if (null === $transaction) { if (1 === Number::compare($amount, $max = $instruction->getCreditedAmount() - $instruction->getReversingCreditedAmount())) { throw new \InvalidArgumentException(sprintf('$amount cannot be greater than %.2f (PaymentInstruction restriction).', $max)); } if (1 === Number::compare($amount, $credit->getCreditedAmount())) { throw new \InvalidArgumentException(sprintf('$amount cannot be greater than %.2f (Credit restriction).', $credit->getCreditedAmount())); } if (false === $credit->isIndependent() && 1 === Number::compare($amount, $max = $payment->getCreditedAmount() - $payment->getReversingCreditedAmount())) { throw new \InvalidArgumentException(sprintf('$amount cannot be greater than %.2f (Payment restriction).', $max)); } $transaction = $this->buildFinancialTransaction(); $transaction->setTransactionType(FinancialTransactionInterface::TRANSACTION_TYPE_REVERSE_CREDIT); $transaction->setRequestedAmount($amount); $credit->addTransaction($transaction); $credit->setReversingCreditedAmount($amount); $instruction->setReversingCreditedAmount($instruction->getReversingCreditedAmount() + $amount); if (false === $credit->isIndependent()) { $payment->setReversingCreditedAmount($payment->getReversingCreditedAmount() + $amount); } $retry = false; } else { if (FinancialTransactionInterface::TRANSACTION_TYPE_REVERSE_CREDIT !== $transaction->getTransactionType()) { throw new InvalidPaymentInstructionException('Pending transaction is not of TYPE_REVERSE_CREDIT.'); } if ($credit->getId() !== $transaction->getCredit()->getId()) { throw new InvalidCreditException('Pending transaction belongs to another Credit.'); } if (1 === Number::compare($amount, $instruction->getReversingCreditedAmount())) { throw new \InvalidArgumentException(sprintf('$amount cannot be greater than %.2f (PaymentInstruction restriction).', $instruction->getReversingCreditedAmount())); } if (0 !== Number::compare($amount, $credit->getReversingCreditedAmount())) { throw new \InvalidArgumentException(sprintf('$amount must be equal to %.2f (Credit restriction).', $credit->getReversingCreditedAmount())); } if (false === $credit->isIndependent() && 1 === Number::compare($amount, $payment->getReversingCreditedAmount())) { throw new \InvalidArgumentException(sprintf('$amount cannot be greater than %.2f (Payment restriction).', $payment->getReversingCreditedAmount())); } $retry = true; } $plugin = $this->getPlugin($instruction->getPaymentSystemName()); try { $plugin->reverseCredit($transaction, $amount); $processedAmount = $transaction->getProcessedAmount(); if (PluginInterface::RESPONSE_CODE_SUCCESS === $transaction->getResponseCode()) { $transaction->setState(FinancialTransactionInterface::STATE_SUCCESS); $credit->setReversingCreditedAmount(0.0); $instruction->setReversingCreditedAmount($instruction->getReversingCreditedAmount() - $amount); $credit->setCreditedAmount($credit->getCreditedAmount() - $processedAmount); $instruction->setCreditedAmount($instruction->getCreditedAmount() - $processedAmount); if (false === $credit->isIndependent()) { $payment->setReversingCreditedAmount($payment->getReversingCreditedAmount() - $amount); $payment->setCreditedAmount($payment->getCreditedAmount() - $processedAmount); } return $this->buildFinancialTransactionResult($transaction, Result::STATUS_SUCCESS, PluginInterface::REASON_CODE_SUCCESS); } else { $transaction->setState(FinancialTransactionInterface::STATE_FAILED); $credit->setReversingCreditedAmount(0.0); $instruction->setReversingCreditedAmount($instruction->getReversingCreditedAmount() - $amount); if (false === $credit->isIndependent()) { $payment->setReversingCreditedAmount($payment->getReversingCreditedAmount() - $amount); } return $this->buildFinancialTransactionResult($transaction, Result::STATUS_FAILED, $transaction->getReasonCode()); } } catch (PluginFinancialException $ex) { $transaction->setState(FinancialTransactionInterface::STATE_FAILED); $credit->setReversingCreditedAmount(0.0); $instruction->setReversingCreditedAmount($instruction->getReversingCreditedAmount() - $amount); if (false === $credit->isIndependent()) { $payment->setReversingCreditedAmount($payment->getReversingCreditedAmount() - $amount); } return $this->buildFinancialTransactionResult($transaction, Result::STATUS_FAILED, $transaction->getReasonCode()); } catch (PluginBlockedException $blocked) { $transaction->setState(FinancialTransactionInterface::STATE_PENDING); if ($blocked instanceof PluginTimeoutException) { $reasonCode = PluginInterface::REASON_CODE_TIMEOUT; } else { if ($blocked instanceof PluginActionRequiredException) { $reasonCode = PluginInterface::REASON_CODE_ACTION_REQUIRED; } else { if (null === ($reasonCode = $transaction->getReasonCode())) { $reasonCode = PluginInterface::REASON_CODE_BLOCKED; } } } $transaction->setReasonCode($reasonCode); $transaction->setResponseCode(PluginInterface::RESPONSE_CODE_PENDING); $result = $this->buildFinancialTransactionResult($transaction, Result::STATUS_PENDING, $reasonCode); $result->setPluginException($blocked); $result->setRecoverable(); return $result; } }