Skip to content
This repository has been archived by the owner on Mar 29, 2022. It is now read-only.

Commit

Permalink
Merge pull request #13 from heidelpay/feature/PLENTY-88/add-sync-request
Browse files Browse the repository at this point in the history
feature/PLENTY-88/add-sync-request
  • Loading branch information
Simon Gabriel authored Mar 12, 2019
2 parents 68e9590 + 5df403b commit fc44da8
Show file tree
Hide file tree
Showing 11 changed files with 376 additions and 81 deletions.
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@
"required": false,
"label": "Config.invoicesecuredb2cChannelIdLabel",
"options": {
"defaultValue": "31HA07BC81895ACFE22C154CBC521922"
"defaultValue": "31HA07BC8129FBA7AF65934626B0F907"
}
},
"invoicesecuredb2c.minAmount": {
Expand Down
64 changes: 64 additions & 0 deletions resources/lib/invoiceSecuredB2CTransactionRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php
/**
* Performs credit card transaction requests.
*
* @license Use of this software requires acceptance of the License Agreement. See LICENSE file.
* @copyright Copyright © 2017-present heidelpay GmbH. All rights reserved.
*
* @link https://dev.heidelpay.com/plentymarkets
*
* @author Simon Gabriel <[email protected]>
*
* @package heidelpay\plentymarkets-gateway\external-lib-callbacks
*/

use Heidelpay\PhpPaymentApi\Request;

/** @var array $requestParams */
$requestParams = SdkRestApi::getParam('request');
$transactionType = SdkRestApi::getParam('transactionType');

$paymentMethod = new \Heidelpay\PhpPaymentApi\PaymentMethods\InvoiceB2CSecuredPaymentMethod();
$paymentMethod->setRequest(Request::fromPost($requestParams));

$responseArray = null;

$refId = SdkRestApi::getParam('referenceId') ?: null;
$paymentFrameOrigin = $paymentMethod->getRequest()->getFrontend()->getPaymentFrameOrigin();
$preventAsyncRedirect = $paymentMethod->getRequest()->getFrontend()->getPreventAsyncRedirect();
$cssPath = $paymentMethod->getRequest()->getFrontend()->getCssPath();

try {
if (!is_callable([$paymentMethod, $transactionType])) {
throw new \Exception('Invalid transaction type for InvoiceB2CSecured payment method (' . $transactionType . ')!');
}

if ($refId !== null) {
$response = $paymentMethod->{$transactionType}(
$refId,
$paymentFrameOrigin,
$preventAsyncRedirect,
$cssPath
);
} else {
$response = $paymentMethod->{$transactionType}($paymentFrameOrigin, $preventAsyncRedirect, $cssPath);
}
} catch (\Exception $e) {
$errorResponse = [
'exceptionCode' => $e->getCode(),
'exceptionMsg' => $e->getMessage(),
'exceptionTrace' => $e->getTraceAsString(),
];
}

// return the responseArray, if an exception has been thrown.
// else, return an array containing response results.
$responseObj = $paymentMethod->getResponse();
$responseArray = $responseObj->toArray();
ksort($responseArray);
return $errorResponse ?? [
'response' => $responseArray,
'isSuccess' => $responseObj->isSuccess(),
'isPending' => $responseObj->isPending(),
'isError' => $responseObj->isError(),
];
77 changes: 66 additions & 11 deletions resources/lib/submitBasket.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,82 @@
* @package heidelpay\plentymarkets-gateway\external-lib-callbacks
*/

use Heidelpay\PhpBasketApi\Object\BasketItem;
use Heidelpay\PhpBasketApi\Request as BasketApiRequest;

function normalizeValue($value) {
return (int)round(abs($value) * 100);
}

/** @var array $authData */
$authData = SdkRestApi::getParam('auth');
/** @var array $basketData */
$basketData = SdkRestApi::getParam('basket');
/** @var array $basketItems */
$basketItems = SdkRestApi::getParam('basketItems');
/** @var bool $sandmoxmode */
$sandboxmode = SdkRestApi::getParam('sandboxmode');

$basket = new \Heidelpay\PhpBasketApi\Object\Basket();
$basket->setAmountTotalNet((int) $basketData['basketAmountNet'] * 100);
//$basket->setAmountTotalVat($basketData['??']);
$basket->setAmountTotalDiscount((int) $basketData['basketRebate'] * 100);

foreach ($basketData['basketItems'] as $cartItem) {
$basketItem = new \Heidelpay\PhpBasketApi\Object\BasketItem();
$basketItem->setAmountGross((int) $cartItem['basketAmount'] * 100);
$basketItem->setAmountNet((int) $cartItem['basketAmountNet'] * 100);
$basketItem->setAmountDiscount((int) $cartItem['rebate'] * 100);
$basketItem->setQuantity((int) $cartItem['quantity'] * 100);
$basketItem->setVat((int) $cartItem['vat'] * 100);
$basketAmount = $basketData['basketAmount'];
$basketAmountNet = $basketData['basketAmountNet'];
$basketAmountVat = $basketAmount - $basketAmountNet;
$basket->setAmountTotalNet(normalizeValue($basketAmountNet))
->setCurrencyCode($basketData['currency'])
->setAmountTotalVat(normalizeValue($basketAmountVat));
$goodsAndShipmentNet = 0;

foreach ($basketItems as $item) {
$basketItem = new BasketItem();
$quantity = $item['quantity'];
$amount = $item['price'] * $quantity;
$vat = $item['vat'];
$amountNet = $amount * 100 / (100 + $vat);
$amountVat = $amount - $amountNet; // $amountNet * $vat / 100;
$basketItem->setAmountGross(normalizeValue($amount))
->setAmountVat(normalizeValue($amountVat))
->setAmountNet(normalizeValue($amountNet))
->setAmountDiscount(normalizeValue($item['rebate']))
->setQuantity($quantity)
->setVat($vat)
->setAmountPerUnit(normalizeValue($item['price']))
->setBasketItemReferenceId($item['id'])
->setTitle($item['title'])
->setType('goods');
$basket->addBasketItem($basketItem);
$goodsAndShipmentNet += $amountNet;
}

// Add shipping position
$shipping = new BasketItem();
$shippingAmount = $basketData['shippingAmount'];
$shippingNet = $basketData['shippingAmountNet'];
$shippingVat = $shippingAmount - $shippingNet;
$shipping->setAmountGross(normalizeValue($shippingAmount))
->setAmountNet(normalizeValue($shippingNet))
->setAmountVat(normalizeValue($shippingVat))
->setQuantity(1)
->setAmountPerUnit(normalizeValue($shippingAmount))
->setBasketItemReferenceId('shipment')
->setTitle('Shipment')
->setType('shipment');
$basket->addBasketItem($shipping);
$goodsAndShipmentNet += $shippingNet;

// Add discount position
$discountAmount = $basketData['couponDiscount'];
if ($discountAmount !== 0) {
$discountItem = new BasketItem();
$discountNet = $basketAmountNet - $goodsAndShipmentNet;
$discountItem->setAmountGross(normalizeValue($discountAmount))
->setAmountNet(normalizeValue($discountNet))
->setQuantity(1)
->setAmountPerUnit(normalizeValue($discountAmount))
->setBasketItemReferenceId('discount')
->setTitle('Discount')
->setType('voucher');

$basket->addBasketItem($discountItem);
}

$request = new BasketApiRequest();
Expand Down
60 changes: 30 additions & 30 deletions resources/views/invoiceSecuredB2CForm.twig
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
<label for="salutation" class="required">{{ trans('Heidelpay::template.salutation') }} <em>*</em></label>
</div>
<div class="col-md-2">
<select id="salutation" required>
<option value="" disabled selected>{{ trans('Heidelpay::template.choose') }}</option>
<option value="mr">{{ trans('Heidelpay::template.mr') }}</option>
<option value="mrs">{{ trans('Heidelpay::template.mrs') }}</option>
<select id="salutation" name="customer_salutation" required>
<option value="" disabled {% if customer_gender == '' %}selected{% endif %}>{{ trans('Heidelpay::template.choose') }}</option>
<option value="MR" {% if customer_gender == 'male' %}selected{% endif %}>{{ trans('Heidelpay::template.mr') }}</option>
<option value="MRS" {% if customer_gender == 'female' %}selected{% endif %}>{{ trans('Heidelpay::template.mrs') }}</option>
</select>
</div>
<div class="col-md-4"></div>
Expand All @@ -23,44 +23,44 @@
</div>
<div class="col-md-1">
<div class="input-box" style="width:100%">
<select id="dob_day" required>
<option disabled selected value="">{{ trans('Heidelpay::template.day') }}</option>
<option value="01">01</option><option value="02">02</option><option value="03">03</option>
<option value="04">04</option><option value="05">05</option><option value="06">06</option>
<option value="07">07</option><option value="08">08</option><option value="09">09</option>
<option value="10">10</option><option value="11">11</option><option value="12">12</option>
<option value="13">13</option><option value="14">14</option><option value="15">15</option>
<option value="16">16</option><option value="17">17</option><option value="18">18</option>
<option value="19">19</option><option value="20">20</option><option value="21">21</option>
<option value="22">22</option><option value="23">23</option><option value="24">24</option>
<option value="25">25</option><option value="26">26</option><option value="27">27</option>
<option value="28">28</option><option value="29">29</option><option value="30">30</option>
<option value="31">31</option>
<select id="dob_day" name="customer_dob_day" required>
<option disabled {% if customer_dob_day == '' %} selected {% endif %} value="">
{{ trans('Heidelpay::template.day') }}</option>
{% for day in 1..31 %}
{% set day = '%02d'|format(day) %}
<option value="{{ day }}"
{% if not customer_dob_day == '' and day == customer_dob_day %} selected{% endif %}>
{{ day }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="col-md-1">
<div class="input-box" style="width:100%">
<select title="dob_month" required>
<option disabled selected value="">{{ trans('Heidelpay::template.month') }}</option>
<option value="01">01</option><option value="02">02</option><option value="03">03</option>
<option value="04">04</option><option value="05">05</option><option value="06">06</option>
<option value="07">07</option><option value="08">08</option><option value="09">09</option>
<option value="10">10</option><option value="11">11</option><option value="12">12</option>
<select title="dob_month" name="customer_dob_month" required>
<option disabled {% if customer_dob_month == '' %} selected {% endif %} value="">
{{ trans('Heidelpay::template.month') }}</option>
{% for month in 1..12 %}
{% set month = '%02d'|format(month) %}
<option value="{{ month }}"
{% if not customer_dob_month == '' and month == customer_dob_month %} selected{% endif %}>
{{ month }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="col-md-1">
<div class="input-box" style="width:100%">
<select id="dob_year" required>
<option disabled selected value="">{{ trans('Heidelpay::template.year') }}</option>
<select id="dob_year" name="customer_dob_year" required>
<option disabled {% if customer_dob_year == '' %} selected {% endif %} value="">
{{ trans('Heidelpay::template.year') }}</option>
{% set minYear = "now -80 years"|date("Y") %}
{% set maxYear = "now -18 years"|date("Y") %}
<ul>
{% for year in maxYear..minYear %}
<option value="{{ year }}">{{ year }}</option>
{% endfor %}
</ul>
{% for year in maxYear..minYear %}
<option value="{{ year }}"
{% if not customer_dob_year == '' and year == customer_dob_year %} selected{% endif %}>
{{ year }}</option>
{% endfor %}
</select>
</div>
</div>
Expand Down
85 changes: 79 additions & 6 deletions src/Controllers/ResponseController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Heidelpay\Constants\Routes;
use Heidelpay\Exceptions\SecurityHashInvalidException;
use Heidelpay\Helper\PaymentHelper;
use Heidelpay\Methods\PaymentMethodContract;
use Heidelpay\Models\Transaction;
use Heidelpay\Services\Database\TransactionService;
use Heidelpay\Services\NotificationServiceContract;
Expand All @@ -14,6 +16,7 @@
use Plenty\Plugin\Controller;
use Plenty\Plugin\Http\Request;
use Plenty\Plugin\Http\Response;
use Symfony\Component\HttpFoundation\Response as BaseResponse;

/**
* Processes the transaction/payment responses coming from the heidelpay payment system.
Expand Down Expand Up @@ -70,6 +73,7 @@ public function __construct(
$this->urlService = $urlService;
}

//<editor-fold desc="Helpers">
/**
* Creates a transaction object and returns bool to indicate success.
*
Expand Down Expand Up @@ -106,6 +110,48 @@ private function createAndHandleTransaction($response, $responseObject): bool
return true;
}



/**
* Returns the salutation from the post request.
*
* @return string
* @throws \RuntimeException
*/
private function getSalutation(): string
{
if ($this->request->exists('customer_salutation')) {
return $this->request->get('customer_salutation');
}

throw new \RuntimeException('Salutation not set!');
}

/**
* Returns the date of birth from the request.
*
* @return string
* @throws \RuntimeException
*/
private function getDateOfBirth(): string
{
if ($this->request->exists('customer_dob_day') &&
$this->request->exists('customer_dob_month') &&
$this->request->exists('customer_dob_year')) {
return implode(
'-',
[
$this->request->get('customer_dob_year'),
$this->request->get('customer_dob_month'),
$this->request->get('customer_dob_day')
]
);
}

throw new \RuntimeException('Date of birth not set!');
}
//</editor-fold>

//<editor-fold desc="Handlers">
/**
* Process the incoming POST response and return the redirect url depending on the response result.
Expand Down Expand Up @@ -178,9 +224,9 @@ public function processPush(): Response
* the heidelpay API redirects to the processAsyncResponse url using GET instead of POST.
* This method is for handling this behaviour.
*
* @return \Symfony\Component\HttpFoundation\Response
* @return BaseResponse
*/
public function emergencyRedirect(): \Symfony\Component\HttpFoundation\Response
public function emergencyRedirect(): BaseResponse
{
$this->notification->warning('response.warningResponseCalledInInvalidContext', __METHOD__);
return $this->response->redirectTo('checkout');
Expand All @@ -190,13 +236,40 @@ public function emergencyRedirect(): \Symfony\Component\HttpFoundation\Response
* Handles form requests which do not need any further action by the client.
*
* @param BasketRepositoryContract $basketRepo
* @return \Symfony\Component\HttpFoundation\Response
* @param PaymentHelper $paymentHelper
* @return BaseResponse
* @throws \RuntimeException
*/
public function handleSyncRequest(BasketRepositoryContract $basketRepo): \Symfony\Component\HttpFoundation\Response
{
public function handleSyncRequest(
BasketRepositoryContract $basketRepo,
PaymentHelper $paymentHelper
): BaseResponse {
$basket = $basketRepo->load();
$this->notification->success('payment.infoPaymentSuccessful', __METHOD__, ['basket' => $basket]);

$mopId = $basket->methodOfPaymentId;
$paymentMethod = $paymentHelper->mapMopToPaymentMethod($mopId);
$methodInstance = $paymentHelper->getPaymentMethodInstanceByMopId($mopId);
if (!$methodInstance instanceof PaymentMethodContract) {
$this->notification->error('payment.errorDuringPaymentExecution', __METHOD__);
return $this->response->redirectTo('checkout');
}

$response = $this->paymentService->sendPaymentRequest(
$basket,
$paymentMethod,
$methodInstance->getTransactionType(),
$mopId,
['birthday' => $this->getDateOfBirth(), 'salutation' => $this->getSalutation()]
);

if ($response['isError'] === true) {
$responseObj = $response['response'];
$errorMsg = ($responseObj['PROCESSING.REASON'] ?? '') . ': ' . ($responseObj['PROCESSING.RETURN'] ?? '');
$this->notification->error('payment.errorDuringPaymentExecution', __METHOD__, ['Message' => $errorMsg]);
return $this->response->redirectTo('checkout');
}

$this->notification->success('payment.infoPaymentSuccessful', __METHOD__);
return $this->response->redirectTo('place-order');
}
//</editor-fold>
Expand Down
Loading

0 comments on commit fc44da8

Please sign in to comment.