getModuleConfiguration()->isActive()) { return false; } $oSettings = $factory->getSettings(); /** @var OxidPayment $oPayment */ $oPayment = oxNew(OxidPayment::class); $oPayment->load($this->getFieldData('oxpaymenttype')); if (false == $oSettings->isAssignedToHeidelPayment($oPayment)) { return false; } $heidelpayment = $oSettings->getPayment($oPayment); if ($factory->getModuleProvider()->isHeidelpayInterfaceNGWActive() && ( $heidelpayment instanceof Prepayment || $heidelpayment instanceof Secured || $heidelpayment instanceof Unsecured || $heidelpayment instanceof Btobbillpurchase ) ) { /** @var PrepaymentData $oPrePaymentData */ $oPrePaymentData = oxNew(PrepaymentData::class); return $oPrePaymentData->getBankTransferData($this, $heidelpayment->getPaymentCode() . '.PA'); } if ($factory->getModuleProvider()->isHeidelpayInterfaceMGWRestActive() && $heidelpayment->isMGWPayment() && ( $heidelpayment instanceof Prepayment || $heidelpayment instanceof Secured || $heidelpayment instanceof Unsecured || $heidelpayment instanceof Btobbillpurchase ) ) { $paymentId = $this->getFieldData('oxtransid'); if (!str_contains($paymentId, 's-pay-') && !str_contains($paymentId, 'p-pay-')) { return false; } try { $result = $factory->getMgwResourceHandler()->obtainPaymentAuthorizationByPayID($paymentId); if (empty($result)) { $result = $factory->getMgwResourceHandler()->obtainPaymentChargesByID($paymentId); $result = $result[0]; } } catch (UnzerApiException $e) { $factory->getModuleConfiguration()->d3getLog()->error( self::class, __FUNCTION__, __LINE__, "Unzer api exception: " . PHP_EOL . "client message: " . $e->getClientMessage() // . PHP_EOL . "merchant message: ". $e->getMerchantMessage(), var_export($e, true) ); } return $result; } return false; } /** * @return null * @throws PaymentNotReferencedToUnzerException * @throws d3ShopCompatibilityAdapterException * @throws d3_cfg_mod_exception * @throws DBALException * @throws DatabaseConnectionException * @throws DatabaseErrorException * @throws StandardException */ public function getHeidelpayEasyCreditInformations() { /** @var Factory $factory */ $factory = oxNew(Factory::class); /** @var OxidPayment $payment */ $payment = oxNew(OxidPayment::class); $payment->load($this->getFieldData('oxpaymenttype')); if (false == $factory->getChannelProvider()->isOxPaymentIdAssignedToChannel($payment->getId())) { return null; } $settings = $factory->getSettings(); $heidelpayment = $settings->getPayment($payment); if ($heidelpayment instanceof Easycredit) { /** @var d3transactionlog $transaction */ $transaction = $factory->getLatestTransactionByObject($this); if (false === ($transaction instanceof d3transactionlog)) { return null; } /** @var TransactionlogReader $reader */ /** @var Criterions $criterionContainer */ $reader = $transaction->getTransactiondata(); $criterionContainer = oxNew(Criterions::class, oxNew(Criterions\Easycredit::class)); return $criterionContainer->getSelectedCriterions($reader->getCriterionTags()); } return null; } /** * * @return int|null * @throws DBALException * @throws Exception * @throws DatabaseConnectionException * @throws DatabaseErrorException */ public function d3CreateTemporaryOrder(Basket $oBasket, User $oUser) { /* D3 START disabled - 03.03.2016 - KH */ $this->setId(Registry::get(UtilsObject::class)->generateUId()); // validating various order/basket parameters before finalizing $iOrderState = $this->validateOrder($oBasket, $oUser); if ($iOrderState) { return $iOrderState; } // copies user info $this->setUser($oUser); // copies basket info $this->loadFromBasket($oBasket); // payment information $this->setPayment($oBasket->getPaymentId()); // set folder information, if order is new // #M575 in recalculating order case folder must be the same as it was $this->setFolder(); //#4005: Order creation time is not updated when order processing is complete $this->updateOrderDate(); // marking as not finished $this->setOrderStatus('PENDING'); $aVouchers = $oBasket->getVouchers(); /** @var Factory $factory */ $factory = oxNew(Factory::class); if (count($aVouchers)) { $aVoucherIds = []; $pendingLimit = $factory->getModuleProvider()->getPaymentCollectorOrderPendingTime(); foreach ($aVouchers as $oStdVoucher) { /** @var Voucher $oVoucher */ $oVoucher = oxNew(Voucher::class); if ($oVoucher->load($oStdVoucher->sVoucherId)) { $aVoucherIds[$oStdVoucher->sVoucherId] = $oStdVoucher->sVoucherId; $oVoucher->assign(['oxreserved' => time() + $pendingLimit * 3600]); $oVoucher->save(); } } $this->assign(['d3heidelpayvouchers' => implode('|', $aVoucherIds)]); } //saving all order data to DB $this->save(); if (false == $factory->getModuleProvider()->isUsingZeroOrderNumber() && false == $this->oxorder__oxordernr->value) { $this->setNumber(); } // set order ID for thankyou $oBasket->setOrderId($this->getId()); Registry::getSession()->setVariable('sess_challenge', $this->getId()); return null; } /** * @param string $sStatus * * @return void * @throws PaymentNotReferencedToUnzerException * @throws d3ShopCompatibilityAdapterException * @throws d3_cfg_mod_exception * @throws DBALException * @throws DatabaseConnectionException * @throws DatabaseErrorException * @throws StandardException */ protected function setOrderStatus($sStatus) { /** @var Factory $factory */ $factory = oxNew(Factory::class); if (! $factory->getModuleConfiguration()->isActive()) { parent::setOrderStatus($sStatus); return; } if ($factory->getModuleProvider()->isHeidelpayInterfaceMGWRestActive()) { parent::setOrderStatus($sStatus); return; } if ($factory->getModuleProvider()->isHeidelpayInterfaceNGWActive()) { $oDB = DatabaseProvider::getDb(); $sOldStatus = $oDB->getOne('select oxtransstatus from oxorder where oxid="' . $this->getId() . '"'); $sPaid = $oDB->getOne('select oxpaid from oxorder where oxid="' . $this->getId() . '"'); $sPaymentId = $this->getFieldData('OXPAYMENTTYPE'); /** @var Factory $factory */ $factory = oxNew(Factory::class); /** @var OxidPayment $payment */ $payment = oxNew(OxidPayment::class); $payment->load($sPaymentId); if (! $factory->getChannelProvider()->isOxPaymentIdAssignedToChannel($payment->getId())) { parent::setOrderStatus($sStatus); return; } $settings = $factory->getSettings(); $blIsPrepayment = $settings->getPayment($payment) instanceof Prepayment; $blIsWaiting = $sOldStatus == 'PENDING' && $sPaid == '0000-00-00 00:00:00'; if ($blIsPrepayment && $blIsWaiting) { $sStatus = "PENDING"; } } parent::setOrderStatus($sStatus); } /** * * @return bool|int * @throws d3ShopCompatibilityAdapterException * @throws d3_cfg_mod_exception * @throws DBALException * @throws DatabaseConnectionException * @throws DatabaseErrorException * @throws StandardException * @throws Exception */ public function d3FinalizeTemporaryOrder(Basket $oBasket, User $oUser) { /** @var Factory $factory */ $factory = oxNew(Factory::class); $registry = Registry::get(Registry::class); $modulConfiguration = $factory->getModuleConfiguration(); $oUserPayment = $this->setPayment($oBasket->getPaymentId()); // executing payment (on failure deletes order and returns error code) // in case when recalculating order, payment execution is skipped $blRet = $this->executePayment($oBasket, $oUserPayment); if ($blRet !== true) { return $blRet; } if (!$this->oxorder__oxordernr->value) { $this->setNumber(); } else { /** @var Counter $counter */ $counter = oxNew(Counter::class); $counter->update($this->getCounterIdent(), $this->oxorder__oxordernr->value); } // deleting remark info only when order is finished Registry::getSession()->deleteVariable('ordrem'); //#4005: Order creation time is not updated when order processing is complete //$this->updateOrderDate(); // updating order trans status (success status) $this->setOrderStatus('OK'); // store orderid $oBasket->setOrderId($this->getId()); // updating wish lists $this->updateWishlist($oBasket->getContents(), $oUser); // updating users notice list $this->updateNoticeList($oBasket->getContents(), $oUser); // marking vouchers as used and sets them to $this->aVoucherList (will be used in order email) // skipping this action in case of order recalculation $this->markVouchers($oBasket, $oUser); // send order by email to shop owner and current user // skipping this action in case of order recalculation $iRet = $this->sendOrderByEmail($oUser, $oBasket, $oUserPayment); // the negative case shouldn't be possible $this->d3VerifyBasketSameAmount($oBasket, $modulConfiguration, $registry); return $iRet; } /** * TODO: outsource this in a own model * * * @return null * @throws d3ShopCompatibilityAdapterException * @throws d3_cfg_mod_exception * @throws DBALException * @throws DatabaseConnectionException * @throws DatabaseErrorException * @throws StandardException */ protected function d3VerifyBasketSameAmount(Basket $oxBasket, d3_cfg_mod $modulConfiguration, Registry $registry) { $transaction = $this->d3GetLastHeidelpayTransaction($oxBasket, $modulConfiguration); if (is_null($transaction)) { return null; } /** @var TransactionlogReader $reader */ $reader = $transaction->getTransactiondata(); $amount = $reader->getAmount(); if ($amount !== $this->getTotalOrderSum()) { /** @var Factory $factory */ $factory = oxNew(Factory::class); $transStatusError = $factory->getModuleProvider()->getOxTransStatusErrorState(); if (empty($transStatusError)) { $transStatusError = 'ERROR'; } $this->setD3HPTransactionStatusError($transStatusError); $this->d3SendHPErrorMessage($modulConfiguration, $registry, $reader, $this->getTotalOrderSum()); } return null; } /** * * @return d3transactionlog|null |null * @throws d3ShopCompatibilityAdapterException * @throws d3_cfg_mod_exception * @throws DBALException * @throws DatabaseConnectionException * @throws DatabaseErrorException * @throws StandardException */ protected function d3GetLastHeidelpayTransaction(Basket $oxBasket, d3_cfg_mod $modulConfiguration) { /** @var OxidPayment $oPayment */ $oPayment = oxNew(OxidPayment::class); $oPayment->load($oxBasket->getPaymentId()); /** @var Factory $factory */ $factory = oxNew(Factory::class); try { /** @var Payment $heidelPayment */ $heidelPayment = $factory->getSettings()->getPayment($oPayment); } catch (PaymentNotReferencedToUnzerException) { return null; } if (false == $heidelPayment instanceof Payment) { return null; } $refrenceNumber = $factory->getReferenceNumber(); if (empty($refrenceNumber)) { $modulConfiguration->d3getLog()->error( self::class, __FUNCTION__, __LINE__, "no reference but Unzer payment! payment is: " . var_export($heidelPayment, true) ); return null; } $transaction = $factory->getLatestTransactionByReference($refrenceNumber); if (false == $transaction) { $modulConfiguration->d3getLog()->warning( self::class, __FUNCTION__, __LINE__, 'no transaction found but Unzer payment and referencenumber', $refrenceNumber ); return null; } return $transaction; } /** * @param $transStatusError * @param bool $resetPaidDate */ public function setD3HPTransactionStatusError($transStatusError, $resetPaidDate = true) { $aAssignment = []; $aAssignment['oxtransstatus'] = $transStatusError; if ($resetPaidDate) { $aAssignment['oxpaid'] = '0000-00-00 00:00:00'; } $this->assign($aAssignment); $this->save(); } /** * TODO refactor into separate class * * @param $basketAmount * * @throws d3ShopCompatibilityAdapterException * @throws d3_cfg_mod_exception * @throws DBALException * @throws DatabaseConnectionException * @throws DatabaseErrorException * @throws StandardException */ public function d3SendHPErrorMessage(d3_cfg_mod $modulConfiguration, Registry $registry, TransactionlogReader $reader, $basketAmount) { $text = $registry->getLang()->translateString( 'D3UNZER_DIFFERENCE_IN_ORDER_ERRRORMESSAGE', Registry::getLang()->getBaseLanguage(), true ); $message = sprintf($text, $this->getFieldData('oxordernr'), $reader->getUniqueid(), $reader->getAmount(), $basketAmount); $message .= PHP_EOL. "ordernr: ". $this->getFieldData('oxordernr'); $message .= PHP_EOL. "uniqueid: ". $reader->getUniqueid(); $message .= PHP_EOL. "Unzer amount: ".$reader->getAmount(); $message .= PHP_EOL. "basket amount: ". $basketAmount; $subject = $registry->getLang()->translateString( 'D3UNZER_DIFFERENCE_IN_ORDER_SUBJECT', Registry::getLang()->getBaseLanguage(), true ); $subject .= $this->getFieldData('oxordernr'); /** @var Factory $factory */ $factory = oxNew(Factory::class); /** @var Mail $email */ $email = oxNew(Mail::class, oxNew(Email::class), $modulConfiguration, Registry::getConfig()->getActiveShop()); $email->setSubject($subject)->setMessage($message)->sendMail($factory); } /** * @return Basket * @throws ArticleException * @throws ArticleInputException * @throws NoArticleException * @throws SystemComponentException */ public function d3GetOrderBasket() { $this->reloadDelivery(false); $this->reloadDiscount(false); $oBasket = $this->getOrderBasket(false); foreach ($this->getOrderArticles() as $oOrderArticle) { $oBasket->addOrderArticleToBasket($oOrderArticle); } /* D3 START added - #4998 - 29.04.2016 - KH */ $aVouchers = explode('|', $this->getFieldData('d3heidelpayvouchers')); $oBasket->setSkipVouchersChecking(true); foreach ($aVouchers as $sVoucherId) { $oVoucher = oxNew(Voucher::class); if ($oVoucher->load($sVoucherId)) { $oBasket->addVoucher($sVoucherId); } } /* D3 END added - #4998 - 29.04.2016 - KH */ //$oBasket->setVoucherDiscount($this->oxorder__oxvoucherdiscount->value); $oBasket->calculateBasket(); foreach ($oBasket->getContents() as $oBasketItem) { /** @var BasketItem $oBasketItem */ /** @var Article $oArticle */ $oArticle = oxNew(Article::class); $oArticle->loadInLang($this->oxorder__oxlang->value, $oBasketItem->getArticle()->getProductId()); $oBasketItem->d3SetArticle($oArticle); } return $oBasket; } /** * @param Basket $oxBasket * @param object $oxUser * @param bool $blRecalculatingOrder * * @return int * @throws d3_cfg_mod_exception * @throws Exception */ public function finalizeOrder(Basket $oBasket, $oUser, $blRecalculatingOrder = false) { /** @var Factory $factory */ $factory = oxNew(Factory::class); $registry = $factory->getOxidProvider()->getRegistry(); $modulConfiguration = $factory->getModuleConfiguration(); if (false == $blRecalculatingOrder && $modulConfiguration->isActive() && $factory->getModuleProvider()->isHeidelpayInterfaceMGWRestActive()) { $sPaymentid = $oBasket->getPaymentId(); /** @var OxidPayment $payment */ $payment = oxNew(OxidPayment::class); $heidelPaySettings = $factory->getSettings(); if ($payment->load($sPaymentid) && $heidelPaySettings->isAssignedToHeidelPayment($payment)) { Registry::getSession()->setVariable(self::MGW_ORDERINPROGRESS, true); $factory->getModuleConfiguration()->d3getLog()->info( self::class, __FUNCTION__, __LINE__, 'mgw: begin surpressing e-mail sendind' ); $this->setD3HeidelpayIsSurpressEMailSending($factory); $factory->getModuleConfiguration()->d3getLog()->info( self::class, __FUNCTION__, __LINE__, 'mgw: end surpressing e-mail sendind' ); } } if ($factory->getModuleProvider()->isHeidelpayInterfaceNGWActive()) { try { $paymentId = $oBasket->getPaymentId(); $payment = oxNew(OxidPayment::class); $payment->load($paymentId); /** @var Viewconfig $heidelpayViewConfig */ $heidelpayViewConfig = oxNew( Viewconfig::class, d3_cfg_mod::get('d3unzer'), Registry::get(Registry::class), $factory ); $settings = $heidelpayViewConfig->getSettings(); $heidelPayment = $settings->getPayment($payment); if ($heidelPayment instanceof Secured) { /** @var HPPaymentController $paymentController */ $paymentController = oxNew(PaymentController::class); if (false == $paymentController->isHeidelpayInvoiceSecuredAllowed($oBasket)) { return self::ORDER_STATE_PAYMENTERROR; } } } catch (PaymentNotReferencedToUnzerException) { // ignore exception, because it's handled already before } } $return = parent::finalizeOrder($oBasket, $oUser, $blRecalculatingOrder); if (false == $modulConfiguration->isActive() || $registry->getConfig()->isAdmin()) { return $return; } if ($factory->getModuleProvider()->isHeidelpayInterfaceMGWRestActive()) { $factory->getModuleConfiguration()->d3getLog()->info( self::class, __FUNCTION__, __LINE__, 'mgw: return: '.$return ); return $return; } $this->d3VerifyBasketSameAmount($oBasket, $modulConfiguration, $registry); $this->d3SetWaitingState($oBasket, $modulConfiguration); return $return; } /** * @param $modulConfiguration * * @return null * @throws DBALException * @throws DatabaseConnectionException * @throws DatabaseErrorException * @throws StandardException * @throws SystemComponentException * @throws d3ShopCompatibilityAdapterException * @throws d3_cfg_mod_exception */ protected function d3SetWaitingState(Basket $basket, $modulConfiguration) { $transaction = $this->d3GetLastHeidelpayTransaction($basket, $modulConfiguration); if (false == ($transaction instanceof d3transactionlog)) { return null; } /** @var Parser $oParser */ $oParser = oxNew(Parser::class, $transaction->getTransactiondata()); if ('OK' !== $this->getFieldData('oxtransstatus') || false === $oParser->isWaiting()) { return null; } $this->setD3HPTransactionStatusError('PENDING', true); return null; } protected function sendOrderByEmail($oUser = null, $oBasket = null, $oPayment = null) { $return = self::ORDER_STATE_OK; $this->oUser = $oUser; $this->oBasket = $oBasket; $this->oPayment = $oPayment; if (false == $this->d3HeidelpayIsSurpressEMailSending) { return parent::sendOrderByEmail($oUser, $oBasket, $oPayment); } return $return; } /** * * @return bool * @throws DBALException * @throws StandardException */ public function d3HeidelpaySendOrderByEmail(Basket $basket, User $user) { $oUserPayment = $this->setPayment($basket->getPaymentId()); /** @var Factory $factory */ $factory = oxNew(Factory::class); $factory->getModuleConfiguration()->d3getLog()->info( self::class, __FUNCTION__, __LINE__, 'mgw: send order mail' ); return parent::sendOrderByEmail($user, $basket, $oUserPayment); } /** * @throws SystemComponentException */ public function setD3HeidelpayIsSurpressEMailSending(Factory $factory) { $factory->getOxidProvider()->getSession()->setVariable($factory::HeidelpaySurpressEmailStateSessionName, true); $this->d3HeidelpayIsSurpressEMailSending = true; } /** * @param $payId * @param $orderId * * @throws DatabaseConnectionException * @throws StandardException */ public function d3GetOrderByMgwPayId($payId, $orderId) { $query = "SELECT oxid FROM ".$this->getViewName()." WHERE oxtransid = ? AND oxordernr = ?"; $oxid = DatabaseProvider::getDb()->getOne($query, [$payId, $orderId]); if (false == $oxid || false == $this->load($oxid)) { throw oxNew(StandardException::class, 'no order loadable by transid = '.$payId.' and ordernr = '.$orderId); } } }