예제 #1
0
        public async Task <ActionResult> Thanks()
        {
            #region ### Response Parameters ###

            /*
             *  terminalnumber=1000
             *  lowprofilecode=2467a885-1f97-40d5-8b5f-42222ce64c80
             *  Operation=2
             *  ResponseCode=0
             *  Status=0
             */
            #endregion

            var cardcomManager  = new CardcomManager(ConfigSingleton.Instance.CardcomTerminal, ConfigSingleton.Instance.CardcomUserName, TerminalNoCvv: ConfigSingleton.Instance.CardcomTerminalNoCvv);
            var detailsResponse = cardcomManager.GetTransactionDetails(Request.QueryString["lowprofilecode"]);

            // Collect custom details
            // returnValue: PRICE|PACKAGE|USER_ID|COUPON (e.g: 39.90|3|1|98F41F8F-6F6C-4A0A-A7D4-D719A41A6BD7)
            var returnValue       = detailsResponse.Details["ReturnValue"];
            var returnValueSlices = returnValue.Split('|');

            var model = new PurchaseThanks();
            model.PackageDetails      = PackagesSingleton.Instance.GetPackage(Convert.ToInt32(returnValueSlices[1]));
            model.SubscriptionDetails = (await new SubscriptionsBLL().Get(Convert.ToInt32(returnValueSlices[2])))?.Details;
            model.AmountPaid          = Convert.ToSingle(returnValueSlices[0]);
            return(View(model));
        }
