Skip to content

Commit

Permalink
fix(checkout): use show delivery options on backorders setting (#1136)
Browse files Browse the repository at this point in the history
INT-582
  • Loading branch information
FlorianSDV committed Aug 5, 2024
1 parent 575d640 commit f03b2a1
Show file tree
Hide file tree
Showing 6 changed files with 288 additions and 13 deletions.
10 changes: 9 additions & 1 deletion src/Hooks/CheckoutScriptHooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,19 @@ private function shouldShowDeliveryOptions(): bool

$showDeliveryOptions = false;

$deliveryOptionsEnabledWhenOnBackorder = Settings::get(
CheckoutSettings::ENABLE_DELIVERY_OPTIONS_WHEN_NOT_IN_STOCK,
CheckoutSettings::ID
);

foreach (WC()->cart->get_cart() as $cartItem) {
/** @var WC_Product $product */
$product = $cartItem['data'];

if (! $product->is_virtual() && ! $product->is_on_backorder($cartItem['quantity'])) {
$productIsVirtual = $product->is_virtual();
$productOnBackorder = $product->is_on_backorder($cartItem['quantity']);

if (! $productIsVirtual && (! $productOnBackorder || $deliveryOptionsEnabledWhenOnBackorder)) {
$showDeliveryOptions = true;
break;
}
Expand Down
98 changes: 89 additions & 9 deletions tests/Mock/MockWcCart.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,24 @@ public function add_to_cart(
array $variation = [],
array $cartItemData = []
): void {
for ($i = 0; $i < $quantity; $i++) {
$this->items[] = new WC_Product($productId);
$cartId = $this->generate_cart_id($productId, $variationId, $variation, $cartItemData);
$cartItemKey = $this->find_product_in_cart($cartId);

if ($cartItemKey) {
$this->items[$cartItemKey]['quantity'] += $quantity;
} else {
$this->items[] = [
'data' => new WC_Product($productId),
'quantity' => $quantity,
];
}
}

public function get_cart()
{
return $this->items;
}

/**
* @return void
*/
Expand All @@ -53,13 +66,12 @@ public function empty_cart(): void
public function get_shipping_packages(): array
{
// calculate weight of all products in cart
$weight = array_reduce(
$this->items,
static function (float $carry, WC_Product $item) {
return $carry + (float) $item->get_weight();
},
0
);
$weight = 0;
foreach ($this->items as $item) {
/** @var \WC_Product $wcProduct */
$wcProduct = $item['data'];
$weight += $wcProduct->get_weight() * $item['quantity'];
}

if ($weight > 10) {
return [];
Expand All @@ -69,4 +81,72 @@ static function (float $carry, WC_Product $item) {
'flat_rate:0' => [],
];
}

/**
* Generate a unique ID for the cart item being added.
*
* @param int $productId - id of the product the key is being generated for.
* @param int $variationId of the product the key is being generated for.
* @param array $variation data for the cart item.
* @param array $cartItemData other cart item data passed which affects this items uniqueness in the cart.
*
* @return string cart item key
*/
public function generate_cart_id(
int $productId,
int $variationId = 0,
array $variation = [],
array $cartItemData = []
): string {
$idParts = [$productId];

if ($variationId && 0 !== $variationId) {
$idParts[] = $variationId;
}

if (is_array($variation) && ! empty($variation)) {
$variationKey = '';
foreach ($variation as $key => $value) {
$variationKey .= trim($key) . trim($value);
}
$idParts[] = $variationKey;
}

if (is_array($cartItemData) && ! empty($cartItemData)) {
$cartItemDataKey = '';
foreach ($cartItemData as $key => $value) {
if (is_array($value) || is_object($value)) {
$value = http_build_query($value);
}
$cartItemDataKey .= trim($key) . trim($value);
}
$idParts[] = $cartItemDataKey;
}

return apply_filters(
'woocommerce_cart_id',
md5(implode('_', $idParts))
);
}

/**
* Check if product is in the cart and return cart item key.
* Cart item key will be unique based on the item and its properties, such as variations.
* ONLY RETURNS A KEY! DOES NOT RETURN THE ITEM!
*
* @param mixed $cartId id of product to find in the cart.
*
* @return string cart item key
*/
public function find_product_in_cart($cartId = false): string
{
$thisItemsIsArray = is_array($this->items);
$itemAlreadyExists = isset($this->items[$cartId]);

if ($cartId !== false && $thisItemsIsArray && $itemAlreadyExists) {
return $cartId;
}

return '';
}
}
93 changes: 93 additions & 0 deletions tests/Mock/MockWpEnqueue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

declare(strict_types=1);

namespace MyParcelNL\WooCommerce\Tests\Mock;

use MyParcelNL\Pdk\Base\Support\Arr;
use MyParcelNL\Pdk\Base\Support\Collection;

final class MockWpEnqueue implements StaticMockInterface
{
/**
* @var \MyParcelNL\Pdk\Base\Support\Collection
*/
private static $queuedItems;

/**
* @param $handle
* @param $src
* @param $deps
* @param $ver
* @param $in_footer
*
* @return void
*/
public static function add($handle, $src, $deps, $ver, $in_footer): void
{
$existing = array_filter(Arr::wrap(self::get($handle)));

self::$queuedItems->put(
$handle,
array_merge($existing, [
[
'src' => $src,
'deps' => $deps,
'ver' => $ver,
'in_footer' => $in_footer,
],
])
);
}

/**
* @return \MyParcelNL\Pdk\Base\Support\Collection
*/
public static function all(): Collection
{
return self::getQueuedItems();
}

/**
* @param string $tag
*
* @return array
*/
public static function get(string $tag): array
{
return self::getQueuedItems()
->get($tag, []);
}

public static function reset(): void
{
self::$queuedItems = new Collection();
}

public static function toArray(): array
{
return self::getQueuedItems()
->map(static function (array $actions) {
return (new Collection(Arr::pluck($actions, 'function')))->map(static function ($function) {
if (! is_array($function)) {
return $function;
}

return implode('::', [get_class($function[0]), $function[1]]);
});
})
->toArray();
}

/**
* @return \MyParcelNL\Pdk\Base\Support\Collection
*/
private static function getQueuedItems(): Collection
{
if (null === self::$queuedItems) {
self::reset();
}

return self::$queuedItems;
}
}
83 changes: 83 additions & 0 deletions tests/Unit/Hooks/CheckoutScriptHooksTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php
/** @noinspection StaticClosureCanBeUsedInspection */

declare(strict_types=1);

namespace MyParcelNL\WooCommerce\Hooks;

use MyParcelNL\Pdk\Facade\Pdk;
use MyParcelNL\Pdk\Settings\Model\CheckoutSettings;
use MyParcelNL\WooCommerce\Tests\Mock\MockWpEnqueue;
use MyParcelNL\WooCommerce\Tests\Uses\UsesMockWcPdkInstance;
use WC_Product;
use function MyParcelNL\Pdk\Tests\factory;
use function MyParcelNL\Pdk\Tests\usesShared;
use function MyParcelNL\WooCommerce\Tests\wpFactory;

usesShared(new UsesMockWcPdkInstance());

it(
'enqueues frontend scripts',
function (
bool $enableDeliveryOptions,
bool $enableDeliveryOptionsWhenNotInStock,
array $productData,
array $expected
) {
factory(CheckoutSettings::class)
->withEnableDeliveryOptions($enableDeliveryOptions)
->withEnableDeliveryOptionsWhenNotInStock($enableDeliveryOptionsWhenNotInStock)
->store();

$product = wpFactory(WC_Product::class)
->with($productData)
->make();

WC()->cart->add_to_cart($product->get_id(), 2);

/** @var \MyParcelNL\WooCommerce\Hooks\CheckoutScriptHooks $class */
$class = Pdk::get(CheckoutScriptHooks::class);

$class->enqueueFrontendScripts();

$all =
MockWpEnqueue::all()
->all();

expect($all)
->toHaveKeys($expected['toContain'])
->and($all)->not->toHaveKeys($expected['notToContain']);

MockWpEnqueue::reset();
WC()->cart->empty_cart();
}
)
->with([
'enable all, in stock' => [
'enableDeliveryOptions' => true,
'enableDeliveryOptionsWhenNotInStock' => true,
'productData' => ['id' => 1, 'is_on_backorder' => false],
'expected' => [
'toContain' => ['myparcelnl-delivery-options'],
'notToContain' => [],
],
],
'enable delivery options, on backorder' => [
'enableDeliveryOptions' => true,
'enableDeliveryOptionsWhenNotInStock' => false,
'productData' => ['id' => 1, 'is_on_backorder' => true],
'expected' => [
'toContain' => [],
'notToContain' => ['myparcelnl-delivery-options'],
],
],
'enable all, on backorder' => [
'enableDeliveryOptions' => true,
'enableDeliveryOptionsWhenNotInStock' => true,
'productData' => ['id' => 1, 'is_on_backorder' => true],
'expected' => [
'toContain' => ['myparcelnl-delivery-options'],
'notToContain' => [],
],
],
]);
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@
"value": ["5.0.0-alpha.1"]
}
],
"parentProduct": null,
"product": {
"id": "product",
"countryOfOrigin": "BB",
"customsCode": "1234",
"disableDeliveryOptions": -1,
Expand All @@ -66,7 +66,7 @@
"exportSignature": -1,
"fitInDigitalStamp": 7,
"fitInMailbox": 7,
"id": "product",
"packageType": "digital_stamp"
},
"parentProduct": null
}
}
11 changes: 11 additions & 0 deletions tests/mock_wp_functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use MyParcelNL\Pdk\Facade\Pdk;
use MyParcelNL\WooCommerce\Tests\Exception\DieException;
use MyParcelNL\WooCommerce\Tests\Mock\MockWpActions;
use MyParcelNL\WooCommerce\Tests\Mock\MockWpEnqueue;
use MyParcelNL\WooCommerce\Tests\Mock\MockWpMeta;
use MyParcelNL\WooCommerce\Tests\Mock\MockWpUser;
use MyParcelNL\WooCommerce\Tests\Mock\WordPressOptions;
Expand Down Expand Up @@ -151,3 +152,13 @@ function wp_unslash($value)
{
return $value;
}

function wp_enqueue_script($handle, $src = '', $deps = [], $ver = false, $in_footer = false)
{
MockWpEnqueue::add($handle, $src, $deps, $ver, $in_footer);
}

function wp_enqueue_style($handle, $src, $deps, $version, $media)
{
MockWpEnqueue::add($handle, $src, $deps, $version, $media);
}

0 comments on commit f03b2a1

Please sign in to comment.