Forum Replies Created

Viewing 2 replies - 1 through 2 (of 2 total)
  • Thread Starter geppert

    (@geppert)

    Follow-up: Root cause identified after source code analysis

    I’ve had a chance to dig into the plugin source code (v9.0.60) and can now provide a more precise description of what’s happening.

    Root cause

    The bug originates in ppcp_regular_create_order_request() inside class-ppcp-paypal-checkout-for-woocommerce-request.php.

    When a customer pays via direct credit/debit card entry (not PayPal login), process_payment() in class-ppcp-paypal-checkout-for-woocommerce-gateway-cc.php calls ppcp_regular_create_order_request($woo_order_id) (line 232). This function correctly fetches order details via ppcp_get_details_from_order() (line 2343), which reads $order->get_shipping_total() — so the shipping amount is present in $cart['shipping'] at this point.

    However, the entire amount.breakdown block — including the shipping field — is wrapped inside a send_items gate (line 2376):

    PHP

    if ($this->send_items === true) {
        // item_total, shipping, tax_total, discount are all set here
    }
    

    If send_items is disabled in the plugin settings, the entire breakdown is skipped. The amount.value still uses $cart['order_total'] from ppcp_get_details(), which correctly includes shipping in the total — but since the breakdown is absent, PayPal receives a total that includes shipping with no breakdown to account for it, causing PayPal to record shipping: 0.00 internally.

    Additionally, even when send_items is enabled, the ppcp_get_details() reconciliation logic (lines 1202–1260) can produce a negative ship_discount_amount to balance rounding differences, which may further suppress the shipping value in the breakdown.

    The trigger: SET_PROVIDED_ADDRESS mode

    The issue is specifically triggered during the checkout page flow. ppcp_shipping_preference() (line 264) returns SET_PROVIDED_ADDRESS when $page === 'checkout' (line 302). In this mode, PayPal does not recalculate shipping from its own address data — it relies entirely on what the plugin sends in the breakdown. If the breakdown is missing or incomplete, PayPal silently records shipping: 0.00.

    In contrast, the GET_FROM_FILE mode (used for cart/product page PayPal button flows) triggers a PayPal-side shipping recalculation, which is why those orders are processed correctly.

    Affected code paths

    • class-ppcp-paypal-checkout-for-woocommerce-gateway-cc.php → process_payment() → ppcp_regular_create_order_request()
    • class-ppcp-paypal-checkout-for-woocommerce-request.php → ppcp_regular_create_order_request() lines 2376–2415
    • class-ppcp-paypal-checkout-for-woocommerce-request.php → ppcp_shipping_preference() lines 264–306

    Suggested fix

    The shipping amount should be added to the breakdown unconditionally when SET_PROVIDED_ADDRESS is used and $cart['shipping'] > 0, regardless of the send_items setting. The send_items flag should control whether line items are sent, but should not suppress the shipping amount in the breakdown — these are two separate concerns.

    A minimal targeted fix would be to move the shipping breakdown assignment outside of the send_items block in ppcp_regular_create_order_request():

    PHP

    // Outside of the send_items block:
    if (isset($cart['shipping']) && $cart['shipping'] > 0) {
        $body_request['purchase_units'][0]['amount']['breakdown']['shipping'] = array(
            'currency_code' => apply_filters('wpg_ppcp_woocommerce_currency', $this->ppcp_get_currency($woo_order_id), $cart['shipping']),
            'value' => $cart['shipping'],
        );
    }
    

    This same issue likely affects ppcp_create_order_request() (line 483) for the same reason.

    Thread Starter geppert

    (@geppert)

    I am fully aware that I can translate the plugin, but I use no plugins for multi-language, just different pages.

    Ideally it’d look something like an option in the shortcode [webbabooking language=english] [webbabooking language=german] but that does not seem to exist

Viewing 2 replies - 1 through 2 (of 2 total)