예제 #2
0
        public async Task <string> ProcessCardcomTransaction()
        {
            #region ### IPN Parameters ###

            /*
             *  GET https://localhost:44373/Purchase/ProcessCardcomTransaction?terminalnumber=1000&lowprofilecode=2467a885-1f97-40d5-8b5f-42222ce64c80&Operation=2&DealRespone=0&DealResponse=0&TokenResponse=0&InvoiceResponseCode=0&OperationResponse=0&OperationResponseText=OK&ReturnValue=39.90%7c3%7c1%7c98F41F8F-6F6C-4A0A-A7D4-D719A41A6BD7
             *
             *  ---
             *
             *  terminalnumber=1000
             *  lowprofilecode=2467a885-1f97-40d5-8b5f-42222ce64c80
             *  Operation=2
             *  DealResponse=0
             *  TokenResponse=0
             *  InvoiceResponseCode=0
             *  OperationResponse=0
             *  OperationResponseText=OK
             *  ReturnValue=39.90|3|1|98F41F8F-6F6C-4A0A-A7D4-D719A41A6BD7
             */
            #endregion

            var step        = 0;
            var transaction = new Entities.Transaction();
            var httpResult  = "";

            var transactionsBLL = new TransactionsBLL();
            var ordersBLL       = new OrdersBLL();

            try
            {
                LoggerSingleton.Instance.Info("Cardcom", "Process-Transaction", new List <string> {
                    $"QueryString: {Request.QueryString}"
                });

                step = 1;

                var cardcomManager = new CardcomManager(ConfigSingleton.Instance.CardcomTerminal, ConfigSingleton.Instance.CardcomUserName);

                step = 2;

                // Collect basic details
                transaction.Raw            = Request.QueryString?.ToString();
                transaction.Code           = Request.QueryString["lowprofilecode"];
                transaction.StatusCode     = Convert.ToInt32(Request.QueryString["OperationResponse"]);
                transaction.StatusCodeCard = Convert.ToInt32(Request.QueryString["DealResponse"]);

                step = 3;

                if (transaction.StatusCode != 0)
                {
                    throw new Exception($"[StatusCode Error] StatusCode {transaction.StatusCode} ({transaction.Code})");
                }

                step = 4;

                // Collect extra details
                var detailsResponse = cardcomManager.GetTransactionDetails(transaction.Code);
                transaction.StatusCodeDetails = Convert.ToInt32(detailsResponse.Details["ResponseCode"]);
                transaction.RawDetails        = detailsResponse.Raw;

                step = 5;

                // add invoice details
                transaction.InvoiceStatusCode = Convert.ToInt32(detailsResponse.Details["InvoiceResponseCode"]);
                transaction.InvoiceNumber     = detailsResponse.Details["InvoiceNumber"] ?? "";
                transaction.InvoiceType       = Convert.ToInt32(detailsResponse.Details["InvoiceType"] ?? "0");

                step = 6;

                if (transaction.StatusCodeDetails != 0)
                {
                    throw new Exception($"[StatusCode Error] StatusCodeDetails {transaction.StatusCodeDetails} ({transaction.Code})");
                }

                step = 7;

                transaction.CardOwnerId = detailsResponse.Details["CardOwnerID"] ?? "";

                // fix format > MM (e.g: 7 to 07)
                var CardValidityMonth = detailsResponse.Details["CardValidityMonth"] ?? "";
                if (CardValidityMonth.Length == 1)
                {
                    CardValidityMonth = $"0{CardValidityMonth}";
                }

                transaction.CardExpiry    = $"{detailsResponse.Details["CardValidityYear"] ?? ""}{CardValidityMonth}";
                transaction.CardSuffix    = detailsResponse.Details["ExtShvaParams.CardNumber5"] ?? "";
                transaction.NumOfPayments = Convert.ToInt32(detailsResponse.Details["NumOfPayments"] ?? "1");

                step = 8;

                // load ReturnValue field > extract order-id
                var returnValue = detailsResponse.Details["ReturnValue"].Trim();
                var orderId     = Convert.ToInt32(returnValue);

                step = 9;

                // load related order
                var order = await ordersBLL.Get(orderId);

                step = 10;

                // Collect custom details
                transaction.Price   = order.Total;
                transaction.OrderId = order.Details.Id;

                step = 11;

                // update Order Status
                order.Details.Status = Entities.eOrderStatus.APPROVED;
                order.Details.IsPaid = true;
                var orderUpdated = await ordersBLL.SaveDetails(order.Details) > 0;

                if (!orderUpdated)
                {
                    LoggerSingleton.Instance.Info("Cardcom", "Save Order Details Failed", new List <string> {
                        $"#{orderId}", "Status: APPROVED", $"Code: {transaction.Code}"
                    });
                }

                step = 12;

                // send sms
                if (orderUpdated)
                {
                    SMSManager.OrderStatusChanged(order);
                }

                step = 13;

                httpResult = "OK";
            }
            catch (Exception ex)
            {
                ex.Data.Add("step", step);
                ex.Data.Add("Method", "ProcessCardcomTransaction");
                LoggerSingleton.Instance.Error("Cardcom", ex);
                httpResult = ex.Message;
            }

            try {
                // add a transaction
                var transactionId = await transactionsBLL.Create(transaction);

                if (transactionId <= 0)
                {
                    throw new Exception($"Error while trying to save an incoming transaction ({transaction.Code})");
                }
            }
            catch (Exception ex)
            {
                ex.Data.Add("Action", "CreateTransaction");
                ex.Data.Add("Method", "ProcessCardcomTransaction");
                LoggerSingleton.Instance.Error("Cardcom", ex);
                httpResult = ex.Message;
            }

            Response.StatusCode = httpResult == "OK" ? (int)HttpStatusCode.OK : (int)HttpStatusCode.InternalServerError;
            return(httpResult);
        }
