示例#1
0
        /// <summary>
        /// Gets the shipping addresses for the basket
        /// </summary>
        /// <param name="basket">The basket to parse; can be null to return the default shipping address</param>
        /// <returns>The shipping addresses for the basket</returns>
        public static List <TaxAddress> GetShippingAddresses(Basket basket)
        {
            List <TaxAddress> shippingAddresses = new List <TaxAddress>();
            string            shippingCountry;
            int    shippingProvinceId;
            string shippingPostalCode;

            if (basket != null)
            {
                foreach (BasketShipment shipment in basket.Shipments)
                {
                    Address shippingAddress = shipment.Address;
                    if (shippingAddress != null && shippingAddress.IsValid)
                    {
                        shippingCountry    = shippingAddress.CountryCode;
                        shippingProvinceId = shippingAddress.ProvinceId;
                        shippingPostalCode = shippingAddress.PostalCode;
                        TaxAddress tempShippingAddress = new TaxAddress(shippingCountry, shippingProvinceId, shippingPostalCode);
                        if (shippingAddresses.IndexOf(tempShippingAddress) < 0)
                        {
                            shippingAddresses.Add(tempShippingAddress);
                        }
                    }
                }
            }
            if (shippingAddresses.Count == 0)
            {
                Warehouse shippingAddress = Token.Instance.Store.DefaultWarehouse;
                shippingCountry    = shippingAddress.CountryCode;
                shippingProvinceId = ProvinceDataSource.GetProvinceIdByName(shippingCountry, shippingAddress.Province);
                shippingPostalCode = shippingAddress.PostalCode;
                shippingAddresses.Add(new TaxAddress(shippingCountry, shippingProvinceId, shippingPostalCode));
            }
            return(shippingAddresses);
        }
示例#2
0
        /// <summary>
        /// Gets the tax rules that may apply
        /// </summary>
        /// <param name="taxCodeId">The tax code of the taxable item</param>
        /// <param name="billingAddress">The billing address for the item</param>
        /// <param name="shippingAddress">The shipping address for the item</param>
        /// <param name="user">The user shopping for the item</param>
        /// <returns>A List of TaxRule records that may apply</returns>
        public static List <TaxRule> GetPotentialTaxRules(int taxCodeId, TaxAddress billingAddress, TaxAddress shippingAddress, User user)
        {
            int[]             taxCodeIds        = { taxCodeId };
            List <TaxAddress> shippingAddresses = new List <TaxAddress>();

            shippingAddresses.Add(shippingAddress);
            return(GetPotentialTaxRules(taxCodeIds, billingAddress, shippingAddresses, user));
        }
示例#3
0
        /// <summary>
        /// Gets the tax rules that may apply
        /// </summary>
        /// <param name="taxCodeIds">The tax code of the taxable item(s)</param>
        /// <param name="billingAddress">The billing address for the item(s)</param>
        /// <param name="shippingAddresses">The shipping addresses for the item(s)</param>
        /// <param name="user">The user shopping for the item(s)</param>
        /// <returns>A List of TaxRule records that may apply</returns>
        public static List <TaxRule> GetPotentialTaxRules(int[] taxCodeIds, TaxAddress billingAddress, List <TaxAddress> shippingAddresses, User user)
        {
            // BUILD THE KEY
            String cacheKey = GetTaxCodesKey(taxCodeIds) + "~" + GetAddressKey(billingAddress) + "~" + GetAddressKey(shippingAddresses) + "~" + user.UserId;
            Dictionary <string, List <TaxRule> > taxRulesDic = null;

            // CHECK THE HTTP CONTEXT FOR EXISTING RULES
            if (HttpContext.Current != null)
            {
                taxRulesDic = HttpContext.Current.Items["PotentialTaxRules"] as Dictionary <string, List <TaxRule> >;
                if (taxRulesDic != null)
                {
                    if (taxRulesDic.ContainsKey(cacheKey))
                    {
                        return(taxRulesDic[cacheKey]);
                    }
                }
                else
                {
                    taxRulesDic = new Dictionary <string, List <TaxRule> >();
                }
            }

            List <TaxRule>    allRules     = new List <TaxRule>();
            TaxRuleCollection countryRules = TaxRuleDataSource.LoadForTaxCodes(taxCodeIds, billingAddress, user);

            foreach (TaxRule rule in countryRules)
            {
                allRules.Add(rule);
            }
            foreach (TaxAddress shippingAddress in shippingAddresses)
            {
                countryRules = TaxRuleDataSource.LoadForTaxCodes(taxCodeIds, shippingAddress, user);
                foreach (TaxRule rule in countryRules)
                {
                    if (!ListContainsTaxRule(allRules, rule.TaxRuleId))
                    {
                        allRules.Add(rule);
                    }
                }
            }

            // IF CONTEXT IS AVAILABLE STORE THE RESULTS
            if (HttpContext.Current != null)
            {
                taxRulesDic[cacheKey] = allRules;
                HttpContext.Current.Items["PotentialTaxRules"] = taxRulesDic;
            }
            return(allRules);
        }
