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

871 patch factory refactor + tests #417

Merged
merged 6 commits into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- set connect-timeout for 5 Seconds and request-timeout for 30 seconds
- [0007771](https://bugs.oxid-esales.com/view.php?id=7771): Paypal can only work with two decimal places. For shops with configured additional decimal places, the corresponding rounding takes place
- [0007772](https://bugs.oxid-esales.com/view.php?id=7772): Fix pay in nettomode
- Fix line item amounts in case of discounts (Discussion here https://forum.oxid-esales.com/t/paypal-modul-2-5-1-fehler-bei-rabatten-fehler-die-1223354igste/99472)

## [2.5.2] - 2025-02-06

Expand Down
162 changes: 78 additions & 84 deletions src/Core/PatchRequestFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,106 +26,91 @@
*/
class PatchRequestFactory
{
/**
* @var array
*/
private $request = [];

/**
* @var Basket
*/
private $basket;

/**
* @param Basket $basket
* Returns array of patches that will be applied to an Order
*
* @param Basket $basket
* @param string $orderId
* @return array
*/
public function getRequest(
public function getOrderPatches(
Basket $basket,
string $orderId = ''
): array {
$this->basket = $basket;
$currency = Registry::getConfig()->getActShopCurrencyObject();
//we can't sent basket items along with order request when precision level is above 2
$withItems = !$this->basket->isCalculationModeNetto() && !($currency->decimal > 2);
$currency = $basket->getBasketCurrency();
$deliveryId = Registry::getSession()->getVariable("deladrid");
$deliveryAddress = oxNew(Address::class);

$this->getShippingNamePatch();
$this->getShippingAddressPatch();
$this->getAmountPatch();
if ($orderId) {
$this->getCustomIdPatch($orderId);
}
if ($withItems) {
$this->getPurchaseUnitsPatch(
$this->basket,
$currency
);
$patches = array_values(
array_filter([
$this->getAmountPatch(),
$orderId ? $this->getCustomIdPatch($orderId) : null,
$this->getPurchaseUnitsPatch()
])
);

if ($deliveryId && $deliveryAddress->load($deliveryId)) {
$patches[] = $this->getShippingNamePatch($deliveryAddress);
$patches[] = $this->getShippingAddressPatch($deliveryAddress);
}

return $this->request;
return $patches;
}

protected function getShippingAddressPatch(): void
public function getShippingAddressPatch(Address $deliveryAddress): Patch
{
$deliveryId = Registry::getSession()->getVariable("deladrid");
$deliveryAddress = oxNew(Address::class);

if ($deliveryId && $deliveryAddress->load($deliveryId)) {
$patch = new Patch();
$patch->op = Patch::OP_REPLACE;
$patch->path = "/purchase_units/@reference_id=='"
. Constants::PAYPAL_ORDER_REFERENCE_ID
. "'/shipping/address";
$patch = new Patch();
$patch->op = Patch::OP_REPLACE;
$patch->path = "/purchase_units/@reference_id=='"
. Constants::PAYPAL_ORDER_REFERENCE_ID
. "'/shipping/address";

$address = new AddressPortable();
$address = new AddressPortable();

$state = oxNew(State::class);
$state->load($deliveryAddress->getFieldData('oxstateid'));
$state = oxNew(State::class);
$state->load($deliveryAddress->getFieldData('oxstateid'));

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

$addressLine =
$deliveryAddress->getFieldData('oxstreet') . " " . $deliveryAddress->getFieldData('oxstreetnr');
$address->address_line_1 = $addressLine;
$addressLine =
$deliveryAddress->getFieldData('oxstreet') . " " . $deliveryAddress->getFieldData('oxstreetnr');
$address->address_line_1 = $addressLine;

$addinfoLine = $deliveryAddress->getFieldData('oxcompany') . " " .
$deliveryAddress->getFieldData('oxaddinfo');
$address->address_line_2 = $addinfoLine;
$addinfoLine = $deliveryAddress->getFieldData('oxcompany') . " " .
$deliveryAddress->getFieldData('oxaddinfo');
$address->address_line_2 = $addinfoLine;

$address->admin_area_1 = $state->getFieldData('oxtitle');
$address->admin_area_2 = $deliveryAddress->getFieldData('oxcity');
$address->country_code = $country->oxcountry__oxisoalpha2->value;
$address->postal_code = $deliveryAddress->getFieldData('oxzip');
$address->admin_area_1 = $state->getFieldData('oxtitle');
$address->admin_area_2 = $deliveryAddress->getFieldData('oxcity');
$address->country_code = $country->oxcountry__oxisoalpha2->value;
$address->postal_code = $deliveryAddress->getFieldData('oxzip');

$patch->value = $address;
$patch->value = $address;

$this->request[] = $patch;
}
return $patch;
}

protected function getShippingNamePatch(): void
public function getShippingNamePatch(Address $deliveryAddress): ?Patch
{
$deliveryId = Registry::getSession()->getVariable("deladrid");
$deliveryAddress = oxNew(Address::class);

if ($deliveryId && $deliveryAddress->load($deliveryId)) {
$fullName = $deliveryAddress->oxaddress__oxfname->value . " " . $deliveryAddress->oxaddress__oxlname->value;
$patch = new Patch();
$patch->op = Patch::OP_REPLACE;
$patch->path = "/purchase_units/@reference_id=='"
. Constants::PAYPAL_ORDER_REFERENCE_ID
. "'/shipping/name";
$patch->value = new \stdClass();
$patch->value->full_name = $fullName;
$fullName = $deliveryAddress->oxaddress__oxfname->value . " " . $deliveryAddress->oxaddress__oxlname->value;
$patch = new Patch();
$patch->op = Patch::OP_REPLACE;
$patch->path = "/purchase_units/@reference_id=='"
. Constants::PAYPAL_ORDER_REFERENCE_ID
. "'/shipping/name";
$patch->value = new \stdClass();
$patch->value->full_name = $fullName;

$this->request[] = $patch;
}
return $patch;
}

protected function getAmountPatch(): void
public function getAmountPatch(): ?Patch
{
$value = (Registry::get(PayPalRequestAmountFactory::class))->getAmount($this->basket);
if ((float)$value->value !== 0.00) {
Expand All @@ -134,20 +119,29 @@ protected function getAmountPatch(): void
$patch->path = "/purchase_units/@reference_id=='" . Constants::PAYPAL_ORDER_REFERENCE_ID . "'/amount";
$patch->value = $value;

$this->request[] = $patch;
return $patch;
}

return null;
}

/**
* @param Basket $basket
* @param $currency
* @return \OxidSolutionCatalysts\PayPalApi\Model\Orders\Patch|null
*/
protected function getPurchaseUnitsPatch(
Basket $basket,
$currency
): void {
public function getPurchaseUnitsPatch(): ?Patch
{
//get shop currency with master settings decimal level
$currency = Registry::getConfig()->getActShopCurrencyObject();
//we can't send basket items along with order request when precision level is above 2
$withItems = !$this->basket->isCalculationModeNetto() && !($currency->decimal > 2);
//update currency object with decimal precision restricted version
$currency = $this->basket->getBasketCurrency();

if (!$withItems) {
return null;
}

$basketItems = $basket->getContents();
$basketItems = $this->basket->getContents();
$language = Registry::getLang();

$patch = new Patch();
Expand All @@ -167,12 +161,12 @@ protected function getPurchaseUnitsPatch(
);
// We provide no tax, because Tax is in 99% not necessary.
// Maybe just PUI, but PUI orders will not be patched.
$item->quantity = (string) $basketItem->getAmount();
$item->quantity = (string)$basketItem->getAmount();
$patchValues[] = $item;
}
}

$wrapping = $basket->getPayPalCheckoutWrapping();
$wrapping = $this->basket->getPayPalCheckoutWrapping();
if ($wrapping) {
$item = new Item();
$item->name = $language->translateString('GIFT_WRAPPING');
Expand All @@ -186,7 +180,7 @@ protected function getPurchaseUnitsPatch(
$patchValues[] = $item;
}

$giftCard = $basket->getPayPalCheckoutGiftCard();
$giftCard = $this->basket->getPayPalCheckoutGiftCard();
if ($giftCard) {
$item = new Item();
$item->name = $language->translateString('GREETING_CARD');
Expand All @@ -200,7 +194,7 @@ protected function getPurchaseUnitsPatch(
$patchValues[] = $item;
}

$payment = $basket->getPayPalCheckoutPayment();
$payment = $this->basket->getPayPalCheckoutPayment();
if ($payment) {
$item = new Item();
$item->name = $language->translateString('PAYMENT_METHOD');
Expand All @@ -215,7 +209,7 @@ protected function getPurchaseUnitsPatch(
}

// possible price surcharge
$discount = $basket->getPayPalCheckoutDiscount();
$discount = $this->basket->getPayPalCheckoutDiscount();

if ($discount < 0) {
$discount *= -1;
Expand All @@ -229,7 +223,7 @@ protected function getPurchaseUnitsPatch(
}

// Dummy-Article for Rounding-Error
if ($roundDiff = $basket->getPayPalCheckoutRoundDiff()) {
if ($roundDiff = $this->basket->getPayPalCheckoutRoundDiff()) {
$item = new Item();
$item->name = $language->translateString('OSC_PAYPAL_VAT_CORRECTION');

Expand All @@ -241,16 +235,16 @@ protected function getPurchaseUnitsPatch(

$patch->value = $patchValues;

$this->request[] = $patch;
return $patch;
}

protected function getCustomIdPatch(string $shopOrderId): void
public function getCustomIdPatch(string $shopOrderId): Patch
{
$patch = new Patch();
$patch->op = Patch::OP_ADD;
$patch->path = "/purchase_units/@reference_id=='" . Constants::PAYPAL_ORDER_REFERENCE_ID . "'/custom_id";
$patch->value = $shopOrderId;

$this->request[] = $patch;
return $patch;
}
}
63 changes: 45 additions & 18 deletions src/Core/PayPalRequestAmountFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
namespace OxidSolutionCatalysts\PayPal\Core;

use OxidEsales\Eshop\Application\Model\Basket;
use OxidEsales\Eshop\Core\Registry;
use OxidSolutionCatalysts\PayPalApi\Model\Orders\AmountBreakdown;
use OxidSolutionCatalysts\PayPalApi\Model\Orders\AmountWithBreakdown;
use OxidSolutionCatalysts\PayPal\Core\Utils\PriceToMoney;
Expand All @@ -21,6 +22,29 @@
*/
class PayPalRequestAmountFactory
{
/**
* @var \OxidEsales\Eshop\Application\Model\Basket
*/
private Basket $basket;
/**
* @var \OxidEsales\Eshop\Core\Config
*/
private $config;
private bool $enteredNetPrice = false;
private bool $netMode = false;
private stdClass $currency;
private $discount;
private $itemTotal;
private $itemTotalAdditionalCosts;
private $brutBasketTotal;
private $shipping;

public function __construct()
{
$this->config = Registry::getConfig();
$this->enteredNetPrice = $this->getConfig()->getConfigParam('blEnterNetPrice');
}

public function getAmount(Basket $basket): AmountWithBreakdown
{
$this->basket = $basket;
Expand Down Expand Up @@ -63,24 +87,6 @@ protected function createAmountWithBreakdown(): AmountWithBreakdown

return $amount;
}
/**
* @return object|\OxidEsales\Eshop\Core\Config
*/
public function getConfig()
{
return $this->config;
}

public function getCurrency(): stdClass
{
return $this->currency;
}

public function setCurrency(stdClass $currency): void
{
$currency->decimal = 2;
$this->currency = $currency;
}

/**
* Calculates the breakdown components of the amount
Expand Down Expand Up @@ -160,4 +166,25 @@ protected function processShipping(AmountBreakdown $breakdown): void
$breakdown->item_total = PriceToMoney::convert($combinedTotal, $this->getCurrency());
}
}

/**
* @return object|\OxidEsales\Eshop\Core\Config
*/
public function getConfig()
{
return $this->config;
}

public function getCurrency(): stdClass
{
$currency = clone $this->currency;
$currency->decimal = 2;

return $currency;
}

public function setCurrency(stdClass $currency): void
{
$this->currency = $currency;
}
}
8 changes: 4 additions & 4 deletions src/Service/Payment.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ public function doCreatePatchedOrder(
return $return;
}

/**
* @throws \OxidSolutionCatalysts\PayPalApi\Exception\ApiException
*/
public function doPatchPayPalOrder(
EshopModelBasket $basket,
string $checkoutOrderId,
Expand All @@ -199,14 +202,11 @@ public function doPatchPayPalOrder(
/** @var ApiOrderService $orderService */
$orderService = $this->serviceFactory->getOrderService();

$request = $this->patchRequestFactory
->getRequest($basket, $shopOrderId);

// Update Order
try {
$orderService->updateOrder(
$checkoutOrderId,
$request,
$this->patchRequestFactory->getOrderPatches($basket, $shopOrderId),
Constants::PAYPAL_PARTNER_ATTRIBUTION_ID_PPCP
);
} catch (Exception $exception) {
Expand Down
Loading
Loading