예제 #3
0
        public async Task <HttpStatusCodeResult> ProcessCardcomTransaction()
        {
            #region ### IPN Parameters ###

            /*
             *  GET https://localhost:44373/Purchase/ProcessCardcomTransaction?terminalnumber=1000&lowprofilecode=2467a885-1f97-40d5-8b5f-42222ce64c80&Operation=2&DealRespone=0&DealResponse=0&TokenResponse=0&InvoiceResponseCode=0&OperationResponse=0&OperationResponseText=OK&ReturnValue=39.90%7c3%7c1%7c98F41F8F-6F6C-4A0A-A7D4-D719A41A6BD7
             *
             *  ---
             *
             *  terminalnumber=1000
             *  lowprofilecode=2467a885-1f97-40d5-8b5f-42222ce64c80
             *  Operation=2
             *  DealResponse=0
             *  TokenResponse=0
             *  InvoiceResponseCode=0
             *  OperationResponse=0
             *  OperationResponseText=OK
             *  ReturnValue=39.90|3|1|98F41F8F-6F6C-4A0A-A7D4-D719A41A6BD7
             */
            #endregion

            var step = 0;
            try
            {
                LoggerSingleton.Instance.Info("Cardcom", "Process-Transaction", new List <string> {
                    $"QueryString: {Request.QueryString}"
                });

                var transactionsBLL  = new TransactionsBLL();
                var couponsBLL       = new CouponsBLL();
                var subscriptionsBLL = new SubscriptionsBLL();

                var cardcomManager = new CardcomManager(ConfigSingleton.Instance.CardcomTerminal, ConfigSingleton.Instance.CardcomUserName, TerminalNoCvv: ConfigSingleton.Instance.CardcomTerminalNoCvv);
                step = 1;

                // Collect basic details
                var transaction = new Transaction();
                transaction.Raw            = Request.QueryString?.ToString();
                transaction.Code           = Request.QueryString["lowprofilecode"];
                transaction.StatusCode     = Convert.ToInt32(Request.QueryString["OperationResponse"]);
                transaction.CardStatusCode = Convert.ToInt32(Request.QueryString["DealResponse"]);
                step = 2;

                // Collect extra details
                var detailsResponse = cardcomManager.GetTransactionDetails(transaction.Code);
                step = 3;

                if (Convert.ToInt32(detailsResponse.Details["ResponseCode"]) != 0)
                {
                    throw new Exception($"Error while trying to get details. status-code {detailsResponse.Details["ResponseCode"]} ({transaction.Code})");
                }

                step = 4;

                transaction.RawDetails          = detailsResponse.Raw;
                transaction.Token               = detailsResponse.Details["Token"] ?? "";
                transaction.TokenExpiry         = detailsResponse.Details["TokenExDate"] ?? "";
                transaction.TokenApprovalNumber = detailsResponse.Details["TokenApprovalNumber"] ?? "";
                transaction.CardOwnerId         = detailsResponse.Details["CardOwnerID"] ?? "";

                // fix format > MM (e.g: 7 to 07)
                var CardValidityMonth = detailsResponse.Details["CardValidityMonth"] ?? "";
                if (CardValidityMonth.Length == 1)
                {
                    CardValidityMonth = $"0{CardValidityMonth}";
                }

                transaction.CardExpiry        = $"{detailsResponse.Details["CardValidityYear"] ?? ""}{CardValidityMonth}";
                transaction.CardSuffix        = detailsResponse.Details["ExtShvaParams.CardNumber5"] ?? "";
                transaction.InvoiceStatusCode = Convert.ToInt32(detailsResponse.Details["InvoiceResponseCode"]);
                transaction.InvoiceNumber     = detailsResponse.Details["InvoiceNumber"] ?? "";
                transaction.InvoiceType       = Convert.ToInt32(detailsResponse.Details["InvoiceType"] ?? "0");
                transaction.NumOfPayments     = Convert.ToInt32(detailsResponse.Details["NumOfPayments"] ?? "1");
                step = 5;

                // Collect custom details
                // returnValue: PRICE|PACKAGE|USER_ID|COUPON (e.g: 39.90|3|1|98F41F8F-6F6C-4A0A-A7D4-D719A41A6BD7)
                var returnValue       = detailsResponse.Details["ReturnValue"].Trim();
                var returnValueSlices = returnValue.Split('|');
                transaction.Price          = Convert.ToSingle(returnValueSlices[0]);
                transaction.PackageId      = Convert.ToInt32(returnValueSlices[1]);
                transaction.SubscriptionId = Convert.ToInt32(returnValueSlices[2]);

                var coupon = await couponsBLL.Find(returnValueSlices[3]);

                transaction.Coupon = coupon == null ? "" : coupon.Code.ToString();
                step = 6;

                // Create Transaction Row
                var transactionId = await transactionsBLL.Save(transaction);

                if (transactionId <= 0)
                {
                    throw new Exception($"Error while trying to save an incoming transaction ({transaction.Code})");
                }
                transaction.RowId = transactionId;
                step = 7;

                if (transaction.StatusCode != 0)
                {
                    var success1 = await subscriptionsBLL.SaveRegistrationStep(transaction.SubscriptionId, "TransactionFailed");

                    if (!success1)
                    {
                        LoggerSingleton.Instance.Info("Cardcom", $"SaveRegistrationStep Failed For User #{transaction.SubscriptionId}");
                    }

                    throw new Exception($"transaction code error. status-code {transaction.StatusCode} ({transaction.Code})");
                }

                step = 8;

                // Update Coupon Capacity
                if (!string.IsNullOrEmpty(transaction.Coupon))
                {
                    var successCapacity = await couponsBLL.IncreaseCapacityInUse(Guid.Parse(transaction.Coupon));

                    if (!successCapacity)
                    {
                        LoggerSingleton.Instance.Info("Cardcom", "IncreaseCapacity Failed", new List <string> {
                            $"#{transaction.SubscriptionId}",
                            transaction.Coupon
                        });
                    }
                }
                step = 9;

                var packageDetails = PackagesSingleton.Instance.GetPackage(transaction.PackageId);
                step = 10;

                // calculate the valid-until, the Recurring Payments Start Date and the corresponding interval id
                DateTime?validUntil     = packageDetails.ValidUntil;
                var      timeIntervalId = packageDetails.CardcomIntervalId;
                step = 11;

                // update ValidUntil
                var successValidUntil = await subscriptionsBLL.SaveValidUntil(transaction.SubscriptionId, validUntil);

                if (!successValidUntil)
                {
                    LoggerSingleton.Instance.Info("Cardcom", "SaveValidUntil Failed", new List <string> {
                        $"#{transaction.SubscriptionId}",
                    });
                }
                step = 12;

                var chargeDetails = new Entities.ChargeDetails
                {
                    SubscriptionId = transaction.SubscriptionId,
                    Token          = transaction.Token,
                    IsAutoRenewal  = true,
                    CardSuffix     = transaction.CardSuffix,
                    CardExpiry     = transaction.CardExpiry,
                    CardOwnerId    = transaction.CardOwnerId,
                    Code           = transaction.Code
                };

                // save charge details for this subscription
                var successChargeDetails = await subscriptionsBLL.SaveChargeDetails(chargeDetails);

                if (!successChargeDetails)
                {
                    LoggerSingleton.Instance.Info("Cardcom", "SaveChargeDetails Failed", new List <string> {
                        $"#{chargeDetails.SubscriptionId}",
                        chargeDetails.Token
                    });
                }
                step = 13;

                // load subscription
                var subscription = await subscriptionsBLL.Get(transaction.SubscriptionId);

                step = 14;

                var responseCharge = cardcomManager.SetRecurringCharge(
                    chargeDetails.Code,
                    "My Morning Love",
                    validUntil.Value,
                    timeIntervalId,
                    new List <CardcomIFrameSourceItem> {
                    new CardcomIFrameSourceItem {
                        Description = packageDetails.Name,
                        Price       = packageDetails.Price,
                        Quantity    = 1
                    }
                },
                    returnValue,
                    new CardcomInvoiceDetails
                {
                    CustomerId   = subscription.Details.Id.ToString(),
                    CustomerName = subscription.Details.FullName,
                    Email        = subscription.Details.Email,
                    SendEmail    = true
                }
                    );
                step = 15;
                if (responseCharge.Details["ResponseCode"] != "0")
                {
                    LoggerSingleton.Instance.Info("Cardcom", $"SetRecurringCharge Failed With Code {responseCharge.Details["ResponseCode"]}");

                    await subscriptionsBLL.SaveAutoRenewal(transaction.SubscriptionId, false); // recurring charge has failed > mark user as AutoRenewal false
                }
                step = 16;

                chargeDetails.RecurringId = Convert.ToInt32(responseCharge.Details["Recurring0.RecurringId"]);
                successChargeDetails      = await subscriptionsBLL.SaveChargeDetails(chargeDetails);

                if (!successChargeDetails)
                {
                    LoggerSingleton.Instance.Info("Cardcom", "SaveChargeDetails (with RecurringId) Failed", new List <string> {
                        $"#{chargeDetails.SubscriptionId}",
                        chargeDetails.Token,
                        responseCharge.Details["Recurring0.RecurringId"]
                    });
                }
                step = 17;

                var success2 = await subscriptionsBLL.SaveRegistrationStep(subscription.Details.Id, "Completed");

                if (!success2)
                {
                    LoggerSingleton.Instance.Info("Cardcom", $"SaveRegistrationStep Failed For User #{subscription.Details.Id}");
                }

                return(new HttpStatusCodeResult(HttpStatusCode.OK, "OK"));
            }
            catch (Exception ex) {
                ex.Data.Add("step", step);
                ex.Data.Add("Method", "ProcessCardcomTransaction");
                LoggerSingleton.Instance.Error("Cardcom", ex);
                return(new HttpStatusCodeResult(HttpStatusCode.InternalServerError, ex.Message));
            }
        }
