Products: 3
Taxable:  3
Value:    £1,949.48
Delivery: £60.00
Discount: £115.00
Tax:      £366.90
Subtotal: £1,894.48
Total:    £2,261.38

@return Basket
495533
public function three()
    {
        $basket = new Basket(new UnitedKingdom);

        $basket = $this->addProductFour($basket);
        $basket = $this->addProductFive($basket);
        $basket = $this->addProductSix($basket);

        return $basket;
    }
1079319
public function nine()
    {
        $sku     = '9';
        $name    = 'Gift Card';
        $rate    = new UnitedKingdomValueAddedTax;
        $price   = new Money(2500, new Currency('GBP'));
        $product = new Product($sku, $name, $price, $rate);
        $product->quantity(3);
        $product->freebie(true);
        $product->delivery(new Money(99, new Currency('GBP')));

        return $product;
    }
1249652
public function nine()
    {
        $basket = new Basket(new UnitedKingdom);

        $basket = $this->addProductZero($basket);
        $basket = $this->addProductFive($basket);
        $basket = $this->addProductEight($basket);
        $basket = $this->addProductNine($basket);

        return $basket;
    }
438356
public function priceCalculator()
    {
        $return_price = 0;

        $price      = \floatval($this->getRequest()->query->get('price', 0));
        $product_id = \intval($this->getRequest()->query->get('product_id', 0));
        $action     = $this->getRequest()->query->get('action', ''); // With ot without tax
        $convert    = \intval($this->getRequest()->query->get('convert_from_default_currency', 0));

        if (null !== $product = ProductQuery::create()->findPk($product_id)) {
            if ($action == 'to_tax') {
                $return_price = $this->computePrice($price, 'without_tax', $product);
            } elseif ($action == 'from_tax') {
                $return_price = $this->computePrice($price, 'with_tax', $product);
            } else {
                $return_price = $price;
            }

            if ($convert != 0) {
                $return_price = $price * Currency::getDefaultCurrency()->getRate();
            }
        }

        return new JsonResponse(array('result' => $this->formatPrice($return_price)));
    }
128730
public function calculateTotalDiscount(Basket $basket, Discount $discount, Money $total)
    {
        // Handle a ValueDiscount
        if ($discount instanceof ValueDiscount) {
            $total = $this->subtractValueDiscount($total, $discount);
        }

        // Handle a PercentageDiscount
        if ($discount instanceof PercentageDiscount) {
            $total = $this->subtractPercentageDiscount($total, $discount);
        }

        // Handle a QuantityDiscount
        if ($discount instanceof QuantityDiscount) {
            // Calculate the total quantity of items ordered
            $totalQuantity = 0;

            foreach ($basket->products() as $product) {
                $totalQuantity = $totalQuantity + $product->quantity;
            }

            $quantityDiscount = $discount->rate();

            // Handle a ValueDiscount within a QuantityDiscount
            if ($quantityDiscount instanceof ValueDiscount) {
                $total = $this->subtractValueDiscount($total, $quantityDiscount);
            }

            // Handle a PercentageDiscount within a QuantityDiscount
            if ($quantityDiscount instanceof PercentageDiscount) {
                $total = $this->subtractPercentageDiscount($total, $quantityDiscount);
            }
        }

        return $total;
    }
1006515
public function getPaymorrowTotalVatAmount()
    {
        /** @var OxpsPaymorrowOxBasket|oxBasket $this */

        // Products VAT
        $dTotalVat = (double) array_sum( (array) $this->getProductVats( false ) );

        // Get cost and add costs VATs
        $aCosts = (array) $this->getCosts();

        foreach ( $aCosts as $oPrice ) {
            $dTotalVat += (double) $this->_getVatForValidPrice( $oPrice );
        }

        // Add surcharge VAT amount in case it is not yet included in basket
        $dTotalVat += (double) $this->_getVatForValidPrice( $this->_getPaymentMethodSurcharge() );

        return $dTotalVat;
    }
1340020
def compute_taxes(self, precision=None):
        '''
        
        '''
        base = self.gross - self.total_discounts
        return quantize(sum([t.compute(base, precision) for t in self.__taxes]),
                        precision)
