public void TestRoundDown() {
			Money money = new Money();

			money.RoundingMode = RoundingMode.AlwaysRoundDown;
			money.Amount = 1.119M;
			Assert.IsTrue(money.Amount == 1.11M, "Round Up failed (" + money.ToString() + " != 1.11");
		}
		public static Money CalculateDefaultPriceReduction(Money originalPrice, int itemQuantity, IPromotionData data) {

			Money priceReduction = null;
			Money promotionPrice = new Money(originalPrice, 0);
			promotionPrice.Amount = data.PromotionAmount;
			promotionPrice.Multiply(itemQuantity);

			switch (data.PromotionAmountType) {
				case PromotionAmountType.PercentReduction:
					if (data.PromotionAmount <= 100 && data.PromotionAmount > 0) {
						priceReduction = new Money(originalPrice);
						priceReduction.RoundingMode = RoundingMode.AlwaysRoundUp;
						priceReduction.Multiply(data.PromotionAmount / 100);
					} else {
						priceReduction = originalPrice;
					}
					break;
				case PromotionAmountType.AbsolutePrice:
					priceReduction = new Money(originalPrice);
					priceReduction.Subtract(promotionPrice);
					break;
				case PromotionAmountType.AbsoluteReduction:
					priceReduction = promotionPrice;
					break;
				default:
					LogManager.GetLogger(typeof(GenericPromotion)).Error("Unknown PromotionAmountType");
					break;
			}

			return priceReduction;
		}
		public Money CalculatePriceReduction(IBasketLine basketLine) {
			
			/*
			 * Buy N, get one free
			 * i.e. Buy 4, pay for 3
			 */
			try {
				int quantity = basketLine.Quantity / (PromotionBase.AuxData + 1);

				//See how many multiples we have
				if (quantity * (PromotionBase.AuxData + 1) > basketLine.Quantity) {
					quantity--;
				}

				if (quantity > 0) {

					Money discount = new Money(basketLine.LinePrice);
					discount.RoundingMode = RoundingMode.AlwaysRoundUp;

					discount.Divide(basketLine.Quantity);
					discount.Multiply(quantity);

					return discount;

				} else {

					return new Money(0);

				}

			} catch (Exception e) {
				LogManager.GetLogger(GetType()).Error(e);
				return new Money(0);
			}
		}
        protected string RenderSubTotal() {
            Money SubTotal = new Money();
            SubTotal.Add(CurrentBasket.SubTotal);

            SubTotal.Subtract(CurrentBasket.DeliveryPrice);
            return HtmlFormatUtils.FormatMoney(SubTotal);

        }
		public void TestSubtract() {

			Money money1 = new Money(2.23M);
			Money money2 = new Money(1.11M);

			money1.Subtract(money2);
			Assert.IsTrue(money1.Amount == 1.12M, "Subtraction failed (" + money2.ToString() + " != 1.12");
		}
		public void TestAdd() {

			Money money1 = new Money(1.23M);
			Money money2 = new Money(1.11M);

			money1.Add(money2);
			Assert.IsTrue(money1.Amount == 2.34M, "Addition failed (" + money2.ToString() + " != 2.34");
		}
		public static string FormatMoney(Money money, string cultureCode, IBasketRules rules, ITextTranslator translator) {

			if (rules.ShowPrices(WebStoreContext.Current.CurrentUser)) {
				return FormatMoney(money, cultureCode);
			}

			return translator.GetText("no_price_shown");
		}
		public void TestRoundUp() {
			Money money = new Money();

			money.RoundingMode = RoundingMode.AlwaysRoundUp;
			money.Amount = 1.111M;
			Assert.IsTrue(money.Amount == 1.12M, "Round Up failed (" + money.ToString() + " != 1.12");

			money.Amount = 2400;
			money.Multiply(.175M);
			Assert.IsTrue(money.Amount == 420M, "Round Up failed (" + money.ToString() + " != 420.00");
		}
		public void TestRoundIEEE() {
			Money money = new Money();

			money.RoundingMode = RoundingMode.IEEE754Section4;
			money.Amount = 1.115M;
			Assert.IsTrue(money.Amount == 1.12M, "Round Up failed (" + money.ToString() + " != 1.12");
			money.Amount = 1.125M;
			Assert.IsTrue(money.Amount == 1.12M, "Round Up failed (" + money.ToString() + " != 1.12");
			money.Amount = 1.135M;
			Assert.IsTrue(money.Amount == 1.14M, "Round Up failed (" + money.ToString() + " != 1.14");
		}
        /// <summary>
        /// default constructor
        /// </summary>
        public BasketItem() {

            _basketitemid = 0;
            _basket = null;
            _product = null;
            _lineTaxDecimal = 0;
            _linePreTaxDecimal = 0;
            _quantity = 0;
            _itemtypeid = 0;
            _pricingstatusid = 0;
            _inserttimestamp = DateTime.Now;
            _updatetimestamp = DateTime.Now;

            _optionList = new ArrayList();
            Status = PricingStatus.NotChecked;
            ItemType = BasketItemType.StandardItem;

            _linePreTaxMoney = null;
        }
		public void TestRoundPoint5() {
			Money money = new Money();

			money.RoundingMode = RoundingMode.RoundPoint5AndHigher;
			money.Amount = 1.115M;
			Assert.IsTrue(money.Amount == 1.12M, "Round To Point 5 failed (" + money.ToString() + " != 1.12");
			money.Amount = 1.125M;
			Assert.IsTrue(money.Amount == 1.13M, "Round To Point 5 failed (" + money.ToString() + " != 1.13");
			money.Amount = 1.13495M;
			Assert.IsTrue(money.Amount == 1.14M, "Round To Point 5 failed (" + money.ToString() + " != 1.14");

			money.Amount = 453;
			money.Add(new Money(36));
			money.Add(new Money(10));
			money.Multiply(0.175M);
		
			Assert.IsTrue(money.Amount == 87.33M, "Round To Point 5 failed (" + money.ToString() + " != 87.33");

		}
 public BandedCharge(decimal boundary, Money charge) {
     _boundary = boundary;
     _charge = charge;
 }
 protected virtual void Amount_OnChange(Money money) {
     if (money != null) {
         _amountDecimal = money.Amount;
         _currencycode = money.CurrencyCode;
     } else {
         _amountDecimal = 0;
         _currencycode = "GBP"; //anything!
     }
 }
		public Money(Money money) {
			Currency = new Currency(money.Currency.CultureInfo);
			_value = money.LongValue;
		}
 public Money(Money money, decimal amount) : this(money) {
     Amount = amount;
 }
 protected virtual void TaxPrice_OnChange(Money money) {
     if (money != null) {
         _basketTaxPriceDecimal = money.Amount;
     } else {
         _basketTaxPriceDecimal = 0;
     }
 }
		public bool GreaterThan(Money money) {
			if (money.Currency.CurrencyCode == Currency.CurrencyCode) {
				return _value > money.LongValue;
			} else {
				throw new ArgumentException("Non-identical currency codes");
			}
		}
		public virtual void RequestRefund(IElectronicPayment payment, Money refundAmount) {
			throw new NotImplementedException("Not yet implemented");
		}
 public FlatDeliveryChargeCalculator(string currencyCode, decimal chargeAmount) {
     _charge = new Money(currencyCode, chargeAmount);
 }
 private void LineTax_OnChange(Money money) {
     _lineTaxDecimal = money.Amount;
 }
		public static string FormatMoney(Money money) {
			return FormatMoney(money, "en-GB");
		}
		public static string FormatMoney(Money money, string cultureCode) {
			return money.ToString().Replace(" ", "&nbsp;");
		}
        public virtual IBasketLine UpdateItem(BasketItem item, string description, decimal price) {

            BasketItemList.Remove(item);
            item.Description = description;
            Money m = new Money(price);
            item.UnitLinePrice = item.LinePrice = item.TaxPrice = m;
            BasketItemList.Add(item);

            return item;
        }
        public virtual IBasketLine AddItem(BasketItemType itemType, string description, decimal price) {

            BasketItem item = new BasketItem();

            item.Basket = this;
            item.Quantity = 1;
            item.ItemType = itemType;
            item.Status = PricingStatus.OK;
            Money m = new Money(price);
            item.UnitLinePrice = m;
            
            BasketItemList.Add(item);

            return item;
        }
		private void AppendOrderItems(ref XmlNode orderFormDoc, IBasket order) {

			XmlNode items = AppendCcApiRecord(ref orderFormDoc, XML_TAG_ORDER_ITEM_LIST);

			for (int i = 1; i <= order.BasketItemList.Count; i++) {

                IBasketLine line = (IBasketLine) order.BasketItemList[i - 1];

				XmlNode item = AppendCcApiRecord(ref items, XML_TAG_ORDER_ITEM);

				//Get the unit price before tax, shipping, but after discount
				Money preTaxPrice = new Money(line.LinePrice);

				Money totalPrice = new Money(line.LinePrice);
				totalPrice.Add(line.TaxPrice);

				AppendCcApiIntegerField(ref item, XML_TAG_ORDER_ITEM_NUMBER, i);
				AppendCcApiStringField(ref item, XML_TAG_PRODUCT_CODE, line.ItemCode);
				AppendCcApiStringField(ref item, XML_TAG_ID, line.ItemCode);
				AppendCcApiStringField(ref item, XML_TAG_DESCRIPTION, StringUtils.Left(line.Description, 64));
				AppendCcApiIntegerField(ref item, XML_TAG_QUANTITY, line.Quantity);
				AppendCcApiIntegerField(ref item, XML_TAG_TAX_EXEMPT, 0);

				AppendCcApiMoneyField(ref item, XML_TAG_UNIT_PRICE, preTaxPrice);

				//Ignore tax and total for now...
				//AppendCcApiMoneyField(ref item, XML_TAG_VAT, line.TaxPrice);
				//AppendCcApiMoneyField(ref item, XML_TAG_TOTAL, totalPrice);

			}

			/*
			 			<OrderItemList>
			  <OrderItem>
			    <ItemNumber DataType="S32">1</ItemNumber>
			    <ProductCode>100200400</ProductCode>
			    <Id>100200400</Id>
			    <Desc>Some Stuff</Desc>
			    <Price DataType="Money" Currency="826">1125</Price>
			    <StateTax DataType="Money" Currency="826">395</StateTax>
			    <Total DataType="Money" Currency="826">2645</Total>
			    <Qty DataType="S32">2</Qty>
			    <TaxExempt DataType="S32">0</TaxExempt>
			  </OrderItem>
			</OrderItemList>
			*/

		}
		public override IElectronicPayment ProcessHttpResponse(HttpRequest postBackData, PaymentRequestTypes paymentType) {
			
			IElectronicPayment payment = new ElectronicPayment();

			switch (paymentType) {
				case PaymentRequestTypes.ImmediatePayment:
				case PaymentRequestTypes.ReservePayment:

					try {

						Currency currency = GetPaymentCurrency(postBackData);
						payment.LocalRequestReference = postBackData["cartId"];
						Money amount = new Money(currency, Decimal.Parse(postBackData["authAmount"]));
						payment.PaymentAmount = amount;

						SetPaymentDate(postBackData, payment);

						//Make sure this request came from the right address
						if (IsAllowedRemoteAddress(postBackData) && IsCallbackAuthenticated(postBackData)) {        
   
							string status = postBackData["transStatus"];

							switch (status.ToUpper()) {
								case STATUS_SUCCESS:
									payment.TransactionStatus = PaymentStatus.Approved;
									payment.TransactionReference = postBackData["transId"];
									break;
								case STATUS_DECLINED:
									payment.TransactionStatus = PaymentStatus.Declined;
									break;
								default:
									payment.TransactionStatus = PaymentStatus.Other;
									break;
							}
						} else {
							payment.TransactionStatus = PaymentStatus.Fraud;
						}

						LogResponse(payment, "WorldPay Status [" + postBackData["transStatus"]
							+ "], Raw Auth Code [" + postBackData["rawAuthCode"] 
							+ "], Raw Auth Message [" + postBackData["rawAuthMessage"] 
							+ "], " + GetResponseHttpLogInfo(postBackData));

					} catch (Exception e) {
						Logger.Error(e);
					}

					try {
						//payment.UserInfo.UserName = postBackData["name"];
						payment.UserInfo.UserAddress.Postcode = postBackData["postcode"];
						payment.UserInfo.UserDetails.EmailAddress = postBackData["email"];
						payment.UserInfo.UserAddress.AddressLine1 = postBackData["address"];
						payment.UserInfo.UserAddress.CountryCode = postBackData["countryString"];
						payment.UserInfo.UserDetails.TelephoneNumber = postBackData["tel"];
						payment.UserInfo.UserDetails.FaxNumber = postBackData["fax"];
					} catch (Exception f) {
						Logger.Error(f);
					}

					return payment;

				default:
					throw new InvalidOperationException("Payment request type not supported [" + paymentType + "]");			
			}
		}
		protected void AppendCcApiMoneyField(ref XmlNode node, string fieldName, Money amount) {

			XmlElement total = XMLUtils.AppendNewElement(ref node, fieldName, "" + amount.LongValue);
			XMLUtils.AppendNewAttribute(ref total, XML_ATTRIBUTE_DATA_TYPE, DATA_TYPE_MONEY);
			XMLUtils.AppendNewAttribute(ref total, XML_ATTRIBUTE_CURRENCY, "" + amount.Currency.CurrencyCodeNumeric);

		}
		public void Subtract(Money price) {
			if (price.Currency.CurrencyCode == Currency.CurrencyCode) {
				Amount -= price.Amount;
			} else {
				throw new ArgumentException("Non-identical currency codes");
			}
		}
		public override void RequestRefund(IElectronicPayment payment, Money refundAmount) {
			ProcessRequest(payment);
		}
        public static string FormatMoney(Money money, IBasketRules rules, ITextTranslator translator) {
			return FormatMoney(money, "en-GB", rules, translator);
		}