예제 #4
0
        public async Task <string> ProcessCardcomTransaction()
        {
            #region ### IPN Parameters ###

            /*
             *  GET https://localhost:44373/Purchase/ProcessCardcomTransaction?terminalnumber=1000&lowprofilecode=2467a885-1f97-40d5-8b5f-42222ce64c80&Operation=2&DealRespone=0&DealResponse=0&TokenResponse=0&InvoiceResponseCode=0&OperationResponse=0&OperationResponseText=OK&ReturnValue=39.90%7c3%7c1%7c98F41F8F-6F6C-4A0A-A7D4-D719A41A6BD7
             *
             *  ---
             *
             *  terminalnumber=1000
             *  lowprofilecode=2467a885-1f97-40d5-8b5f-42222ce64c80
             *  Operation=2
             *  DealResponse=0
             *  TokenResponse=0
             *  InvoiceResponseCode=0
             *  OperationResponse=0
             *  OperationResponseText=OK
             *  ReturnValue=39.90|3|1|98F41F8F-6F6C-4A0A-A7D4-D719A41A6BD7
             */
            #endregion

            var step = 0;
            var isTransactionFailed = false;
            var transaction         = new Transaction();
            var httpResult          = "";

            var transactionsBLL  = new TransactionsBLL();
            var couponsBLL       = new CouponsBLL();
            var subscriptionsBLL = new SubscriptionsBLL();

            // [step-1: process request]
            try
            {
                LoggerSingleton.Instance.Info("Cardcom", "Process-Transaction", new List <string> {
                    $"QueryString: {Request.QueryString}"
                });

                // defaults
                transaction.StatusCode                = 9999;
                transaction.StatusCodeDetails         = 9999;
                transaction.StatusCodeChargeToken     = 9999;
                transaction.StatusCodeRecurringCharge = 9999;
                transaction.InvoiceNumber             = "";

                var cardcomManager = new CardcomManager(ConfigSingleton.Instance.CardcomTerminal, ConfigSingleton.Instance.CardcomUserName, TerminalNoCvv: ConfigSingleton.Instance.CardcomTerminalNoCvv);

                step = 1;

                // Collect basic details
                transaction.Raw            = Request.QueryString?.ToString();
                transaction.Code           = Request.QueryString["lowprofilecode"];
                transaction.StatusCode     = Convert.ToInt32(Request.QueryString["OperationResponse"]);
                transaction.CardStatusCode = Convert.ToInt32(Request.QueryString["DealResponse"]);

                step = 2;

                // Collect extra details
                var detailsResponse = cardcomManager.GetTransactionDetails(transaction.Code);

                step = 3;

                transaction.StatusCodeDetails = Convert.ToInt32(detailsResponse.Details["ResponseCode"]);
                transaction.RawDetails        = detailsResponse.Raw;

                if (Convert.ToInt32(detailsResponse.Details["ResponseCode"]) != 0)
                {
                    throw new Exception($"Error while trying to get details. status-code {detailsResponse.Details["ResponseCode"]} ({transaction.Code})");
                }

                step = 4;

                transaction.Token               = detailsResponse.Details["Token"] ?? "";
                transaction.TokenExpiry         = detailsResponse.Details["TokenExDate"] ?? "";
                transaction.TokenApprovalNumber = detailsResponse.Details["TokenApprovalNumber"] ?? "";
                transaction.CardOwnerId         = detailsResponse.Details["CardOwnerID"] ?? "";

                // fix format > MM (e.g: 7 to 07)
                var CardValidityMonth = detailsResponse.Details["CardValidityMonth"] ?? "";
                if (CardValidityMonth.Length == 1)
                {
                    CardValidityMonth = $"0{CardValidityMonth}";
                }

                transaction.CardExpiry    = $"{detailsResponse.Details["CardValidityYear"] ?? ""}{CardValidityMonth}";
                transaction.CardSuffix    = detailsResponse.Details["ExtShvaParams.CardNumber5"] ?? "";
                transaction.NumOfPayments = Convert.ToInt32(detailsResponse.Details["NumOfPayments"] ?? "1");
                step = 5;

                // Collect custom details
                // returnValue: PRICE|PACKAGE|USER_ID|COUPON (e.g: 39.90|3|1|98F41F8F-6F6C-4A0A-A7D4-D719A41A6BD7)
                var returnValue       = detailsResponse.Details["ReturnValue"].Trim();
                var returnValueSlices = returnValue.Split('|');
                transaction.Price          = Convert.ToSingle(returnValueSlices[0]);
                transaction.PackageId      = Convert.ToInt32(returnValueSlices[1]);
                transaction.SubscriptionId = Convert.ToInt32(returnValueSlices[2]);

                var coupon = await couponsBLL.Find(returnValueSlices[3]);

                transaction.Coupon = coupon == null ? "" : coupon.Code.ToString();
                step = 6;

                // load package
                var packageDetails = PackagesSingleton.Instance.GetPackage(transaction.PackageId);

                step = 7;

                // load subscription
                var subscription = await subscriptionsBLL.Get(transaction.SubscriptionId);

                step = 8;

                /*
                 *  we have two states to handle:
                 *  1. free week -> no charge + recurring-charge with a 1 week delay
                 *  2. coupon -> immediate charge + recurring-charge with a week/month delay (depending on the acquired package)
                 */
                var isFreeWeek = coupon == null;
                /// isFreeWeek = false; // disabled

                if (isFreeWeek)
                {
                    transaction.Price = 0;
                }
                else
                {
                    // actual charge using generated TOKEN
                    var responseCharge = cardcomManager.ChargeWithToken(
                        transaction.Token,
                        transaction.CardExpiry,
                        transaction.CardOwnerId,
                        new List <CardcomIFrameSourceItem> {
                        new CardcomIFrameSourceItem {
                            Description = $"#{packageDetails.Id} {packageDetails.Name}",
                            Price       = transaction.Price,
                            Quantity    = 1
                        }
                    },
                        returnValue,
                        transaction.NumOfPayments,
                        InvoiceDetails: new CardcomInvoiceDetails
                    {
                        CustomerId   = subscription.Details.Id.ToString(),
                        CustomerName = subscription.Details.FirstName,
                        Email        = subscription.Details.Email,
                        SendEmail    = true
                    }
                        );

                    step = 9;

                    transaction.StatusCodeChargeToken = Convert.ToInt32(responseCharge.Details["ResponseCode"]);
                    transaction.RawChargeToken        = responseCharge.Raw;

                    if (Convert.ToInt32(responseCharge.Details["ResponseCode"]) != 0)
                    {
                        throw new Exception($"Error while trying to charge with token {transaction.Token}. status-code {responseCharge.Details["ResponseCode"]} ({transaction.Code})");
                    }

                    step = 10;

                    transaction.CardStatusCode = 0;  // update the card status code

                    // add invoice details
                    transaction.InvoiceStatusCode = Convert.ToInt32(responseCharge.Details["InvoiceResponse.ResponseCode"]);
                    transaction.InvoiceNumber     = responseCharge.Details["InvoiceResponse.InvoiceNumber"] ?? "";
                    transaction.InvoiceType       = Convert.ToInt32(responseCharge.Details["InvoiceResponse.InvoiceType"] ?? "0");
                }

                step = 11;

                if (transaction.StatusCode != 0)
                {
                    var success1 = await subscriptionsBLL.SaveRegistrationStep(transaction.SubscriptionId, "TransactionFailed");

                    if (!success1)
                    {
                        LoggerSingleton.Instance.Info("Cardcom", $"SaveRegistrationStep Failed For User #{transaction.SubscriptionId}");
                    }

                    throw new Exception($"transaction code error. status-code {transaction.StatusCode} ({transaction.Code})");
                }

                step = 12;

                // Update Coupon Capacity
                if (!string.IsNullOrEmpty(transaction.Coupon))
                {
                    var successCapacity = await couponsBLL.IncreaseCapacityInUse(Guid.Parse(transaction.Coupon));

                    if (!successCapacity)
                    {
                        LoggerSingleton.Instance.Info("Cardcom", "IncreaseCapacity Failed", new List <string> {
                            $"#{transaction.SubscriptionId}",
                            transaction.Coupon
                        });
                    }
                }
                step = 13;

                // calculate the valid-until, the Recurring Payments Start Date and the corresponding interval id
                DateTime?validUntil     = packageDetails.ValidUntil;
                var      timeIntervalId = packageDetails.CardcomIntervalId;

                step = 14;

                if (isFreeWeek)
                {
                    validUntil = DateTime.Now.AddDays(7);
                }

                step = 15;

                // update ValidUntil
                var successValidUntil = await subscriptionsBLL.SaveValidUntil(transaction.SubscriptionId, validUntil);

                if (!successValidUntil)
                {
                    LoggerSingleton.Instance.Info("Cardcom", "SaveValidUntil Failed", new List <string> {
                        $"#{transaction.SubscriptionId}",
                    });
                }
                step = 16;

                var chargeDetails = new Entities.ChargeDetails
                {
                    SubscriptionId = transaction.SubscriptionId,
                    Token          = transaction.Token,
                    IsAutoRenewal  = packageDetails.IsReccuringPayment,
                    CardSuffix     = transaction.CardSuffix,
                    CardExpiry     = transaction.CardExpiry,
                    CardOwnerId    = transaction.CardOwnerId,
                    Code           = transaction.Code
                };

                // save charge details for this subscription
                var successChargeDetails = await subscriptionsBLL.SaveChargeDetails(chargeDetails);

                if (!successChargeDetails)
                {
                    LoggerSingleton.Instance.Info("Cardcom", "SaveChargeDetails Failed", new List <string> {
                        $"#{chargeDetails.SubscriptionId}",
                        chargeDetails.Token
                    });
                }
                step = 17;

                // add a transaction
                var transactionId = await transactionsBLL.Save(transaction);

                if (transactionId <= 0)
                {
                    throw new Exception($"Error while trying to save an incoming transaction ({transaction.Code})");
                }
                transaction.RowId = transactionId;

                step = 18;

                // set recurring-charge
                if (packageDetails.IsReccuringPayment)
                {
                    step = 19;

                    var responseRecurringCharge = cardcomManager.SetRecurringCharge(
                        chargeDetails.Code,
                        "My Morning Love",
                        validUntil.Value,
                        timeIntervalId,
                        new List <CardcomIFrameSourceItem> {
                        new CardcomIFrameSourceItem {
                            Description = packageDetails.Name,
                            Price       = packageDetails.Price,
                            Quantity    = 1
                        }
                    },
                        returnValue,
                        new CardcomInvoiceDetails
                    {
                        CustomerId   = subscription.Details.Id.ToString(),
                        CustomerName = subscription.Details.FullName,
                        Email        = subscription.Details.Email,
                        SendEmail    = true
                    }
                        );


                    step = 20;

                    transaction.StatusCodeRecurringCharge = Convert.ToInt32(responseRecurringCharge.Details["ResponseCode"]);
                    transaction.RawRecurringCharge        = responseRecurringCharge.Raw;

                    if (responseRecurringCharge.Details["ResponseCode"] != "0")
                    {
                        await subscriptionsBLL.SaveAutoRenewal(transaction.SubscriptionId, false); // recurring charge has failed > mark user as AutoRenewal false

                        throw new Exception($"Error while trying to set Recurring Charge. status-code {responseRecurringCharge.Details["ResponseCode"]} ({transaction.Code})");
                    }
                    step = 20;

                    chargeDetails.RecurringId = Convert.ToInt32(responseRecurringCharge.Details["Recurring0.RecurringId"]);
                    successChargeDetails      = await subscriptionsBLL.SaveChargeDetails(chargeDetails);

                    if (!successChargeDetails)
                    {
                        LoggerSingleton.Instance.Info("Cardcom", "SaveChargeDetails (with RecurringId) Failed", new List <string> {
                            $"#{chargeDetails.SubscriptionId}",
                            chargeDetails.Token,
                            responseRecurringCharge.Details["Recurring0.RecurringId"]
                        });
                    }
                }

                step = 21;

                httpResult = "OK";
            }
            catch (Exception ex)
            {
                isTransactionFailed = true;
                ex.Data.Add("step", step);
                ex.Data.Add("Method", "ProcessCardcomTransaction");
                LoggerSingleton.Instance.Error("Cardcom", ex);
                httpResult = ex.Message;
            }

            step = 22;

            // [step-2: update transaction]
            try
            {
                // Create Transaction Row
                var transactionId = await transactionsBLL.Save(transaction);

                if (transactionId <= 0)
                {
                    throw new Exception($"Error while trying to save an incoming transaction ({transaction.Code})");
                }
                transaction.RowId = transactionId;
            }
            catch (Exception ex)
            {
                isTransactionFailed = true;
                ex.Data.Add("step", step);
                ex.Data.Add("Method", "ProcessCardcomTransaction");
                LoggerSingleton.Instance.Error("Cardcom", ex);
                httpResult = ex.Message;
            }

            step = 23;

            // [step-3: mark registration state]
            try
            {
                var success = await subscriptionsBLL.SaveRegistrationStep(transaction.SubscriptionId, isTransactionFailed? "TransactionFailed" : "Completed");

                if (!success)
                {
                    LoggerSingleton.Instance.Info("Cardcom", $"SaveRegistrationStep Failed For User #{transaction.SubscriptionId}");
                }
            }
            catch (Exception ex)
            {
                ex.Data.Add("step", step);
                ex.Data.Add("Method", "ProcessCardcomTransaction");
                LoggerSingleton.Instance.Error("Cardcom", ex);
                httpResult = ex.Message;
            }

            Response.StatusCode = httpResult == "OK" ? (int)HttpStatusCode.OK : (int)HttpStatusCode.InternalServerError;
            return(httpResult);

            ///return new HttpStatusCodeResult(HttpStatusCode.OK, "OK");
            /// return httpStatusCodeResult;
        }