示例#4
0
        public static TaxAddress ConvertTaxAddress(IAddressBase address)
        {
            var result = new TaxAddress
            {
                Country      = address.CountryID,
                Region       = address.State,
                City         = address.City,
                PostalCode   = address.PostalCode,
                AddressLine1 = address.AddressLine1,
                AddressLine2 = address.AddressLine2,
                AddressLine3 = address.AddressLine3,
            };

            return(result);
        }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="payment">The Payment object associated with this request</param>
 /// <param name="subscriptionPlan">The SubscriptionPlan associated witht this request</param>
 /// <param name="remoteIP">Remote IP of the user initiating the request</param>
 public AuthorizeRecurringTransactionRequest(Payment payment, SubscriptionPlan subscriptionPlan, string remoteIP) : base(payment, remoteIP)
 {
     this._TransactionOrigin = TransactionOrigin.Internet;
     if (subscriptionPlan != null)
     {
         this.SubscriptionName         = subscriptionPlan.Name;
         this.Amount                   = payment.Amount;
         this.RecurringChargeSpecified = subscriptionPlan.RecurringChargeSpecified;
         // GET THE SUBSCRIPTION CHARGE WITH TAX
         Order      order            = payment.Order;
         int        billToProvinceId = ProvinceDataSource.GetProvinceIdByName(order.BillToCountryCode, order.BillToProvince);
         TaxAddress billingAddress   = new TaxAddress(order.BillToCountryCode, billToProvinceId, order.BillToPostalCode);
         this.RecurringCharge      = TaxHelper.GetPriceWithTax(subscriptionPlan.RecurringCharge, subscriptionPlan.TaxCodeId, billingAddress, billingAddress);
         this.NumberOfPayments     = subscriptionPlan.NumberOfPayments;
         this.PaymentFrequency     = subscriptionPlan.PaymentFrequency;
         this.PaymentFrequencyUnit = subscriptionPlan.PaymentFrequencyUnit;
     }
 }
