public int Add(AddSubscriptionBookingParams param)
        {
            try
            {
                using (var transaction = new TransactionScope())
                {
                    var bookingCode = Helper.RandomString(Constant.BookingCodeLength);
                    while (IsBookingCodeExists(bookingCode))
                    {
                        bookingCode = Helper.RandomString(Constant.BookingCodeLength);
                    }
                    param.SubscriptionBookingsObject.BookingCode = bookingCode;

                    // Insert New Bookings
                    DayaxeDbContext.SubscriptionBookings.InsertOnSubmit(param.SubscriptionBookingsObject);
                    Commit();

                    if (param.SubscriptionBookingDiscounts != null && param.SubscriptionBookingDiscounts.Id > 0)
                    {
                        var subscriptionDiscount = new SubscriptionBookingDiscounts
                        {
                            DiscountId            = param.SubscriptionBookingDiscounts.Id,
                            SubscriptionBookingId = param.SubscriptionBookingsObject.Id,
                            SubscriptionId        = param.SubscriptionBookingsObject.SubscriptionId
                        };

                        DayaxeDbContext.SubscriptionBookingDiscounts.InsertOnSubmit(subscriptionDiscount);
                    }

                    // Insert to History for First Cycle
                    var cycle = new SubscriptionCycles
                    {
                        SubscriptionBookingId = param.SubscriptionBookingsObject.Id,
                        StartDate             = param.SubscriptionBookingsObject.StartDate,
                        EndDate         = param.SubscriptionBookingsObject.EndDate,
                        CancelDate      = param.SubscriptionBookingsObject.CancelDate,
                        LastUpdatedBy   = param.SubscriptionBookingsObject.LastUpdatedBy,
                        LastUpdatedDate = param.SubscriptionBookingsObject.LastUpdatedDate,
                        Status          = param.SubscriptionBookingsObject.Status,
                        Price           = param.ActualPrice,
                        MerchantPrice   = param.MerchantPrice,
                        PayByCredit     = param.PayByCredit,
                        TotalPrice      = param.TotalPrice,
                        Quantity        = param.SubscriptionBookingsObject.Quantity,
                        StripeChargeId  = string.Empty,
                        StripeCouponId  = param.SubscriptionBookingsObject.StripeCouponId,
                        StripeInvoiceId = string.Empty,
                        CycleNumber     = 1
                    };

                    DayaxeDbContext.SubscriptionCycles.InsertOnSubmit(cycle);

                    // Insert Discount for Current Customer active Subscription
                    var discount = new Discounts
                    {
                        DiscountName = string.Format("{0} - {1} {2}",
                                                     param.SubscriptionName,
                                                     param.FirstName,
                                                     param.LastName),
                        Code          = string.Format("SUP{0}", Helper.RandomString(8)),
                        StartDate     = param.SubscriptionBookingsObject.StartDate,
                        EndDate       = param.SubscriptionBookingsObject.EndDate,
                        CodeRequired  = true,
                        PercentOff    = 100,
                        PromoType     = (byte)Enums.PromoType.SubscriptionPromo,
                        MinAmount     = 0,
                        IsAllProducts = true,
                        MaxPurchases  = (byte)param.MaxPurchases
                    };
                    DayaxeDbContext.Discounts.InsertOnSubmit(discount);
                    Commit();

                    // Add Invoices
                    var subscriptionInvoice = new SubscriptionInvoices
                    {
                        SubscriptionCyclesId = cycle.Id,
                        BookingStatus        = cycle.Status,
                        Quantity             = cycle.Quantity,
                        Price              = cycle.Price,
                        MerchantPrice      = cycle.MerchantPrice,
                        PayByCredit        = cycle.PayByCredit,
                        TotalPrice         = cycle.TotalPrice,
                        InvoiceStatus      = (int)Enums.InvoiceStatus.Charge,
                        StripeChargeId     = cycle.StripeChargeId,
                        ChargeAmount       = cycle.Price,
                        StripeRefundId     = string.Empty,
                        RefundAmount       = 0,
                        RefundCreditAmount = 0,
                        StripeCouponId     = cycle.StripeCouponId,
                        CreatedDate        = DateTime.UtcNow,
                        CreatedBy          = 1
                    };
                    DayaxeDbContext.SubscriptionInvoices.InsertOnSubmit(subscriptionInvoice);

                    var discountUsed = new SubsciptionDiscountUseds
                    {
                        CustomerId            = param.SubscriptionBookingsObject.CustomerId,
                        DiscountId            = discount.Id,
                        SubscriptionBookingId = param.SubscriptionBookingsObject.Id
                    };
                    DayaxeDbContext.SubsciptionDiscountUseds.InsertOnSubmit(discountUsed);

                    var cusCredits = DayaxeDbContext.CustomerCredits
                                     .SingleOrDefault(cc => cc.CustomerId == param.CustomerCreditsObject.CustomerId);

                    // Add Logs when refund by Upgrade to Subscription
                    if (param.RefundCreditByUpgrade > 0)
                    {
                        var creditLogs = new CustomerCreditLogs
                        {
                            Amount                = param.RefundCreditByUpgrade,
                            ProductId             = 0,
                            BookingId             = 0,
                            SubscriptionId        = param.SubscriptionBookingsObject.SubscriptionId,
                            CreatedBy             = param.CustomerCreditsObject.CustomerId,
                            CreatedDate           = DateTime.UtcNow,
                            CreditType            = (byte)Enums.CreditType.PartialPuchaseRefund,
                            Description           = param.RefundCreditDescription,
                            CustomerId            = param.CustomerCreditsObject.CustomerId,
                            ReferralId            = param.CustomerCreditsObject.ReferralCustomerId,
                            SubscriptionBookingId = param.SubscriptionBookingsObject.Id,
                            Status                = true,
                            GiftCardId            = 0
                        };

                        DayaxeDbContext.CustomerCreditLogs.InsertOnSubmit(creditLogs);

                        if (cusCredits != null)
                        {
                            cusCredits.Amount += param.RefundCreditByUpgrade;
                        }
                    }

                    // Add Logs when pay by DayAxe Credit
                    if (param.PayByCredit > 0)
                    {
                        var creditLogs = new CustomerCreditLogs
                        {
                            Amount                = param.PayByCredit,
                            ProductId             = 0,
                            BookingId             = 0,
                            SubscriptionId        = param.SubscriptionBookingsObject.SubscriptionId,
                            CreatedBy             = param.CustomerCreditsObject.CustomerId,
                            CreatedDate           = DateTime.UtcNow,
                            CreditType            = (byte)Enums.CreditType.Charge,
                            Description           = param.Description,
                            CustomerId            = param.CustomerCreditsObject.CustomerId,
                            ReferralId            = param.CustomerCreditsObject.ReferralCustomerId,
                            SubscriptionBookingId = param.SubscriptionBookingsObject.Id,
                            Status                = true,
                            GiftCardId            = 0
                        };

                        DayaxeDbContext.CustomerCreditLogs.InsertOnSubmit(creditLogs);

                        if (cusCredits != null)
                        {
                            cusCredits.Amount -= param.PayByCredit;
                        }
                    }

                    // First Buy of referral
                    if (param.CustomerCreditsObject != null && param.CustomerCreditsObject.ReferralCustomerId > 0 && (
                            DayaxeDbContext.Bookings.Count(x => x.CustomerId == param.SubscriptionBookingsObject.CustomerId) == 1 ||
                            DayaxeDbContext.SubscriptionBookings.Count(x => x.CustomerId == param.SubscriptionBookingsObject.CustomerId) == 1))
                    {
                        var logs = DayaxeDbContext.CustomerCreditLogs
                                   .Where(ccl => ccl.CustomerId == param.CustomerCreditsObject.ReferralCustomerId &&
                                          ccl.ReferralId == param.SubscriptionBookingsObject.CustomerId &&
                                          !ccl.Status)
                                   .ToList();

                        if (logs.Any())
                        {
                            logs.ForEach(log =>
                            {
                                var cus = DayaxeDbContext.CustomerCredits
                                          .FirstOrDefault(cc => cc.CustomerId == log.CustomerId);
                                if (cus != null)
                                {
                                    cus.Amount += log.Amount;
                                }

                                log.Status = true;
                            });
                            Commit();
                        }
                    }

                    // Add to Customer Credit Log
                    var logsReferred = DayaxeDbContext.CustomerCreditLogs
                                       .Where(ccl => ccl.ReferralId == param.SubscriptionBookingsObject.CustomerId && !ccl.Status)
                                       .ToList();
                    if (logsReferred.Any())
                    {
                        logsReferred.ForEach(log =>
                        {
                            var cus = DayaxeDbContext.CustomerCredits
                                      .FirstOrDefault(cc => cc.CustomerId == log.CustomerId);
                            if (cus != null)
                            {
                                cus.Amount += log.Amount;
                            }

                            log.Status = true;
                        });
                    }

                    // Insert Schedule
                    var schedules = new Schedules
                    {
                        ScheduleSendType      = (int)Enums.ScheduleSendType.IsEmailConfirmSubscription,
                        Name                  = "Send Email confirm Subscription",
                        Status                = (int)Enums.ScheduleType.NotRun,
                        SubscriptionBookingId = param.SubscriptionBookingsObject.Id
                    };
                    DayaxeDbContext.Schedules.InsertOnSubmit(schedules);

                    // Maybe not use here because flow upgrade to subscription do not use this
                    if (param.BookingId > 0)
                    {
                        var bookings = DayaxeDbContext.Bookings.FirstOrDefault(b => b.BookingId == param.BookingId);
                        if (bookings != null)
                        {
                            var chargePrice = (int)((bookings.TotalPrice - bookings.HotelPrice) * 100);
                            try
                            {
                                bookings.TotalPrice -= bookings.HotelPrice;
                                bookings.PassStatus  = (int)Enums.BookingStatus.Active;

                                var discounts = new DiscountBookings
                                {
                                    DiscountId = discount.Id,
                                    ProductId  = bookings.ProductId,
                                    BookingId  = bookings.BookingId
                                };

                                DayaxeDbContext.DiscountBookings.InsertOnSubmit(discounts);
                                bookings.IsActiveSubscription = true;

                                string responseString;
                                if (chargePrice > 0)
                                {
                                    var          chargeService = new StripeChargeService();
                                    StripeCharge charge        = chargeService.Capture(bookings.StripeChargeId, chargePrice);
                                    responseString = charge.StripeResponse.ResponseJson;
                                }
                                else
                                {
                                    var refundOptions = new StripeRefundCreateOptions
                                    {
                                        Reason = StripeRefundReasons.RequestedByCustomer
                                    };
                                    var          refundService = new StripeRefundService();
                                    StripeRefund refund        = refundService.Create(bookings.StripeChargeId, refundOptions);
                                    responseString = refund.StripeResponse.ResponseJson;
                                }

                                var logs = new Logs
                                {
                                    LogKey         = "UpgradeSubscriptionCharge",
                                    UpdatedContent = string.Format("Params: {0} - Response: {1}",
                                                                   JsonConvert.SerializeObject(param, CustomSettings.SerializerSettings()),
                                                                   responseString),
                                    UpdatedBy   = param.SubscriptionBookingsObject.CustomerId,
                                    UpdatedDate = DateTime.UtcNow
                                };
                                AddLog(logs);
                            }
                            catch (Exception ex)
                            {
                                var logs = new Logs
                                {
                                    LogKey         = "UpgradeSubscriptionChargeError",
                                    UpdatedContent = string.Format("Params: {0} - {1} - {2} - {3}",
                                                                   JsonConvert.SerializeObject(param, CustomSettings.SerializerSettings()),
                                                                   ex.Message,
                                                                   ex.StackTrace,
                                                                   ex.Source),
                                    UpdatedBy   = param.SubscriptionBookingsObject.CustomerId,
                                    UpdatedDate = DateTime.UtcNow
                                };
                                AddLog(logs);
                            }
                        }
                    }

                    Commit();

                    transaction.Complete();
                }
            }
            catch (Exception ex)
            {
                var logs = new Logs
                {
                    LogKey         = "AddBookingError",
                    UpdatedContent = string.Format("{0} - {1} - {2} - {3}", param.SubscriptionBookingsObject.CustomerId, ex.Message, ex.StackTrace, ex.Source),
                    UpdatedBy      = param.SubscriptionBookingsObject.CustomerId,
                    UpdatedDate    = DateTime.UtcNow
                };
                AddLog(logs);

                throw new Exception(ex.Message, ex);
            }

            return(param.SubscriptionBookingsObject.Id);
        }
        private int PurchaseSubscription(out bool success)
        {
            // Check customer change their email
            success = true;
            bool isPayByCredit;

            var bookingExists = _subscriptionBookingRepository.GetBookingInLast3Minutes(PublicSubscription.Id,
                                                                                        PublicCustomerInfos != null ? PublicCustomerInfos.EmailAddress : email.Text.Replace(" ", ""));

            if (bookingExists != null)
            {
                success = false;
                newBookingModal.Visible = true;
                return(bookingExists.Id);
            }

            if (PublicCustomerInfos == null)
            {
                PublicCustomerInfos = new CustomerInfos
                {
                    EmailAddress = email.Text.Replace(" ", ""),
                    FirstName    = FirstName.Text.Trim(),
                    LastName     = LastName.Text.Trim(),
                    ZipCode      = txtzipcode.Text.Trim()
                };

                // Create new account with email
                var response = _customerInfoRepository.GetVipAccess(email.Text.Replace(" ", ""), Constant.SearchPageDefault, FirstName.Text.Trim(), LastName.Text.Trim());
                PublicCustomerInfos.CustomerId       = response.CustomerId;
                PublicCustomerInfos.StripeCustomerId = response.StripeCustomerId;

                CacheLayer.Clear(CacheKeys.CustomerInfosCacheKey);
                CacheLayer.Clear(CacheKeys.CustomerCreditsCacheKey);

                Session["ReferralCode"] = response.ReferralCode;

                string searchPage = !string.IsNullOrEmpty((string)Session["SearchPage"])
                    ? Session["SearchPage"].ToString()
                    : Constant.SearchPageDefault;

                // Send email new account
                var responseEmail = EmailHelper.EmailNewAccount(PublicCustomerInfos.EmailAddress,
                                                                PublicCustomerInfos.FirstName,
                                                                response.Password,
                                                                Helper.ResolveRelativeToAbsoluteUrl(Request.Url,
                                                                                                    string.Format("{0}?sp={1}",
                                                                                                                  searchPage,
                                                                                                                  response.PasswordKey)), // Reset Password Url
                                                                Helper.ResolveRelativeToAbsoluteUrl(Request.Url,
                                                                                                    string.Format("{0}?c={1}",
                                                                                                                  searchPage,
                                                                                                                  response.AccessKey))); // Browse Day Pass
                PublicCustomerCredits = _subscriptionBookingRepository.GetCustomerCredits(response.CustomerId);


                Session["UserSession"]  = response.AccessKey;
                Session["IsRegister"]   = true;
                Session["ReferralCode"] = response.ReferralCode;
            }

            Regex regex = new Regex(@"([\d]+)(\s)?/(\s)?([\d]+)");
            int   month;
            int   year;

            int.TryParse(regex.Match(txtexpdat.Value).Groups[1].Value, out month);
            int.TryParse("20" + regex.Match(txtexpdat.Value).Groups[4].Value, out year);
            string fullName = string.Format("{0} {1}", FirstName.Text, LastName.Text);

            // Check customer has exists with email
            int            customerId     = PublicCustomerInfos.CustomerId;
            StripeCustomer stripeCustomer = null;
            Discounts      discounts      = new Discounts();
            double         actualPrice    = PublicSubscription.Price;
            double         totalPrice;
            bool           hasCoupon      = false;
            string         stripeCouponId = string.Empty;

            // update user info with exists
            if (!string.IsNullOrEmpty(PublicCustomerInfos.StripeCustomerId))
            {
                stripeCustomer = GetCustomerById(PublicCustomerInfos.StripeCustomerId);
            }

            // Use New Card
            if (MVCardInfo.ActiveViewIndex == 0)
            {
                StripeToken stripeToken = CreateToken(cctextbox.Text.Replace(" ", ""), year, month, txtzipcode.Text,
                                                      fullName,
                                                      txtseccode.Value);

                // update new card for customer
                PublicCustomerInfos.StripeTokenId    = stripeToken.Id;
                PublicCustomerInfos.StripeCardId     = stripeToken.StripeCard.Id;
                PublicCustomerInfos.BankAccountLast4 = stripeToken.StripeCard.Last4;
                PublicCustomerInfos.CardType         = Helper.GetCreditCardType(cctextbox.Text.Replace(" ", ""));
                PublicCustomerInfos.ZipCode          = txtzipcode.Text;

                if (stripeCustomer == null)
                {
                    stripeCustomer = CreateCustomer(PublicCustomerInfos.EmailAddress, fullName, stripeToken.Id);
                    PublicCustomerInfos.StripeCustomerId = stripeCustomer.Id;
                }
                else
                {
                    // Update Stripe exists customer with New Card
                    var card = CreateCard(stripeToken.Id, PublicCustomerInfos.StripeCustomerId);
                    UpdateCustomer(PublicCustomerInfos.EmailAddress, fullName,
                                   PublicCustomerInfos.StripeCustomerId, card.Id);
                }
                _customerInfoRepository.Update(PublicCustomerInfos);

                isPayByCredit = IsPayByCreditCheckBox.Checked;
            }
            else
            {
                isPayByCredit = DCreditCheckBox.Checked;
            }

            if (string.IsNullOrWhiteSpace(PromoText.Text))
            {
                Session.Remove(_discountKey);
            }

            // Not available upgrade so checkout with this hotel
            if (Session[_discountKey] != null)
            {
                discounts = JsonConvert.DeserializeObject <Discounts>(Session[_discountKey].ToString());
            }

            // Have Discount
            if (discounts != null && discounts.Id > 0)
            {
                discounts = _discountRepository.VerifyDiscountsSubscription(discounts, customerId, PublicSubscription.Id);

                // Discount Invalid
                if (discounts != null)
                {
                    actualPrice = Helper.CalculateDiscount(discounts, actualPrice, TotalTickets);
                    hasCoupon   = true;
                }
                else
                {
                    InitDefaultPromo(Message.ExceedLimit, false);
                    Session[_discountKey] = null;
                    success = false;
                    return(0);
                }

                if (discounts.BillingCycleNumber > 1)
                {
                    stripeCouponId = string.Format("{0}C{1}", PublicCustomerInfos.CustomerId,
                                                   Helper.RandomString(Constant.BookingCodeLength));
                    if (discounts.PercentOff > 0)
                    {
                        var couponPrice = PublicSubscription.Price - actualPrice;
                        //Create the Coupon
                        var coupon = new StripeCouponCreateOptions
                        {
                            Duration         = "repeating",
                            Id               = stripeCouponId,
                            MaxRedemptions   = discounts.BillingCycleNumber,
                            DurationInMonths = discounts.BillingCycleNumber
                        };


                        if (discounts.PromoType == (int)Enums.PromoType.Fixed)
                        {
                            coupon.AmountOff = (int)(couponPrice * 100);
                            coupon.Currency  = "usd";
                        }

                        if (discounts.PromoType == (int)Enums.PromoType.Percent)
                        {
                            coupon.PercentOff = (int)(discounts.PercentOff);
                        }

                        //coupon.AmountOff - AmountOff is not a property of StripeCouponCreateOptions
                        var          couponService = new StripeCouponService();
                        StripeCoupon createdCoupon = couponService.Create(coupon);

                        //Apply it to the customer
                        var customerOptions = new StripeCustomerUpdateOptions
                        {
                            Coupon = createdCoupon.Id
                        };

                        var customerService = new StripeCustomerService();
                        customerService.Update(PublicCustomerInfos.StripeCustomerId, customerOptions);
                    }
                }
            }

            if (PublicCustomerInfos.FirstName != FirstName.Text.Trim() || PublicCustomerInfos.LastName != LastName.Text.Trim())
            {
                PublicCustomerInfos.FirstName = FirstName.Text.Trim();
                PublicCustomerInfos.LastName  = LastName.Text.Trim();
                _customerInfoRepository.Update(PublicCustomerInfos);

                // Update Stripe exists customer
                UpdateCustomer(PublicCustomerInfos.EmailAddress, fullName, PublicCustomerInfos.StripeCustomerId, string.Empty);
            }

            // Discount 100% ??
            // Price equal 0, so we should not charge with this
            totalPrice = actualPrice * TotalTickets;
            double chargePrice          = totalPrice;
            string creditLogDescription = string.Empty;

            var subscriptionOptions = new StripeSubscriptionCreateOptions
            {
                PlanId = PublicSubscription.StripePlanId
            };

            // Use DayAxe Credit
            if (isPayByCredit && PublicCustomerCredits != null && PublicCustomerCredits.Amount > 0)
            {
                hasCoupon = true;

                chargePrice = totalPrice - PublicCustomerCredits.Amount;
                if (chargePrice <= 0)
                {
                    chargePrice = 0;
                }
            }

            if (hasCoupon && string.IsNullOrEmpty(stripeCouponId))
            {
                var couponPrice = PublicSubscription.Price - chargePrice;
                if (couponPrice > 0)
                {
                    // Create Coupon Id because we used DayAxe Credit
                    stripeCouponId = string.Format("{0}C{1}", PublicCustomerInfos.CustomerId,
                                                   Helper.RandomString(Constant.BookingCodeLength));
                    var couponOptions = new StripeCouponCreateOptions
                    {
                        Id        = stripeCouponId,
                        AmountOff = Convert.ToInt32(couponPrice * 100), // USD
                        Duration  = "once",
                        Currency  = "USD"
                    };

                    // Create Coupon
                    var couponService = new StripeCouponService();
                    var coupon        = couponService.Create(couponOptions);

                    subscriptionOptions.CouponId = stripeCouponId;

                    creditLogDescription = string.Format("{0} – {1}",
                                                         PublicSubscription.Name, coupon.Id);
                }
            }

            // Create Subscription on Stripe
            var subscriptionService         = new StripeSubscriptionService();
            StripeSubscription subscription = subscriptionService.Create(PublicCustomerInfos.StripeCustomerId, subscriptionOptions);

            var booking = new SubscriptionBookings
            {
                SubscriptionId       = PublicSubscription.Id,
                Quantity             = TotalTickets,
                StripeCouponId       = stripeCouponId,
                BookedDate           = DateTime.UtcNow,
                ActivedDate          = subscription.Start,
                StartDate            = subscription.CurrentPeriodStart,
                EndDate              = subscription.CurrentPeriodEnd,
                Status               = (int)Enums.SubscriptionBookingStatus.Active,
                CustomerId           = customerId,
                LastUpdatedDate      = DateTime.UtcNow,
                LastUpdatedBy        = customerId,
                StripeSubscriptionId = subscription.Id
            };

            var param = new AddSubscriptionBookingParams
            {
                SubscriptionBookingsObject = booking,
                CustomerCreditsObject      = PublicCustomerCredits,
                Description                  = creditLogDescription,
                SubscriptionName             = PublicSubscription.Name,
                FirstName                    = PublicCustomerInfos.FirstName,
                LastName                     = PublicCustomerInfos.LastName,
                SubscriptionBookingDiscounts = discounts,
                ActualPrice                  = actualPrice,
                MerchantPrice                = PublicSubscription.Price,
                PayByCredit                  = totalPrice.Equals(chargePrice) ? 0 : totalPrice - chargePrice,
                TotalPrice                   = chargePrice,
                MaxPurchases                 = PublicSubscription.MaxPurchases
            };

            int bookingId = _subscriptionBookingRepository.Add(param);

            //Session.Remove(_discountKey);

            CacheLayer.Clear(CacheKeys.SubscriptionBookingsCacheKey);
            CacheLayer.Clear(CacheKeys.CustomerInfosCacheKey);
            CacheLayer.Clear(CacheKeys.CustomerCreditsCacheKey);
            CacheLayer.Clear(CacheKeys.CustomerCreditLogsCacheKey);
            CacheLayer.Clear(CacheKeys.DiscountsCacheKey);
            CacheLayer.Clear(CacheKeys.SubscriptionBookingDiscountsCacheKey);
            CacheLayer.Clear(CacheKeys.SubsciptionDiscountUsedCacheKey);
            CacheLayer.Clear(CacheKeys.SubscriptionDiscountsCacheKey);
            CacheLayer.Clear(CacheKeys.SubscriptionCyclesCacheKey);

            return(bookingId);
        }