1002297
public function getTax()
    {
        $content = $this->getContent();

        $tax = $content->reduce(function (Money $tax, CartItem $cartItem) {
            return $tax->add($cartItem->getTaxTotal());
        }, new Money(0, Config::get('shoppingcart.currency')));

        return $tax;
    }
883534
function ec_step1() {
    global $order, $order_totals, $db, $doPayPal;

    // if cart is empty due to timeout on login or shopping cart page, go to timeout screen
    if ($_SESSION['cart']->count_contents() == 0) {
      $message = 'Logging out due to empty shopping cart.  Is session started properly? ... ' . "\nSESSION Details:\n" . print_r($_SESSION, TRUE) . 'GET:' . "\n" . print_r($_GET, TRUE);
      include_once(DIR_WS_MODULES . 'payment/paypal/paypal_functions.php');
      ipn_debug_email($message);
      zen_redirect(zen_href_link(FILENAME_TIME_OUT, '', 'SSL'));
    }

    // init new order object
    require(DIR_WS_CLASSES . 'order.php');
    $order = new order;

    // load the selected shipping module so that shipping taxes can be assessed
    require(DIR_WS_CLASSES . 'shipping.php');
    $shipping_modules = new shipping($_SESSION['shipping']);

    // load OT modules so that discounts and taxes can be assessed
    require(DIR_WS_CLASSES . 'order_total.php');
    $order_total_modules = new order_total;
    $order_totals = $order_total_modules->pre_confirmation_check();
    $order_totals = $order_total_modules->process();

    $doPayPal = $this->paypal_init();
    $options = array();

    // build line item details
    $options = $this->getLineItemDetails($this->selectCurrency());

    // Set currency and amount
    $options['CURRENCYCODE'] = $this->selectCurrency();
    $order_amount = $this->calc_order_amount($order->info['total'], $options['CURRENCYCODE']);

    // Determine the language to use when visiting the PP site
    $lc_code = $this->getLanguageCode();
    if ($lc_code != '') $options['LOCALECODE'] = $lc_code;

    // Allow delayed payments such as eCheck?
    if (defined('MODULE_PAYMENT_PAYPALEC_ALLOWEDPAYMENT') && MODULE_PAYMENT_PAYPALEC_ALLOWEDPAYMENT == 'Instant Only') $options['ALLOWEDPAYMENTMETHOD'] = 'InstantPaymentOnly';

    //Gift Options
    $options['GIFTMESSAGEENABLE'] = 0;
    $options['GIFTRECEIPTEENABLE'] = 0;
    $options['GIFTWRAPENABLE'] = 0;
    $options['GIFTWRAPNAME'] = '';
    $options['GIFTWRAPAMOUNT'] = 0;

    $options['BUYEREMAILOPTINENABLE'] = 0;

    $options['CUSTOMERSERVICENUMBER'] = (defined('STORE_TELEPHONE_CUSTSERVICE') && STORE_TELEPHONE_CUSTSERVICE != '') ? substr(STORE_TELEPHONE_CUSTSERVICE, 0, 16) : '';

    // Store Name to appear on PayPal page
    $options['BRANDNAME'] = (defined('MODULE_PAYMENT_PAYPALWPP_BRANDNAME') && strlen(MODULE_PAYMENT_PAYPALWPP_BRANDNAME) > 3) ? substr(MODULE_PAYMENT_PAYPALWPP_BRANDNAME, 0, 127) : substr(STORE_NAME, 0, 127);

    // Payment Transaction/Authorization Mode
    $options['PAYMENTACTION'] = (MODULE_PAYMENT_PAYPALWPP_TRANSACTION_MODE == 'Auth Only') ? 'Authorization' : 'Sale';
    // for future:
    if (MODULE_PAYMENT_PAYPALWPP_TRANSACTION_MODE == 'Order') $options['PAYMENTACTION'] = 'Order';

    $options['ALLOWNOTE'] = 1;  // allow customer to enter a note on the PayPal site, which will be copied to order comments upon return to store.
    $options['SOLUTIONTYPE'] = 'Sole';  // Use 'Mark' for normal Express Checkout, 'Sole' for auctions or alternate flow
    $options['LANDINGPAGE'] = 'Billing';  // "Billing" or "Login" selects the style of landing page on PayPal site during checkout

    // Set the return URL if they click "Submit" on PayPal site
    $return_url = str_replace('&amp;', '&', zen_href_link('ipn_main_handler.php', 'type=ec', 'SSL', true, true, true));
    // Select the return URL if they click "cancel" on PayPal site or click to return without making payment or login
    $cancel_url = str_replace('&amp;', '&', zen_href_link(($_SESSION['customer_first_name'] != '' && $_SESSION['customer_id'] != '' ? FILENAME_CHECKOUT_SHIPPING : FILENAME_SHOPPING_CART), 'ec_cancel=1', 'SSL'));

    // debug
    $val = $_SESSION; unset($val['navigation']);
    $this->zcLog('ec_step1 - 1', 'Checking to see if we are in markflow' . "\n" . 'cart contents: ' . $_SESSION['cart']->get_content_type() . "\n\nNOTE: " . '$this->showPaymentPage = ' . (int)$this->showPaymentPage . "\nCustomer ID: " . (int)$_SESSION['customer_id'] . "\nSession Data: " . print_r($val, true));

    /**
     * Check whether shipping is required on this order or not.
     * If not, tell PayPal to skip all shipping options
     * ie: don't ask for any shipping info if cart content is strictly virtual and customer is already logged-in
     * (if not logged in, we need address information only to build the customer record)
     */
    if ($_SESSION['cart']->get_content_type() == 'virtual' && isset($_SESSION['customer_id']) && $_SESSION['customer_id'] > 0) {
      $this->zcLog('ec-step1-addr_check', "cart contents is virtual and customer is logged in ... therefore options['NOSHIPPING']=1");
      $options['NOSHIPPING'] = 1;
    } else {
      $this->zcLog('ec-step1-addr_check', "cart content is not all virtual (or customer is not logged in) ... therefore will be submitting address details");
      $options['NOSHIPPING'] = 0;
      // If we are in a "mark" flow and the customer has a usable address, set the addressoverride variable to 1. This will
      // override the shipping address in PayPal with the shipping address that is selected in Zen Cart.
      // @TODO: consider using address-validation against Paypal's addresses via API
      if (MODULE_PAYMENT_PAYPALWPP_CONFIRMED_ADDRESS != 'Yes' && ($address_arr = $this->getOverrideAddress()) !== false) {
        $address_error = false;
        foreach(array('entry_firstname','entry_lastname','entry_street_address','entry_city','entry_postcode','zone_code','countries_iso_code_2') as $val) {
          if ($address_arr[$val] == '') $address_error = true;
          if ($address_error == true) $this->zcLog('ec-step1-addr_check2', '$address_error = true because ' .$val . ' is blank.');
        }
        if ($address_error == false) {
          // set the override var
          $options['ADDROVERRIDE'] = 1;

          // set the address info
          $options['SHIPTONAME']    = substr($address_arr['entry_firstname'] . ' ' . $address_arr['entry_lastname'], 0, 32);
          $options['SHIPTOSTREET']  = substr($address_arr['entry_street_address'], 0, 100);
          if ($address_arr['entry_suburb'] != '') $options['SHIPTOSTREET2'] = substr($address_arr['entry_suburb'], 0, 100);
          $options['SHIPTOCITY']    = substr($address_arr['entry_city'], 0, 40);
          $options['SHIPTOZIP']     = substr($address_arr['entry_postcode'], 0, 20);
          $options['SHIPTOSTATE']   = substr($address_arr['zone_code'], 0, 40);
          $options['SHIPTOCOUNTRYCODE'] = substr($address_arr['countries_iso_code_2'], 0, 2);
          $options['SHIPTOPHONENUM'] = substr($address_arr['entry_telephone'], 0, 20);
        }
      }
      $this->zcLog('ec-step1-addr_check3', 'address details from override check:'.($address_arr == FALSE ? ' <NONE FOUND>' : print_r($address_arr, true)));

      // Do we require a "confirmed" shipping address ?
      if (MODULE_PAYMENT_PAYPALWPP_CONFIRMED_ADDRESS == 'Yes') {
        $options['REQCONFIRMSHIPPING'] = 1;
      }
    }
    // if we know customer's email address, supply it, so as to pre-fill the signup box at PayPal (useful for new PayPal accounts only)
    if (!empty($_SESSION['customer_first_name']) && !empty($_SESSION['customer_id'])) {
      $sql = "select * from " . TABLE_CUSTOMERS . " where customers_id = :custID ";
      $sql = $db->bindVars($sql, ':custID', $_SESSION['customer_id'], 'integer');
      $zc_getemail = $db->Execute($sql);
      if ($zc_getemail->RecordCount() > 0 && $zc_getemail->fields['customers_email_address'] != '') {
        $options['EMAIL'] = $zc_getemail->fields['customers_email_address'];
      }
      if ($zc_getemail->RecordCount() > 0 && $zc_getemail->fields['customers_telephone'] != '' && (!isset($options['ADDROVERRIDE']) || isset($options['ADDROVERRIDE']) && $options['ADDROVERRIDE'] != 1)) {
        $options['SHIPTOPHONENUM'] = $zc_getemail->fields['customers_telephone'];
      }
    }

    if (!isset($options['AMT'])) $options['AMT'] = number_format($order_amount, 2);

    $this->zcLog('ec_step1 - 2 -submit', print_r(array_merge($options, array('RETURNURL' => $return_url, 'CANCELURL' => $cancel_url)), true));

    /**
     * Ask PayPal for the token with which to initiate communications
     */
    $response = $doPayPal->SetExpressCheckout($return_url, $cancel_url, $options);


  $submissionCheckOne = TRUE;
  $submissionCheckTwo = TRUE;
  if ($submissionCheckOne) {
    // If there's an error on line-item details, remove tax values and resubmit, since the most common cause of 10413 is tax mismatches
    if ($response['L_ERRORCODE0'] == '10413') {
      $this->zcLog('ec_step1 - 3 - removing tax portion', 'Tax Subtotal does not match sum of taxes for line-items. Tax details removed from line-item submission data.' . "\n" . print_r($options, true));
          //echo '1st submission REJECTED. {'.$response['L_ERRORCODE0'].'}<pre>'.print_r($options, true) . urldecode(print_r($response, true));
      $tsubtotal = 0;
      foreach ($options as $key=>$value) {
        if (substr($key, 0, 8) == 'L_TAXAMT') {
          $tsubtotal += preg_replace('/[^0-9.\-]/', '', $value);
          unset($options[$key]);
        }
      }
      $options['TAXAMT'] = $tsubtotal;
      $amt = preg_replace('/[^0-9.%]/', '', $options['AMT']);
//      echo 'oldAMT:'.$amt;
//      echo ' newTAXAMT:'.$tsubtotal;
      $taxamt = preg_replace('/[^0-9.%]/', '', $options['TAXAMT']);
      $shipamt = preg_replace('/[^0-9.%]/', '', $options['SHIPPINGAMT']);
      $itemamt = preg_replace('/[^0-9.%]/', '', $options['ITEMAMT']);
      $calculatedAmount = $itemamt + $taxamt + $shipamt;
      if ($amt != $calculatedAmount) $amt = $calculatedAmount;
//      echo ' newAMT:'.$amt;
      $options['AMT'] = $amt;
      $response = $doPayPal->SetExpressCheckout($return_url, $cancel_url, $options);
//echo '<br>2nd submission. {'.$response['L_ERRORCODE0'].'}<pre>'.print_r($options, true);
    }
    if ($submissionCheckTwo) {
    if ($response['L_ERRORCODE0'] == '10413') {
      $this->zcLog('ec_step1 - 4 - removing line-item details', 'PayPal designed their own mathematics rules. Dumbing it down for them.' . "\n" . print_r($options, true));
//echo '2nd submission REJECTED. {'.$response['L_ERRORCODE0'].'}<pre>'.print_r($options, true) . urldecode(print_r($response, true));
      foreach ($options as $key=>$value) {
        if (substr($key, 0, 2) == 'L_') {
          unset($options[$key]);
        }
      }
      $amt = preg_replace('/[^0-9.%]/', '', $options['AMT']);
      $taxamt = preg_replace('/[^0-9.%]/', '', $options['TAXAMT']);
      $shipamt = preg_replace('/[^0-9.%]/', '', $options['SHIPPINGAMT']);
      $itemamt = preg_replace('/[^0-9.%]/', '', $options['ITEMAMT']);
      $calculatedAmount = $itemamt + $taxamt + $shipamt;
      if ($amt != $calculatedAmount) $amt = $calculatedAmount;
      $options['AMT'] = $amt;
      $response = $doPayPal->SetExpressCheckout($return_url, $cancel_url, $options);
//echo '<br>3rd submission. {'.$response['L_ERRORCODE0'].'}<pre>'.print_r($options, true);
    }
   }
  }

    /**
     * Determine result of request for token -- if error occurred, the errorHandler will redirect accordingly
     */
    $error = $this->_errorHandler($response, 'SetExpressCheckout');

    // Success, so read the EC token
    $_SESSION['paypal_ec_token'] = preg_replace('/[^0-9.A-Z\-]/', '', urldecode($response['TOKEN']));

    // prepare to redirect to PayPal so the customer can log in and make their selections
    $paypal_url = $this->getPayPalLoginServer();

    // Set the name of the displayed "continue" button on the PayPal site.
    // 'commit' = "Pay Now"  ||  'continue' = "Review Payment"
    $orderReview = true;
    if ($_SESSION['paypal_ec_markflow'] == 1) $orderReview = false;
    $userActionKey = "&useraction=" . ((int)$orderReview == false ? 'commit' : 'continue');

    // This is where we actually redirect the customer's browser to PayPal. Upon return from PayPal, they go to ec_step2
    header("HTTP/1.1 302 Object Moved");
    zen_redirect($paypal_url . "?cmd=_express-checkout&token=" . $_SESSION['paypal_ec_token'] . $userActionKey);

    // this should never be reached:
    return $error;
  }