示例#6
0
        /// <summary>
        /// Calculates the Tax for the given price
        /// </summary>
        /// <param name="unitPrice">The unit price to calculate Tax for</param>
        /// <param name="quantity" >The Quantity of the line item</param>
        /// <param name="taxCodeId">The tax code that applies to this price</param>
        /// <param name="priority">The priority of the item - 0 for products, can be greater than 0 for non products items.</param>
        /// <param name="billingAddress">The billing address that applies to the price</param>
        /// <param name="shippingAddress">The shipping address that applies to the price</param>
        /// <param name="user">The user being taxed</param>
        /// <returns>The Tax details for the given price</returns>
        public static TaxInfo InternalGetTaxInfo(LSDecimal unitPrice, int quantity, int taxCodeId, int priority, TaxAddress billingAddress, TaxAddress shippingAddress, User user, bool priceIncludesTax)
        {
            bool      isNegativePrice = (unitPrice < 0);
            LSDecimal absPrice        = isNegativePrice ? (unitPrice * -1) : unitPrice;
            //INITIALIZE TAXES
            LSDecimal totalTax     = 0;
            LSDecimal totalTaxRate = 0;
            //GET ANY RULES THAT MAY APPLY TO THESE ADDRESSES
            List <TaxRule>     taxRules = TaxRuleHelper.GetPotentialTaxRules(taxCodeId, billingAddress, shippingAddress, user);
            List <ShopTaxItem> taxItems = new List <ShopTaxItem>();

            //LOOP ANY RULES AND CALCULATE THE IMPACT OF Tax
            foreach (TaxRule taxRule in taxRules)
            {
                //PREVENT INCORRECT COMPOUNDING, AND ENSURE TAX MEETS ADDRESS CRITERIA
                if (priority < taxRule.Priority && taxRule.AppliesToAddress(billingAddress, shippingAddress))
                {
                    int tempTaxItemCount = taxItems.Count;
                    if (taxRule.AppliesToTaxCode(taxCodeId))
                    {
                        LSDecimal tempTax = LineItemCalculator.CalculateTaxForItem(taxRule, absPrice, quantity, priceIncludesTax);
                        taxItems.Add(new ShopTaxItem(taxRule.TaxCodeId, tempTax, taxRule.TaxRate));
                        totalTax     += tempTax;
                        totalTaxRate += taxRule.TaxRate;
                    }
                    //CHECK IF THIS TAX APPLIES ON ANY PREEXISTING SHOPTAX ITEMS
                    for (int i = 0; i < tempTaxItemCount; i++)
                    {
                        ShopTaxItem thisItem = taxItems[i];
                        if (taxRule.AppliesToTaxCode(thisItem.TaxCodeId))
                        {
                            //TAX ON TAX, RATE MUST BE CALCULATED
                            LSDecimal tempTax = LineItemCalculator.CalculateTaxForItem(taxRule, thisItem.Price, 1, priceIncludesTax);
                            taxItems.Add(new ShopTaxItem(taxRule.TaxCodeId, tempTax, taxRule.TaxRate));
                            totalTax     += tempTax;
                            totalTaxRate += TaxHelper.Round(((decimal)thisItem.TaxRate * (decimal)taxRule.TaxRate) / 100, 2, taxRule.RoundingRule);
                        }
                    }
                }
            }
            if (priceIncludesTax)
            {
                //IF PRICE IS Tax INCLUSIVE, THEN CALCULATED Tax CANNOT EXCEED PRICE
                //THIS WOULD INDICATE A CONFIGURATION ERROR
                if (totalTax > absPrice)
                {
                    totalTax = unitPrice;
                }
                if (totalTaxRate > 100)
                {
                    totalTaxRate = 100;
                }
                if (isNegativePrice)
                {
                    totalTax = totalTax * -1;
                }
                LSDecimal actualPrice = unitPrice - totalTax;
                return(new TaxInfo(actualPrice, totalTax, totalTaxRate));
            }
            else
            {
                if (isNegativePrice)
                {
                    totalTax = totalTax * -1;
                }
                return(new TaxInfo(unitPrice, totalTax, totalTaxRate));
            }
        }
示例#7
0
 private static string GetAddressKey(TaxAddress address)
 {
     return(address.CountryCode + "~" + address.ProvinceId + "~" + address.PostalCode);
 }
