Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

B 7.0.x pspaypal 812 takeover pspaypal 806 #349

Closed
wants to merge 13 commits into from
23 changes: 21 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### FIX

- Fix admin block parent call, thanks to Alpha-Sys
- Fix Errorlog-Message "Duplicate entry ..." + fix Update send PUI-Bankdata via Webhook
- Fix PayPalExpress Reauth is necessary if the cart amount (total is greater than before) has changed during the checkout process
- Fix, don't show vaulting-Boxes if it is deactivated in Backend
- [0007656](https://bugs.oxid-esales.com/view.php?id=7656): Fix incompatibility with Klarna-Module
- better Vaulting-Check in PaymentController
- disable Vaulting-Setting if Vaulting not possible
- [0007666](https://bugs.oxid-esales.com/view.php?id=7666): Fix: Price surcharges on the detail page for selection lists are not taken into account
- disable Vaulting-Option of Creditcard if Creditcard are not eligible
- Automatically save Apple Pay certificates during the Apple Pay eligibility check
- [0007681](https://bugs.oxid-esales.com/view.php?id=7681): fix OXID Logger.ERROR: Call to a member function getFieldData() on bool
- [0007675](https://bugs.oxid-esales.com/view.php?id=7675): fix the possibility to finish order without redirect and login to Paypal
- [0007676](https://bugs.oxid-esales.com/view.php?id=7676): If we have a corrupted generated_services.yaml and try to deactivate the module via the admin, we will display a more understandable error message about what happened.
- introduce ActionHash to make the PayPal-Request-ID more unique
- use PayPal-Client v2.0.15
- [0007588](https://bugs.oxid-esales.com/view.php?id=7588): Improve Error handling for Capture Order Requests (thanks to mount7)
- remove Sofort and MyBank, Paymentmethods will soon no longer be accepted via PayPal
- fix: Refund only with note to Buyer (required)
Expand All @@ -18,8 +33,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- [0007666](https://bugs.oxid-esales.com/view.php?id=7666): Fix: Price surcharges on the detail page for selection lists are not taken into account
- [0007695](https://bugs.oxid-esales.com/view.php?id=7695): Fix: if DeliverySet is set in Frontend, then do not add any PseudoDeliveryCosts for PPExpress

### NEW

### NEW
- PayPal-Request-Id based on serialized body, no extra PayPal-Request-Id necessary anymore
- Introduce GooglePay-Payment
- Introduce ApplePay-Payment
- use PayPal-Client v2.0.14
- add Default-Shippingcosts for PP-Express to prevent overcharge.
- provide Smarty-Templates again for OXID7.0 - thank you to D3-Team
- use PayPal-Request-ID in any API-Call (via Client, v3.0.10)
- add Default-Shippingcosts for PP-Express to prevent overcharge.
Expand Down
13 changes: 12 additions & 1 deletion src/Controller/Admin/PayPalConfigController.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use OxidSolutionCatalysts\PayPal\Module;
use OxidSolutionCatalysts\PayPal\Service\ModuleSettings;
use OxidSolutionCatalysts\PayPal\Traits\ServiceContainer;
use OxidSolutionCatalysts\PayPalApi\Exception\ApiException;
use Throwable;

/**
Expand Down Expand Up @@ -208,7 +209,17 @@ protected function checkEligibility(): void
$onBoardingClient = $handler->getOnboardingClient($config->isSandbox(), true);
$merchantInformations = $onBoardingClient->getMerchantInformations();
$handler->saveEligibility($merchantInformations);
} catch (ClientException $exception) {
if (isset($confArr['oscPayPalSetVaulting'])) {
$moduleSettings = $this->getServiceFromContainer(ModuleSettings::class);
$isEligible = $moduleSettings->isSandbox()
? $moduleSettings->isSandboxVaultingEligibility()
: $moduleSettings->isLiveVaultingEligibility();

if (!$isEligible) {
$moduleSettings->save('oscPayPalSetVaulting', false);
}
}
} catch (ClientException|ApiException $exception) {

/** @var Logger $logger */
$logger = $this->getServiceFromContainer(Logger::class);
Expand Down
5 changes: 2 additions & 3 deletions src/Core/Api/IdentityService.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@ public function requestClientToken(): array
$headers['Content-Type'] = 'application/json';
$headers = array_merge($headers, $this->getAuthHeaders());

$path = '/generate-token';
$method = 'post';
$path = '/v1/identity/generate-token';

/** @var ResponseInterface $response */
$response = $this->send($method, $path, [], $headers);
$response = $this->send('POST', $path, [], $headers);
$body = $response->getBody();

return $body ? json_decode((string)$body, true) : [];
Expand Down
252 changes: 252 additions & 0 deletions src/Core/Api/VaultingService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
<?php

/**
* Copyright © OXID eSales AG. All rights reserved.
* See LICENSE file for license details.
*/

namespace OxidSolutionCatalysts\PayPal\Core\Api;

use JsonException;
use OxidEsales\Eshop\Application\Model\Country;
use OxidEsales\Eshop\Application\Model\State;
use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\ViewConfig;
use OxidSolutionCatalysts\PayPal\Core\Constants;
use OxidSolutionCatalysts\PayPalApi\Exception\ApiException;
use OxidSolutionCatalysts\PayPalApi\Service\BaseService;

class VaultingService extends BaseService
{
public function generateUserIdToken($payPalCustomerId = false): array
{
$headers = [];
$headers['Content-Type'] = 'application/x-www-form-urlencoded';
$headers['PayPal-Partner-Attribution-Id'] = Constants::PAYPAL_PARTNER_ATTRIBUTION_ID_PPCP;

$params['grant_type'] = 'client_credentials';
$params['response_type'] = 'id_token';

if ($payPalCustomerId) {
$params["target_customer_id"] = $payPalCustomerId;
}

$path = '/v1/oauth2/token';

$response = $this->send('POST', $path, $params, $headers);
$body = $response->getBody();

return json_decode((string)$body, true);
}

/**
* Request a setup token either for card or for PayPal vaulting
* @param bool $card
* @return array
* @throws ApiException
* @throws JsonException
*/
public function createVaultSetupToken(bool $card = false): array
{
if ($card) {
$body = [
"payment_source" => [
"card" => [],
]
];
} else {
$body = $this->getPaymentSourceForVaulting($card);
}

//add customerid if there already is one
if ($paypalCustomerId = Registry::getConfig()->getUser()->getFieldData("oscpaypalcustomerid")) {
$body["customer"] = [
"id" => $paypalCustomerId
];
}

$headers = $this->getVaultingHeaders();

$path = '/v3/vault/setup-tokens';

$response = $this->send(
'POST',
$path,
[],
$headers,
json_encode($body, JSON_THROW_ON_ERROR | JSON_FORCE_OBJECT)
);
$body = $response->getBody();

return json_decode((string)$body, true);
}

/**
* @param bool $card
* @return array[]
*/
public function getPaymentSourceForVaulting(bool $card): array
{
$viewConf = Registry::get(ViewConfig::class);
$config = Registry::getConfig();
$user = $viewConf->getUser();

$country = oxNew(Country::class);
$country->load($user->getFieldData('oxcountryid'));

$state = oxNew(State::class);
$state->loadByIdAndCountry(
$user->getFieldData('oxstateid'),
$user->getFieldData('oxcountryid')
);

$shopName = Registry::getConfig()->getActiveShop()->getFieldData('oxname');
$lang = Registry::getLang();

$description = sprintf($lang->translateString('OSC_PAYPAL_DESCRIPTION'), $shopName);

$activeShop = Registry::getConfig()->getActiveShop();

$name = $user->getFieldData("oxfname");
$name .= $user->getFieldData("oxlname");
$address = [
"address_line_1" => $user->getFieldData('oxstreet') . " " . $user->getFieldData('oxstreetnr'),
"address_line_2" => $user->getFieldData('oxcompany') . " " . $user->getFieldData('oxaddinfo'),
"admin_area_1" => $state->getFieldData('oxtitle'),
"admin_area_2" => $user->getFieldData('oxcity'),
"postal_code" => $user->getFieldData('oxzip'),
"country_code" => $country->oxcountry__oxisoalpha2->value,
];
$locale =
strtolower($country->oxcountry__oxisoalpha2->value)
. '-'
. strtoupper($country->oxcountry__oxisoalpha2->value);
$experience_context = [
"brand_name" => $activeShop->getFieldData('oxname'),
"locale" => $locale,
"return_url" => $config->getSslShopUrl() . 'index.php?cl=order&fnc=finalizepaypalsession',
"cancel_url" => $config->getSslShopUrl() . 'index.php?cl=order&fnc=cancelpaypalsession',
// "shipping_preference" => "SET_PROVIDED_ADDRESS",
];

if ($card) {
$paymentSource = [
"card" => [
"name" => "$name",
"billing_address" => $address,
"verification_method" => "SCA_WHEN_REQUIRED",
"experience_context" => $experience_context,
"attributes" => [
"verification" => [
"method" => "SCA_WHEN_REQUIRED"
],
"vault" => [
"store_in_vault" => "ON_SUCCESS"
]
],
]
];
} else {
$paymentSource = [
"payment_source" => [
"paypal" => [
"description" => $description,
"shipping" => [
"name" => [
"full name" => $name
],
"address" => $address
],
"usage_type" => "MERCHANT",
"customer_type" => "CONSUMER",
"permit_multiple_payment_tokens" => true,
"usage_pattern" => "IMMEDIATE",
"experience_context" => $experience_context
]
]
];
}

return $paymentSource;
}

public function createVaultPaymentToken($setupToken)
{
$headers = $this->getVaultingHeaders();

$path = '/v3/vault/payment-tokens';

$requestBody = [
"payment_source" => [
"token" => [
"id" => $setupToken,
"type" => "SETUP_TOKEN",
]
]
];

$response = $this->send('POST', $path, [], $headers, json_encode($requestBody));
$responseBody = $response->getBody();

return json_decode((string)$responseBody, true);
}

public function getVaultPaymentTokens($paypalCustomerId)
{
$viewConf = oxNew(ViewConfig::class);
if (!$viewConf->getIsVaultingActive()) {
return null;
}

$path = '/v3/vault/payment-tokens?customer_id=' . $paypalCustomerId;

$response = $this->send('GET', $path);
$body = $response->getBody();

return json_decode((string)$body, true);
}

public function getVaultPaymentTokenByIndex($paypalCustomerId, $index)
{
$paymentTokens = $this->getVaultPaymentTokens($paypalCustomerId);

return $paymentTokens["payment_tokens"][$index];
}

/**
* @param $paymentTokenId
* @return bool
*/
public function deleteVaultedPayment($paymentTokenId)
{
$path = '/v3/vault/payment-tokens/' . $paymentTokenId;

$response = $this->send('DELETE', $path);

return $response->getStatusCode() == 204;
}

/**
* @return array
*/
protected function getVaultingHeaders(): array
{
$headers = [];
$headers['Content-Type'] = 'application/json';
$headers['PayPal-Partner-Attribution-Id'] = Constants::PAYPAL_PARTNER_ATTRIBUTION_ID_PPCP;
$headers = array_merge($headers, $this->getAuthHeaders());
return $headers;
}

protected function getAuthHeaders(): array
{
if (!$this->client->isAuthenticated()) {
$this->client->auth();
}

$headers = [];
$headers['Authorization'] = 'Bearer ' . $this->client->getTokenResponse();

return $headers;
}
}
14 changes: 12 additions & 2 deletions src/Core/Onboarding/Onboarding.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ public function getOnboardingClient(bool $isSandbox, bool $withCredentials = fal
{
$paypalConfig = oxNew(PayPalConfig::class);
$partnerConfig = oxNew(PartnerConfig::class);
$session = Registry::getSession();
$sessionId = $session->getId();
$actionHash = md5($sessionId);

$clientId = '';
$clientSecret = '';
Expand All @@ -126,11 +129,18 @@ public function getOnboardingClient(bool $isSandbox, bool $withCredentials = fal
$clientSecret,
$partnerConfig->getTechnicalPartnerId($isSandbox),
$merchantId,
$paypalConfig->getTokenCacheFileName()
$paypalConfig->getTokenCacheFileName(),
$actionHash
);
}

public function fetchMerchantInformations()
/**
* @return array
* @throws ApiException
* @throws JsonException
* @throws OnboardingException
*/
public function fetchMerchantInformations(): array
{
$onboardingResponse = $this->getOnboardingPayload();
/** @var ApiOnboardingClient $apiClient */
Expand Down
4 changes: 2 additions & 2 deletions src/Core/Onboarding/Webhook.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public function registerWebhooks(): string

/** @var GenericService $notificationService */
$webhookService = Registry::get(ServiceFactory::class)->getWebhookService();
$webHookResponse = $webhookService->request('post', $paypload);
$webHookResponse = $webhookService->request('POST', $paypload);

$webhookId = $webHookResponse['id'] ?? '';
} catch (Exception $exception) {
Expand Down Expand Up @@ -119,7 +119,7 @@ public function getAllRegisteredWebhooks(): array
{
/** @var GenericService $notificationService */
$webhookService = Registry::get(ServiceFactory::class)->getWebhookService();
$result = $webhookService->request('get');
$result = $webhookService->request('GET');

return $result['webhooks'] ?? [];
}
Expand Down
Loading
Loading