$decimals ) { $amount = round( $amount, $settle ); } return round( $amount, $decimals ); } /** * The amount to *display* for a bundle-side price, in the store's chosen tax * basis (the "Display prices in the shop" setting). This is display only: * charging never reads it - the cart engine prices the line from the raw * component prices (see addon_boss_set_cart_item_price) and WooCommerce * applies tax there. It mirrors what WC_Product::get_price_html() does for a * normal product, so a bundle's shown price reads in the same incl/excl-tax * basis as the rest of the catalogue instead of the raw stored figure. * * $ref is the product whose tax status/class applies: the component product * for an item price, the bundle itself for a box-size or whole-bundle price. * With taxes off (or a non-taxable product) WooCommerce returns the figure * unchanged, so this is a no-op on stores that do not charge tax. * * @param WC_Product $ref The product whose tax status/class governs the price. * @param float $raw The raw stored price. * @return float The price to display, in the shop's tax basis. */ function addon_boss_price_to_display( WC_Product $ref, float $raw, string $context = 'shop' ): float { if ( $raw <= 0 ) { return 0.0; } // WooCommerce has TWO display settings - "in the shop" and "during cart and // checkout" - and a store may set them differently, so the caller says which // one applies. Core reads the right option itself: 'cart' picks // woocommerce_tax_display_cart, anything else woocommerce_tax_display_shop. // We require WC 8.0 and display_context landed in 7.6, so it is always there. return (float) wc_get_price_to_display( $ref, array( 'price' => $raw, 'qty' => 1, 'display_context' => $context, ) ); } /** * A printed fee in the shopper's basis, or unchanged when there is nothing to * convert it against. * * The label beside an add-on and the suffix in the cart are the SAME money and * must read the same. The cart side has always had the product and converted; * the label had neither, so a shop running a VAT display toggle printed the * raw stored figure on the product page and the converted one in the tray. * * Null product means a caller that genuinely has none (a repeat instance * rendered outside a product context), and there is no honest conversion to * make: the raw figure is returned exactly as it was printed before, so this * can never change what a caller without a product shows. * * @param float $fee The raw stored fee. * @param mixed $product The product it is charged against, or null. * @return float The figure to print. */ function addon_boss_fee_shown( float $fee, $product = null ): float { if ( $fee <= 0 || ! $product instanceof WC_Product ) { return $fee; } return addon_boss_price_to_display( $product, $fee ); } /** * A figure in the ENTRY basis, converted to the basis a shopper is reading. * * The name-your-price field speaks the shopper's basis end to end, and on a * shop with a tax toggle that basis is whatever the toggle says, which the * server cannot read from any option: the toggle plugin keeps its state in * the browser. So the field POSTS the basis it was speaking, and this pair of * helpers converts bounds out to it and the typed amount back from it. The * declared basis is money-safe to trust: bounds and charge convert together, * so whatever basis is claimed, the shopper pays the figure they saw against * the bounds they saw. */ function addon_boss_entry_to_basis( float $entry, $product, string $basis ): float { if ( $entry <= 0 || ! $product instanceof WC_Product ) { return $entry; } return 'incl' === $basis ? (float) wc_get_price_including_tax( $product, array( 'price' => $entry, 'qty' => 1 ) ) : (float) wc_get_price_excluding_tax( $product, array( 'price' => $entry, 'qty' => 1 ) ); } /** * The inverse: a figure TYPED in the given basis, back to the entry basis so * it can ride the fee pipeline like every configured charge. */ function addon_boss_basis_to_entry( float $shown, $product, string $basis ): float { if ( $shown <= 0 || ! $product instanceof WC_Product ) { return $shown; } // A big round figure, so the ratio survives core's per-call rounding. $bb_ratio = addon_boss_entry_to_basis( 1000.0, $product, $basis ) / 1000.0; return $bb_ratio > 0 ? $shown / $bb_ratio : $shown; } /** * The ONE way this plugin prints a figure a shopper will read. * * Every storefront surface used to format its own money: the receipt, the grid, * the discount cards, the position tiles, the choice labels, the date bands. * Each converted the display basis itself, or forgot to, so a shop running a * VAT toggle got a different answer per surface and every report of it closed * exactly one of them. The dropdown promised "+£9.00" while the tray beneath it * charged £10.80, and fixing the tray never reached the dropdown. * * Converting and formatting therefore live together, once, here. Callers say * what they are printing, not how to print it. * * `convert => false` is for an amount ALREADY in the display basis (a figure a * caller converted itself, or one read back from a data attribute this plugin * wrote). It is not an escape hatch for "no product to hand": pass the product * and let the guard in addon_boss_fee_shown() decide. * * `plain => true` is for a context that cannot hold markup: an