示例#8
0
        /// <summary>
        /// Generates payment records for an order
        /// </summary>
        /// <param name="order">The order being created</param>
        /// <param name="checkoutRequest">The checkout request</param>
        /// <param name="giftCertPayments">The collection of gift certificate payments for this order</param>
        /// <param name="giftCertPaymentMethodId">The ID of the gift certificate payment method</param>
        /// <param name="orderItemSubscriptions">Order Item subscriptions</param>
        internal static void GenerateOrderPayments(Order order, CheckoutRequest checkoutRequest, List <BasketPaymentItem> giftCertPayments, int giftCertPaymentMethodId, Dictionary <int, Subscription[]> orderItemSubscriptions)
        {
            //THIS VARIABLE SHOULD ONLY CONTAIN DATA IF POST-CHECKOUT GATEWAY PROCESSING IS REQUIRED
            string saveAccountData = string.Empty;
            //USE A COMMON DATE FOR ALL PAYMENTS REGISTERED
            DateTime paymentDate = LocaleHelper.LocalNow;
            //CONVERT GIFT CERTIFICATE PLACEHOLDERS INTO PAYMENT ITEMS
            LSDecimal totalGiftCertPayment = 0;

            foreach (BasketPaymentItem giftCertItem in giftCertPayments)
            {
                Payment giftCertPayment = giftCertItem.GetPaymentObject();
                totalGiftCertPayment           += giftCertPayment.Amount;
                giftCertPayment.OrderId         = order.OrderId;
                giftCertPayment.PaymentMethodId = giftCertPaymentMethodId;
                giftCertPayment.PaymentDate     = paymentDate;
                order.Payments.Add(giftCertPayment);
                giftCertPayment.Save();
            }
            //IF PAYMENT DATA WAS PASSED WITH CHECKOUT REQUEST, ADD TO ORDER RECORD NOW
            if (checkoutRequest != null && checkoutRequest.Payment != null)
            {
                //BUILD A LIST OF PAYMENTS TO ADD TO THE ORDER BASED ON CONTENTS
                Payment originalPayment = checkoutRequest.Payment;
                //DETERMINE TOTAL PAYMENT REQUIRED FOR ITEMS
                LSDecimal remainingPaymentAmount = order.Items.TotalPrice();
                //PRESERVE ACCOUNT DATA
                saveAccountData = originalPayment.AccountData;
                //DECIDE WHETHER PAYMENTS MUST BE DIVIDED BECAUSE OF ARB SUBSCRIPTIONS
                if (orderItemSubscriptions.Count > 0)
                {
                    //LOOP EACH ORDER ITEM WITH A RECURRING SUBSCRIPTION
                    foreach (int orderItemId in orderItemSubscriptions.Keys)
                    {
                        // THIS STORES THE DISCOUNT TO APPLY TO EACH SUBSCRIPTION PAYMENT
                        LSDecimal subscriptionDiscount = 0;
                        // THIS STORES ADDITIONAL DISCOUNT TO APPLY ONLY TO THE FIRST SUBSCRIPTION
                        LSDecimal firstSubscriptionAdjustment = 0;
                        // GET THE TOTAL DISCOUNTS APPLIED TO THIS ORDER ITEM (VALUE SHOULD BE NEGATIVE)
                        LSDecimal totalItemAdjustments = GetOrderItemAdjustments(order, orderItemId);
                        // IF THERE IS A DISCOUNT, DETERMINE PRO-RATED DISCOUNT FOR EACH PAYMENT (ITEM)
                        if (totalItemAdjustments != 0)
                        {
                            // THERE IS A DISCOUNT THAT APPLIES TO THIS ORDER ITEM, WE NEED TO DETERMINE AMOUNT
                            // SUBSCRIPTION DISCOUNT IS TOTAL DISCOUNT BY THE NUMBER OF SUBSCRIPTION ITEMS
                            subscriptionDiscount = (LSDecimal)Math.Floor((decimal)(totalItemAdjustments / orderItemSubscriptions[orderItemId].Length));
                            // DETERMINE THE TOTAL DISCOUNT AMOUNT USING CALCULATED PER-SUBSCRIPTION VALUE
                            LSDecimal calculatedTotal = subscriptionDiscount * orderItemSubscriptions[orderItemId].Length;
                            // THE TOTAL DISCOUNT MUST MATCH THE LUMP SUM, SO CALCULATE ANY LEFTOVER DISCOUNT FOR THE FIRST PAYMENT
                            firstSubscriptionAdjustment = (totalItemAdjustments - calculatedTotal);
                        }

                        // WE MUST DETERMINE THE PRICE OF THE ITEM (INCLUDING TAX)
                        // GET THE ORDER ITEM FOR THIS RECURRING SUBSCRIPTION
                        OrderItem orderItem = order.Items[order.Items.IndexOf(orderItemId)];
                        // GET THE PRICE OF THE ITEM (INCLUDING TAX)
                        int        billToProvinceId  = ProvinceDataSource.GetProvinceIdByName(order.BillToCountryCode, order.BillToProvince);
                        TaxAddress billingAddress    = new TaxAddress(order.BillToCountryCode, billToProvinceId, order.BillToPostalCode);
                        LSDecimal  subscriptionPrice = TaxHelper.GetPriceWithTax(orderItem.Price + subscriptionDiscount, orderItem.TaxCodeId, billingAddress, billingAddress);

                        // LOOP ALL THE SUBSCRIPTIONS AND CREATE CORRESPONDING PAYMENT ITEMS
                        foreach (Subscription s in orderItemSubscriptions[orderItemId])
                        {
                            // ADD PAYMENT ITEM ASSOCIATED WITH THE SUBSCRIPTION
                            Payment arbPayment = new Payment();
                            arbPayment.SubscriptionId    = s.SubscriptionId;
                            arbPayment.Amount            = subscriptionPrice + firstSubscriptionAdjustment;
                            arbPayment.CurrencyCode      = originalPayment.CurrencyCode;
                            arbPayment.OrderId           = order.OrderId;
                            arbPayment.PaymentDate       = paymentDate;
                            arbPayment.PaymentMethodId   = originalPayment.PaymentMethodId;
                            arbPayment.PaymentMethodName = originalPayment.PaymentMethodName;
                            arbPayment.PaymentStatus     = PaymentStatus.Unprocessed;
                            arbPayment.ReferenceNumber   = originalPayment.ReferenceNumber;
                            arbPayment.AccountData       = saveAccountData;
                            order.Payments.Add(arbPayment);
                            arbPayment.Save();

                            //ACCOUNT DATA IS RESET AFTER SAVE IN CASE THE SAVE METHOD ALTERS IT BASED
                            //ON MERCHANT SECURITY SETTINGS, WE STILL NEED THE VALUE FOR THE CHECKOUT PROCESS
                            arbPayment.AccountData = saveAccountData;
                            arbPayment.IsDirty     = false;

                            // SUBTRACT THIS PAYMENT FROM THE REMAINING TOTAL
                            remainingPaymentAmount -= arbPayment.Amount;

                            // RESET ADJUSTMENT THAT SHOULD APPLY TO FIRST SUBSCRIPTION ONLY
                            firstSubscriptionAdjustment = 0;
                        }
                    }

                    //CREATE AN ADDITIONAL PAYMENT IF THERE IS ANY AMOUNT LEFT TO BE COLLECTED
                    if (remainingPaymentAmount > 0)
                    {
                        //NEED ONE PAYMENT FOR EACH SUBSCRIPTION
                        Payment remainingPayment = new Payment();
                        remainingPayment.SubscriptionId = 0;
                        if (remainingPaymentAmount >= originalPayment.Amount)
                        {
                            remainingPayment.Amount = originalPayment.Amount;
                        }
                        else
                        {
                            remainingPayment.Amount = remainingPaymentAmount;
                        }
                        remainingPayment.CurrencyCode      = originalPayment.CurrencyCode;
                        remainingPayment.OrderId           = order.OrderId;
                        remainingPayment.PaymentDate       = paymentDate;
                        remainingPayment.PaymentMethodId   = originalPayment.PaymentMethodId;
                        remainingPayment.PaymentMethodName = originalPayment.PaymentMethodName;
                        remainingPayment.PaymentStatus     = PaymentStatus.Unprocessed;
                        remainingPayment.ReferenceNumber   = originalPayment.ReferenceNumber;
                        remainingPayment.AccountData       = saveAccountData;
                        order.Payments.Add(remainingPayment);
                        remainingPayment.Save();
                        //ACCOUNT DATA IS RESET AFTER SAVE IN CASE THE SAVE METHOD ALTERS IT BASED
                        //ON MERCHANT SECURITY SETTINGS, WE STILL NEED THE VALUE FOR THE CHECKOUT PROCESS
                        remainingPayment.AccountData = saveAccountData;
                        remainingPayment.IsDirty     = false;
                    }
                }
                else
                {
                    originalPayment.PaymentId      = 0;
                    originalPayment.SubscriptionId = 0;
                    originalPayment.PaymentStatus  = PaymentStatus.Unprocessed;
                    originalPayment.OrderId        = order.OrderId;
                    originalPayment.PaymentDate    = paymentDate;
                    order.Payments.Add(originalPayment);
                    originalPayment.Save();
                    //ACCOUNT DATA IS RESET AFTER SAVE IN CASE THE SAVE METHOD ALTERS IT BASED
                    //ON MERCHANT SECURITY SETTINGS, WE STILL NEED THE VALUE FOR THE CHECKOUT PROCESS
                    originalPayment.AccountData = saveAccountData;
                    originalPayment.IsDirty     = false;
                }
            }
        }