Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public function recalculate(msOrder $order, array $options = []): array

$deliveryCost = $deliveryResult['delivery_cost'];

$paymentBase = round($cartCost + $deliveryCost, 6);
$paymentBase = OrderService::paymentCommissionBase($cartCost);
$paymentResult = $this->resolvePaymentFee($order, $paymentBase, $mode, $options);
if (!$paymentResult['success']) {
return $paymentResult;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,14 @@ public function getPaymentCost(?msOrder $draft, array $orderData, string $token,
return $this->success('ms3_order_getcost_success', ['cost' => $paymentCost]);
}

// Get cart cost for payment calculation
// Get cart cost for payment calculation (MS2-compatible base: cart only)
$cartCostResponse = $this->getCartCost($draft, $token, $ctx);
$cartCost = $cartCostResponse['success'] ? $cartCostResponse['data']['cost'] : 0;
$paymentBase = OrderService::paymentCommissionBase((float) $cartCost);

// Payment getCost returns total with payment fee, so subtract cart cost
$costWithPayment = $msPayment->getCost($draft, $cartCost);
$paymentCost = $costWithPayment - $cartCost;
// Payment getCost returns total with payment fee, so subtract base
$costWithPayment = $msPayment->getCost($draft, $paymentBase);
$paymentCost = $costWithPayment - $paymentBase;

$response = $this->ms3->utils->invokeEvent('msOnGetPaymentCost', [
'calculator' => $this,
Expand Down
8 changes: 8 additions & 0 deletions core/components/minishop3/src/Services/Order/OrderService.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ public function __construct(modX $modx)
$this->modx = $modx;
}

/**
* Base amount for payment commission (MS2-compatible: cart cost only, delivery excluded).
*/
public static function paymentCommissionBase(float $cartCost): float
{
return round($cartCost, 6);
}

/**
* Clamp computed order total so it never goes negative (defence-in-depth vs misconfigured discounts).
*
Expand Down
67 changes: 67 additions & 0 deletions core/components/minishop3/tests/PaymentCommissionBaseTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

/**
* Guards payment commission base (issue #372): MS2-compatible cart-only base.
*
* Run: php tests/PaymentCommissionBaseTest.php
*/

declare(strict_types=1);

require __DIR__ . '/../vendor/autoload.php';

use MiniShop3\Services\Order\OrderService;
use MiniShop3\Utils\PriceAdjustment;

$fail = static function (string $message): never {
fwrite(STDERR, "FAIL: {$message}\n");
exit(1);
};

$cartCost = 1000.0;
$deliveryCost = 500.0;
$percent = '3%';

$base = OrderService::paymentCommissionBase($cartCost);
if ($base !== 1000.0) {
$fail('paymentCommissionBase must round cart cost only');
}

$fee = PriceAdjustment::calculate($base, $percent);
if (abs($fee - 30.0) > 0.000001) {
$fail('3% of cart 1000 must be 30, got ' . $fee);
}

$wrongFee = PriceAdjustment::calculate($cartCost + $deliveryCost, $percent);
if (abs($wrongFee - 45.0) > 0.000001) {
$fail('sanity: 3% of cart+delivery 1500 must be 45');
}

if (abs($fee - $wrongFee) < 0.000001) {
$fail('cart-only and cart+delivery bases must differ for this repro');
}

$recalculatorSource = file_get_contents(__DIR__ . '/../src/Services/Order/ManagerOrderCostRecalculator.php');
if ($recalculatorSource === false) {
$fail('cannot read ManagerOrderCostRecalculator.php');
}

if (!str_contains($recalculatorSource, 'OrderService::paymentCommissionBase($cartCost)')) {
$fail('ManagerOrderCostRecalculator must use OrderService::paymentCommissionBase($cartCost)');
}

if (preg_match('/paymentBase\s*=\s*round\s*\(\s*\$cartCost\s*\+\s*\$deliveryCost/s', $recalculatorSource) === 1) {
$fail('ManagerOrderCostRecalculator must not use cart+delivery as payment base');
}

$calculatorSource = file_get_contents(__DIR__ . '/../src/Services/Order/OrderCostCalculator.php');
if ($calculatorSource === false) {
$fail('cannot read OrderCostCalculator.php');
}

if (!str_contains($calculatorSource, 'OrderService::paymentCommissionBase')) {
$fail('OrderCostCalculator must use OrderService::paymentCommissionBase');
}

fwrite(STDOUT, "OK PaymentCommissionBaseTest\n");
exit(0);