/// <summary>
        /// Creating a request to get PayKey from PayPal
        /// </summary>
        /// <param name="receiver1amount">amount that receiver1 receives</param>
        /// <param name="receiver2amount">amount that receiver2 receives</param>
        /// <param name="receiver1email">email of receiver1 (max length 127 characters)</param>
        /// <param name="receiver2email">email of receiver2 (max length 127 characters)</param>
        /// <param name="senderEmail">Sender's email address. Maximum length: 127 characters</param>
        /// <returns></returns>
        public string GetPayKey(VisitParallelPaymentParameters p)
        {
            var payRequest  = CreateVisitPaymentRequest(p);
            var payResponse = CallPaypalPay(payRequest);

            return(payResponse.payKey);
        }
        /// <summary>
        /// Gets PayKey from PayPal and updates in the database
        /// </summary>
        /// <param name="paymentId">Payment indentifier</param>
        public Payment UpdatePayPalKey(long paymentId)
        {
            vPayment payment = (vPayment)GetByID(paymentId, new GetByIDParameters(GetSourceTypeEnum.View));

            IUserPaymentInfoService service =
                (IUserPaymentInfoService)EntityFactory.GetEntityServiceByName(vUserPaymentInfo.EntityName, "");

            UserPaymentInfo senderPaymentInfo   = (UserPaymentInfo)service.GetByID(payment.SenderUserID, new GetByIDParameters());
            UserPaymentInfo receiverPaymentInfo = (UserPaymentInfo)service.GetByID(payment.ReceiverUserID, new GetByIDParameters());

            // Checking the business rules first
            PaymentBR biz = (PaymentBR)this.BusinessLogicObject;

            biz.UpdatePayKey(payment, senderPaymentInfo, receiverPaymentInfo);

            VisitParallelPaymentParameters p = new VisitParallelPaymentParameters();

            p.paymentId       = paymentId;
            p.receiver1amount = payment.Amount - payment.ServiceChargeAmount;
            p.receiver2amount = payment.ServiceChargeAmount;
            p.receiver1email  = receiverPaymentInfo.UserPaymentInfoPayPalEmail;
            p.receiver2email  = FWUtils.ConfigUtils.GetAppSettings().Paypal.MainAccount;

            // DEVELOPER NOTE: PayPal Embedded Payment has a bug; it returns an error Payment can't be completed. This feature is currently unavailable.
            // In order to fix the bug, sender email should not be specified. In addition, not specifying sender email allows Guest Payment (without having a PayPal account)
            // Read more here: http://stackoverflow.com/questions/12666184/embedded-payments-and-this-function-is-temporarily-unavailable-error
            //p.senderEmail = senderPaymentInfo.UserPaymentInfoPayPalEmail;

            PayPalService payPal = new PayPalService();
            string        payKey = payPal.GetPayKey(p);

            // logging the details
            long?userId = null;

            if (FWUtils.SecurityUtils.IsUserAuthenticated())
            {
                userId = FWUtils.SecurityUtils.GetCurrentUserIDLong();
            }
            string logString = "" + p.senderEmail + "\t" + p.receiver1email + "\t" + p.receiver1amount + "\t" + p.receiver2amount;

            FWUtils.ExpLogUtils.Logger.WriteLog(new AppLog()
            {
                AppLogTypeID = (short)EntityEnums.AppLogType.PayPal_UpdatePayKey, UserID = userId, ExtraBigInt = paymentId, ExtraString1 = payKey, ExtraString2 = logString
            });

            return(UpdatePaykeyInDatabase(payment.PaymentID, payKey));
        }
        /// <summary>
        /// Creating a request to get PayKey from PayPal
        /// </summary>
        /// <param name="receiver1amount">amount that receiver1 receives</param>
        /// <param name="receiver2amount">amount that receiver2 receives</param>
        /// <param name="receiver1email">email of receiver1 (max length 127 characters)</param>
        /// <param name="receiver2email">email of receiver2 (max length 127 characters)</param>
        /// <param name="senderEmail">Sender's email address. Maximum length: 127 characters</param>
        /// <returns></returns>
        private PayRequest CreateVisitPaymentRequest(VisitParallelPaymentParameters p)
        {
            Check.Require(string.IsNullOrEmpty(p.receiver1email) == false);
            Check.Require(string.IsNullOrEmpty(p.receiver2email) == false);
            //Check.Require(string.IsNullOrEmpty(p.senderEmail) == false);
            Check.Require(p.receiver1email.Length <= 127);
            Check.Require(p.receiver2email.Length <= 127);
            if (string.IsNullOrEmpty(p.senderEmail) == false)
            {
                Check.Require(p.senderEmail.Length <= 127);
            }


            //// (Optional) Sender's email address. Maximum length: 127 characters
            ////TODO: See why it is optional. It should deduct from the sender only

            // URL to redirect the sender's browser to after canceling the approval
            // for a payment; it is always required but only used for payments that
            // require approval (explicit payments)
            string cancelUrl = FWUtils.ConfigUtils.GetAppSettings().Paypal.GetCancelUrlPaymentID(p.paymentId);

            // The code for the currency in which the payment is made; you can
            // specify only one currency, regardless of the number of receivers
            string currencyCode = p.currencyCode;
            // URL to redirect the sender's browser to after the sender has logged
            // into PayPal and approved a payment; it is always required but only
            // used if a payment requires explicit approval
            string returnURL = FWUtils.ConfigUtils.GetAppSettings().Paypal.GetReturnUrlByPaymentID(p.paymentId);

            // (Optional) The URL to which you want all IPN messages for this
            // payment to be sent. Maximum length: 1024 characters
            string ipnNotificationURL = FWUtils.ConfigUtils.GetAppSettings().Paypal.GetIpnNotificationUrl(p.paymentId); // MAX 1024


            string errorLanguage = p.errorLanguage;


            // The action for this request. Possible values are: PAY ï؟½ Use this
            // option if you are not using the Pay request in combination with
            // ExecutePayment. CREATE ï؟½ Use this option to set up the payment
            // instructions with SetPaymentOptions and then execute the payment at a
            // later time with the ExecutePayment. PAY_PRIMARY ï؟½ For chained
            // payments only, specify this value to delay payments to the secondary
            // receivers; only the payment to the primary receiver is processed.
            AdaptivePaymentActionSEnum action = AdaptivePaymentActionSEnum.PAY;


            System.Collections.Specialized.NameValueCollection parameters = new System.Collections.Specialized.NameValueCollection();

            ReceiverList receiverList = new ReceiverList();

            receiverList.receiver = new List <Receiver>();

            PayRequest      request         = new PayRequest();
            RequestEnvelope requestEnvelope = new RequestEnvelope(errorLanguage);

            request.requestEnvelope = requestEnvelope;

            AddReceiver(p.receiver1amount, p.receiver1email, receiverList);
            AddReceiver(p.receiver2amount, p.receiver2email, receiverList);

            ReceiverList receiverlst = new ReceiverList(receiverList.receiver);

            request.receiverList = receiverlst;

            request.senderEmail        = p.senderEmail;
            request.actionType         = action.getFnName();
            request.cancelUrl          = cancelUrl;
            request.currencyCode       = currencyCode;
            request.returnUrl          = returnURL;
            request.requestEnvelope    = requestEnvelope;
            request.ipnNotificationUrl = ipnNotificationURL;

            return(request);
        }