<?php
declare(strict_types=1);
/**
* TransactionRepository.php File.
* This file is part of the Payment.net Project.
*
* PHP version 5
*
* @category Application
* @package Bdm\CheckoutBundle\Repository
* @author Pavel Baraulya <pbaraulya@bdmultimedia.fr>
* @link http://www.payment.net/
*
* FEATURES :
* ==========
*
* TODO-LIST :
* ===========
*
* HISTORY :
* =========
* 20150710 - Pavel Baraulya
*
**/
namespace Bdm\CheckoutBundle\Repository;
use Bdm\BackofficeBundle\Entity\Application;
use Bdm\BackofficeBundle\Entity\Merchant;
use Bdm\CheckoutBundle\Entity\AcquiredBatch;
use Bdm\CheckoutBundle\Entity\Order;
use Bdm\CheckoutBundle\Entity\RecurrentConfiguration;
use Bdm\CheckoutBundle\Entity\Subscription;
use Bdm\CheckoutBundle\Entity\Transaction;
use Bdm\CheckoutBundle\Service\PaymentGateway;
use Bdm\CheckoutBundle\Service\PaymentGatewayService;
use Bdm\CoreBundle\Exception\InvalidFormException;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\Persistence\ObjectRepository;
/**
* Class TransactionRepository
*/
class TransactionRepository
{
protected ObjectRepository $oRepository;
protected PaymentGatewayService $oPaymentGateway;
/**
* Constructor
*
* @param EntityManager $oEm object manager
*/
public function __construct(protected EntityManager $oEm)
{
$this->oRepository = $oEm->getRepository(Transaction::class);
}
/**
* Add new transaction
*
* @param Transaction $oTransaction transaction
*
* @throws InvalidFormException
* @return void
*/
public function add(Transaction $oTransaction)
{
$this->oEm->persist($oTransaction);
$this->oEm->flush();
}
/**
* Update transaction
*
* @param Transaction $oTransaction transaction
*
* @return Transaction
*/
public function update(Transaction $oTransaction)
{
$this->oEm->persist($oTransaction);
$this->oEm->flush();
return $oTransaction;
}
/**
* Makes card api call
*
* @throws \BadMethodCallException
* @deprecated
*/
public function process()
{
throw new \BadMethodCallException(
'Current method was deprecated. To process transactions use PaymentGatewayService'
);
}
/**
* Create list of transactions
*
* @param Subscription[] $oSubscriptions list of subscriptions
*
* @return Transaction[]
*/
public function initTransactions($oSubscriptions)
{
$aTransactions = [];
foreach ($oSubscriptions as $oSubscription) {
$oTransaction = new Transaction();
$oTransaction->setType(Transaction::TYPE_CHARGE);
$oTransaction->setActive(true)
->setState(Transaction::STATE_IN_PROGRESS)
->setAmount($oSubscription->getAmount())
->setCurrencyIsoCode($oSubscription->getCurrencyIsoCode())
->setPaymentMethod($oSubscription->getPaymentMethod())
->setPayment($oSubscription);
$this->oEm->persist($oTransaction);
$aTransactions[] = $oTransaction;
}
$this->oEm->flush();
return $aTransactions;
}
/**
* Find transaction by reference
*
* @param string $sRef reference
*
* @return Transaction
*/
public function findByRef($sRef)
{
return $this->oRepository->findOneBy(['sReference' => $sRef]);
}
/**
* Find transaction by ID
*
* @param string $iId ID
*
* @return Transaction
*/
public function findById($iId)
{
return $this->oRepository->find($iId);
}
/**
* Get transactions by state
*
* @param array $aOrderStates states
* @param null $sGateway gateway key
* @param \DateTime|null $oCreatedBefore date of last changing
* @param array $aTransactionStates transaction states
*
* @return \Doctrine\ORM\Internal\Hydration\IterableResult<Transaction>
*/
public function getTransactionByState(
array $aOrderStates,
$sGateway = null,
\DateTime $oCreatedBefore = null,
array $aTransactionStates = []
) {
$oQb = $this->oRepository->createQueryBuilder('t');
if ($oCreatedBefore instanceof \DateTime) {
$oQb->andWhere('t.oCreationDate < :createdBefore')
->setParameter('createdBefore', $oCreatedBefore);
}
if ($aOrderStates !== [] || !is_null($sGateway)) {
$aCondition = [];
if ($aOrderStates !== []) {
$aCondition[] = 'p.sState IN (:paymentState)';
$oQb->setParameter('paymentState', $aOrderStates);
}
if ($sGateway) {
$aCondition[] = 'p.sPaymentGateway = :gateway';
$oQb->setParameter('gateway', $sGateway);
}
if ($aTransactionStates !== []) {
$aCondition[] = 't.sState IN (:aTransactionStates)';
$oQb->setParameter('aTransactionStates', $aTransactionStates);
}
$oQb->innerJoin('t.oPayment', 'p', 'WITH', implode(' AND ', $aCondition));
}
return $oQb->getQuery()->iterate();
}
/**
* @param string|null $sMerchantEmail merchant's email
* @param array $aReferences array or order references
*
* @return Transaction []
*/
public function getForSplitPaymentSync($sMerchantEmail = null, $aReferences = [])
{
$oQb = $this->oRepository->createQueryBuilder('t');
$oQb
->andWhere('t.sState = :sState')
->setParameter('sState', Transaction::STATE_SUCCEEDED)
->leftJoin('t.oPayment', 'p', Join::WITH, 't.oPayment = p')
->leftJoin(RecurrentConfiguration::class, 'rc', Join::WITH, 'rc.oOrder = p')
->andWhere('rc.oOrder IS NOT NULL');
;
if ($sMerchantEmail != null) {
$oQb->leftJoin(Application::class, 'a', 'WITH', 'p.oApplication = a')
->leftJoin(Merchant::class, 'm', 'WITH', 'a.oMerchant = m')
->andWhere('m.sEmail = :sMerchantEmail')
->setParameter('sMerchantEmail', $sMerchantEmail);
}
if (!empty($aReferences)) {
$oQb->andWhere('p.sReference IN (:aReferences)')
->setParameter('aReferences', $aReferences);
}
return $oQb->getQuery()->getResult();
}
/**
* Get transactions by period
*
* @param \DateTime $oCreationDate transactions created equal or later this date
* @param array $aStates transaction states
* @param array $aOrderStates order states
* @param array $aGateways payment gateways
* @param array $aReferences transaction references
* @param bool $b3DS 3DS flag
*
* @return Transaction[]
*/
public function getTransactionsByPeriod(
\DateTime $oCreationDate = null,
$aStates = [],
$aOrderStates = [],
$aGateways = [],
$aReferences = [],
$b3DS = null
) {
$oQb = $this->oRepository->createQueryBuilder('t');
if ($oCreationDate instanceof \DateTime) {
$oQb->where('t.oCreationDate >= :oCreationDate')
->setParameter('oCreationDate', $oCreationDate);
}
if ($aStates) {
$oQb->andWhere('t.sState IN (:aStates)')
->setParameter('aStates', $aStates);
}
if ($aReferences) {
$oQb->andWhere('t.sReference IN (:aReferences)')
->setParameter('aReferences', $aReferences);
}
if (!empty($aGateways) || !empty($aOrderStates)) {
$oQb->join('t.oPayment', 'p');
}
if ($aGateways) {
$oQb->andWhere('p.sPaymentGateway IN (:gateways)')
->setParameter('gateways', $aGateways);
}
if ($aOrderStates) {
$oQb->andWhere('p.sState IN (:aOrderStates)')
->setParameter('aOrderStates', $aOrderStates);
}
if ($b3DS !== null) {
$oQb->andWhere('t.b3DS = :b3ds')
->setParameter('b3ds', $b3DS);
}
return $oQb->getQuery()->getResult();
}
/**
* @param AcquiredBatch $oAcquiredBatch AcquiredBatch object
* @return float|int|mixed|string
* @throws \Doctrine\ORM\NoResultException
* @throws \Doctrine\ORM\NonUniqueResultException
*/
public function calculateBalanceByBatch(AcquiredBatch $oAcquiredBatch)
{
$oQb = $this->oRepository->createQueryBuilder('t')
->select('SUM(t.fAmount) AS total')
->where('t.oAcquiredBatch = :acquiredBatch')
->andWhere('t.sState IN (:state)')
->setParameters([
'acquiredBatch' => $oAcquiredBatch,
'state' => [Transaction::STATE_SETTLED, Transaction::STATE_SUCCEEDED]
])
;
return $oQb->getQuery()->getSingleScalarResult();
}
}