924312
def total(self):
        
        total = 0
        for item in self.items.all():
            total += item.total
        return total
168998
public function six()
    {
        $basket = new Basket(new UnitedKingdom);

        $basket = $this->addProductZero($basket);
        $basket = $this->addProductThree($basket);
        $basket = $this->addProductSeven($basket);

        return $basket;
    }
1006117
def tax_for_order(self, order_deets):
        """"""
        request = self._post('taxes', order_deets)
        return self.responder(request)
1090985
protected function _calcBasketTotalDiscount()
    {
        if ($this->_oTotalDiscount === null || (!$this->isAdmin())) {
            $this->_oTotalDiscount = $this->_getPriceObject();

            if (is_array($this->_aDiscounts)) {
                foreach ($this->_aDiscounts as $oDiscount) {
                    // skipping bundle discounts
                    if ($oDiscount->sType == 'itm') {
                        continue;
                    }

                    // add discount value to total basket discount
                    $this->_oTotalDiscount->add($oDiscount->dDiscount);
                }
            }
        }
    }
1037192
public function subtotal(Product $product)
    {
        $subtotal = $this->money($product);

        if (! $product->freebie) {
            $value    = $this->value($product);
            $discount = $this->discount($product);
            $subtotal = $subtotal->add($value)->subtract($discount);
        }

        $delivery = $this->delivery($product);
        $subtotal = $subtotal->add($delivery);

        return $subtotal;
    }
741970
public function discount()
    {
        return $this->formatAmount($this->invoice->subtotal + $this->invoice->tax - $this->invoice->total);
    }
1114587
public function tax()
    {
        return (float) array_sum(
            array_map(function (CartItem $item) {
                return $item->getTotalTax();
            }, $this->items)
        );
    }
757537
public function seven()
    {
        $basket = new Basket(new UnitedKingdom);

        $basket = $this->addProductFive($basket);
        $basket = $this->addProductSix($basket);
        $basket = $this->addProductSeven($basket);

        return $basket;
    }