Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


These support forums are now closed for new topics and comments.
Please head on over to http://eureka.ucommerce.net/ for support.

  • Sheppe 43 posts 139 karma points
    Jan 27, 2013 @ 22:59
    Sheppe
    0

    Problem getting checkout pipeline to complete

    I've built an integrated payment service for Payflow Pro, and I've got the link between uCommerce and that working well. The problem is that now I'm having a problem getting the pipeline to add the order to the new orders section, clear the user's basket, and send them a confirmation email.

    My payment service is a synchronous, single transaction process. From what I've read about the checkout pipeline, that's relevant.

    Here's the relevant code from my payment service:

             public UCommerce.EntitiesV2.Payment ProcessPaymentRequest(PaymentRequest request)
            {
                try
                {
                    System.Configuration.AppSettingsReader reader = new AppSettingsReader();
                    string sAmt = request.Amount.ToString();
                    var amt = Regex.Split(sAmt, @"[^0-9\.]+").Where(c => c != "." && c.Trim() != "");
    
                    string PayPalRequest = "TRXTYPE=S" //S - sale transaction
                         + "&TENDER=C" //C - Credit card
                         + "&FIRSTNAME=" + request.AdditionalProperties["FIRST"]
                         + "&LASTNAME=" + request.AdditionalProperties["LAST"]
                         + "&ACCT=" + request.AdditionalProperties["CCNUM"] //card number
                         + "&EXPDATE=" + request.AdditionalProperties["EXP"]
                         //+ "&CVV2=" + request.AdditionalProperties["CCV"]   //card validation value (card security code)
                         + "&AMT=" + amt.FirstOrDefault().ToString()
                         + "&COMMENT1=Composter Sale"
                         + "&USER=" + reader.GetValue("USER", typeof(string)) //ConfigurationSettings.AppSettings["USER"]
                         + "&VENDOR=" + reader.GetValue("VENDOR", typeof(string)) //ConfigurationSettings.AppSettings["VENDOR"]
                         + "&PARTNER=" + reader.GetValue("PARTNER", typeof(string)) //ConfigurationSettings.AppSettings["PARTNER"]
                         + "&PWD=" + reader.GetValue("PWD", typeof(string)); //ConfigurationSettings.AppSettings["PWD"];
    
                    // Create an instance of PayflowNETAPI.
                    PayflowNETAPI PayflowNETAPI = new PayflowNETAPI();
    
                    // RequestId is a unique string that is required for each & every transaction. 
                    // The merchant can use her/his own algorithm to generate 
                    // this unique request id or use the SDK provided API to generate this
                    // as shown below (PayflowUtility.RequestId).
                    string PayPalResponse = PayflowNETAPI.SubmitTransaction(PayPalRequest, PayflowUtility.RequestId);
    
                    // Place the data from PayPal into a namevalue collection.
                    NameValueCollection RequestCollection = GetPayPalCollection(PayflowNETAPI.TransactionRequest);
                    NameValueCollection ResponseCollection = GetPayPalCollection(PayPalResponse);
    
                    // Check for transaction errors, if any.
                    string TransErrors = PayflowNETAPI.TransactionContext.ToString();
                    if (TransErrors != null && TransErrors.Length > 0)
                    {
                        throw new Exception("Error contacting Payflow Pro service. Error: " + TransErrors);
                    }
    
                    Payment p = new Payment
                    {
                        PaymentMethod = request.PaymentMethod,
                        PaymentStatus = PaymentStatus.Get((int)GetPayflowStatus(ResponseCollection["RESULT"])), // This throws an error in development, but should work in production.
                        Amount = request.Amount.Value,
                        TransactionId = ResponseCollection["PNREF"],
                        ReferenceId = ResponseCollection["PPREF"],
                        PurchaseOrder = request.PurchaseOrder,
                        Fee = 0,
                        FeePercentage = 0,
                        Created = DateTime.Now
                    };
                    if (p.PaymentStatus.Name != "Authorized")
                    {
                        PaymentProperty pp = new PaymentProperty();
                        pp.Key = "RESULT";
                        pp.Value = ResponseCollection["RESULT"];
                        p.PaymentProperties.Add(pp);
    
                        pp = new PaymentProperty();
                        pp.Key = "RESPMSG";
                        pp.Value = ResponseCollection["RESPMSG"];
                        p.PaymentProperties.Add(pp);
                    }
    
                    return p;
                }
                catch (Exception ex)
                {
                    Payment p = new Payment();
                    p.TransactionId = "-1";
                    p.PaymentStatus = new PaymentStatus();
                    p.PaymentStatus.Name = "[" + ex.Message + "]" + ex.StackTrace;
    
                    return p;
                }
            }
    
            public UCommerce.EntitiesV2.Payment RequestPayment(PaymentRequest request)
            {
                // The user has requested to process their payment, so return the result of the processpaymentrequest function.
                return ProcessPaymentRequest(request);
            }

    Here's the Razor code that I modified from the demo Razor store. There will be some unneccessary calls in here, from my efforts to make this go:

    @using UCommerce
    @using UCommerce.EntitiesV2
    @using UCommerce.Transactions.Payments
    @using UCommerce.Extensions
    @using UCommerce.Runtime
    @using umbraco.MacroEngines
    @using UCommerce.Api
    @using UCommerce.Pipelines
    @using UCommerce.Transactions
    
    @{
        var basket = SiteContext.Current.OrderContext.GetBasket();
        var po = basket.PurchaseOrder;
        var payment = po.Payments.FirstOrDefault();
    
        if (HttpContext.Current.Request.HttpMethod == "POST" && HttpContext.Current.Request.Form.AllKeys.Any(x => x == "update-payment"))
        {
            // Get the amount to request
            var amountToRequest = new Money(po.OrderTotal.Value, po.BillingCurrency); 
    
            // Get the payment method and set up a new payment request
            var paymentMethodName = HttpContext.Current.Request.Form["payment-method"];
    
            if (paymentMethodName != "")
            {
                var paymentMethod = PaymentMethod.SingleOrDefault(x => x.Name == paymentMethodName);
                var paymentRequest = new PaymentRequest(po, paymentMethod, amountToRequest);
    
                // Build additional properties to pass in the user's credit card information, if appropriate.
                if(paymentMethod.Name.ToLower() == "pay online")
                {
                    paymentRequest.AdditionalProperties.Add("FIRST", HttpContext.Current.Request.Form["first"]);
                    paymentRequest.AdditionalProperties.Add("LAST", HttpContext.Current.Request.Form["last"]);
                    paymentRequest.AdditionalProperties.Add("CCNUM", HttpContext.Current.Request.Form["ccnum"]);
                    paymentRequest.AdditionalProperties.Add("EXP", HttpContext.Current.Request.Form["month"] + HttpContext.Current.Request.Form["year"]);
                }
    
                // Get the service
                IPaymentMethodService paymentService = paymentMethod.GetPaymentMethodService();
    
                // Advance to the next stage of the basket pipeline.
                TransactionLibrary.ExecuteBasketPipeline();
    
                // Request payment with selected service
                Payment payResult = paymentService.RequestPayment(paymentRequest);
    
                // Check that it's OK
                var okPaymentStatus = PaymentStatus.Get((int)PaymentStatusCode.Authorized); 
                bool ok = payResult.PaymentStatus == okPaymentStatus;
    
                if(ok)
                {
                    try
                    {
                    <h1>Ok</h1>
    
                    // Add the payment to the purchase order.
                    payResult.PaymentStatus = PaymentStatus.Get((int) PaymentStatusCode.Acquired);
                    po.AddPayment(payResult);
    
                    // Advance to the next stage of the basket pipeline.
                    TransactionLibrary.ExecuteBasketPipeline();
    
                    // Execute the checkout stage of the order pipeline. This clears the basket and sends a confirmation email.
                    TransactionLibrary.Checkout();
    
                    // Advance to the next stage of the basket pipeline.
                    TransactionLibrary.ExecuteBasketPipeline();
    
                    //HttpContext.Current.Response.Redirect("Confirmation.aspx");
                    }
                    catch(Exception ex)
                    {
                        <p>@ex.Message</p>
                        <p>@ex.InnerException.ToString()</p>
                    }
                }
                else
                {
                    <h1>There was a problem processing your order.</h1>
    
                    /* For troubleshooting purposes
                    <p>@paymentCheck.TransactionId</p>
                    <p>@paymentCheck.PaymentStatus.Name</p>
    
                    foreach(PaymentProperty pp in paymentCheck.PaymentProperties)
                    {
                        <p>@pp.Key</p>
                        <p>@pp.Value</p>
                    }
                    */
                }
    
            }
    
        }
    }
    
    @helper RenderPaymentMethodLabel(PaymentMethod paymentMethod, PurchaseOrder po)
    {
        decimal feePercent = paymentMethod.FeePercent;
    
        var fee = paymentMethod.GetFeeForCurrency(po.BillingCurrency);
        var formattedFee = new Money((fee == null ? 0 : fee.Fee), po.BillingCurrency);
    
        @paymentMethod.Name <text>(</text>@formattedFee <text>+</text> @feePercent.ToString("0.00")<text>%)</text> 
    
    }
    
    
    <form  method="post">
        <div class="row-fluid well" >
            <div class="span6">
                <h3>Payment method</h3>
                <br/>
                @foreach (var paymentMethod in TransactionLibrary.GetPaymentMethods())
                {
                    <label class="radio">
                    <input type="radio" name="payment-method"  @(payment != null && payment.PaymentMethod.Equals(paymentMethod) ? "checked" : string.Empty) 
                    value="@paymentMethod.Name" />@RenderPaymentMethodLabel(paymentMethod, po)</label>
                }
            </div>
                <div>
                <p style="font-weight:bold">
                Credit Card Information (if paying online)
                </p>
                <table cellpadding="4" cellspacing="0" border="1">
                <tr>
                    <td>
                        Name:
                    </td>
                    <td>
                        First: <input type="text" name="first" style="width:100px;" /> Last: <input type="text" name="last" style="width:100px;" />
                    </td>
                </tr>
                <tr>
                    <td>
                        Credit Card Number:
                    </td>
                    <td>
                        <input type="text" name="ccnum" style="width:200px;" />
                    </td>
                </tr>
                <tr>
                    <td>
                        Expiry Date:
                    </td>
                    <td>
                        M:  <input type="text" name="month" style="width:100px;" /> Y:  <input type="text" name="year" style="width:100px;" />
                    </td>
                </tr>
            </table>
            </div>
    
        </div>
        <a href="/cart/shipping.aspx" class="btn btn-small">Back to Shipping Method</a>
        <button name="update-payment" class="pull-right btn btn-large btn-success" type="submit">Continue to Payment Page <i class="icon-arrow-right icon-white"></i></button>
    </form>

    Here's the modified Checkout.config. I just removed a couple of unneccessary steps:

    <configuration>
        <components>
            <!-- Pipeline Instance -->
            <component id="Checkout"
                       service="UCommerce.Pipelines.IPipeline`1[[UCommerce.EntitiesV2.PurchaseOrder, UCommerce]], UCommerce"
                       type="UCommerce.Pipelines.Checkout.CheckoutPipeline, UCommerce.Pipelines">
                <parameters>
                    <tasks>
                        <array>
                            <value>${Checkout.AssignOrderNumber}</value>
                            <value>${Checkout.CreateCustomer}</value>
                            <value>${Checkout.ConvertBasketToPurchaseOrder}</value>
                            <value>${Checkout.AddAuditTrailForCurrentOrderStatus}</value>
                            <value>${Checkout.ClearBasketInformation}</value>
                            <value>${Checkout.SavePurchaseOrder}</value>
                            <value>${Checkout.SendConfirmationEmail}</value>
                        </array>
                    </tasks>
                </parameters>
            </component>
    
            <!-- Pipeline Tasks-->
            <component id="Checkout.CreateCustomer"
                       service="UCommerce.Pipelines.IPipelineTask`1[[UCommerce.EntitiesV2.PurchaseOrder, UCommerce]], UCommerce"
                       type="UCommerce.Pipelines.Checkout.CreateCustomerTask, UCommerce.Pipelines" />
    
            <component id="Checkout.AssignOrderNumber"
                       service="UCommerce.Pipelines.IPipelineTask`1[[UCommerce.EntitiesV2.PurchaseOrder, UCommerce]], UCommerce"
                       type="UCommerce.Pipelines.Checkout.AssignOrderNumberTask, UCommerce.Pipelines" />
    
            <component id="Checkout.ConvertBasketToPurchaseOrder"
                       service="UCommerce.Pipelines.IPipelineTask`1[[UCommerce.EntitiesV2.PurchaseOrder, UCommerce]], UCommerce"
                       type="UCommerce.Pipelines.Checkout.ConvertBasketToPurchaseOrderTask, UCommerce.Pipelines" />
    
            <component id="Checkout.SavePurchaseOrder"
                       service="UCommerce.Pipelines.IPipelineTask`1[[UCommerce.EntitiesV2.PurchaseOrder, UCommerce]], UCommerce"
                       type="UCommerce.Pipelines.Common.SavePurchaseOrderTask, UCommerce.Pipelines" />
    
            <component id="Checkout.AddAuditTrailForCurrentOrderStatus"
                       service="UCommerce.Pipelines.IPipelineTask`1[[UCommerce.EntitiesV2.PurchaseOrder, UCommerce]], UCommerce"
                       type="UCommerce.Pipelines.Common.AddAuditTrailForCurrentOrderStatusTask, UCommerce.Pipelines" />
    
            <component id="Checkout.ClearBasketInformation"
                       service="UCommerce.Pipelines.IPipelineTask`1[[UCommerce.EntitiesV2.PurchaseOrder, UCommerce]], UCommerce"
                       type="UCommerce.Pipelines.Checkout.ClearBasketInformationTask, UCommerce.Pipelines" />
    
            <component id="Checkout.SendConfirmationEmail"
                       service="UCommerce.Pipelines.IPipelineTask`1[[UCommerce.EntitiesV2.PurchaseOrder, UCommerce]], UCommerce"
                       type="UCommerce.Pipelines.Common.SendEmailTask, UCommerce.Pipelines">
                <parameters>
                    <emailTypeName>OrderConfirmation</emailTypeName>
                </parameters>
            </component>
        </components>
    </configuration>

    When I call the Checkout method, I'm getting the following error message:

    Exception occoured while processing pipeline 'UCommerce.Pipelines.Basket.BasketPipeline'. See inner exception for details.

     

    System.InvalidOperationException: Nullable object must have a value. at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) at System.Nullable`1.get_Value() at UCommerce.Pipelines.Basket.CalculatePaymentTotalTask.Execute(PurchaseOrder purchaseOrder) at UCommerce.Pipelines.Pipeline`1.Execute(T subject)

    I'd love some help on this. I'm sure I'm just missing a simple step somewhere.

    Thanks,

    -Sheppe

  • Sheppe 43 posts 139 karma points
    Jan 29, 2013 @ 19:20
    Sheppe
    0

    Anyone?

  • Nickolaj Lundgreen 233 posts 1132 karma points
    Jan 29, 2013 @ 21:08
    Nickolaj Lundgreen
    0

    It's a longshot for sure, but I think its the FeeTotal on the payment that causes the null exception

  • Sheppe 43 posts 139 karma points
    Jan 29, 2013 @ 21:35
    Sheppe
    0

    Thanks Nickolaj. I'll be able to update the code and test that out in a few hours. I'll report back with the results.

    -Sheppe

  • Sheppe 43 posts 139 karma points
    Jan 30, 2013 @ 22:24
    Sheppe
    0

    That update got me passed the first error I reported, but unfortunately it lead right into the next. Here it is:

    Exception occoured while processing pipeline 'UCommerce.Pipelines.Basket.BasketPipeline'. See inner exception for details.

    NHibernate.PropertyValueException: not-null property references a null or transient value UCommerce.EntitiesV2.Payment.PaymentMethodName at NHibernate.Engine.Nullability.CheckNullability(Object[] values, IEntityPersister persister, Boolean isUpdate) at NHibernate.Event.Default.AbstractSaveEventListener.PerformSaveOrReplicate(Object entity, EntityKey key, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess) at NHibernate.Event.Default.AbstractSaveEventListener.PerformSave(Object entity, Object id, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess) at NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess) at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event) at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event) at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event) at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event) at NHibernate.Impl.SessionImpl.FireSaveOrUpdate(SaveOrUpdateEvent event) at NHibernate.Impl.SessionImpl.SaveOrUpdate(String entityName, Object obj) at NHibernate.Engine.CascadingAction.SaveUpdateCascadingAction.Cascade(IEventSource session, Object child, String entityName, Object anything, Boolean isCascadeDeleteEnabled) at NHibernate.Engine.Cascade.CascadeToOne(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) at NHibernate.Engine.Cascade.CascadeAssociation(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) at NHibernate.Engine.Cascade.CascadeProperty(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) at NHibernate.Engine.Cascade.CascadeCollectionElements(Object child, CollectionType collectionType, CascadeStyle style, IType elemType, Object anything, Boolean isCascadeDeleteEnabled) at NHibernate.Engine.Cascade.CascadeCollection(Object child, CascadeStyle style, Object anything, CollectionType type) at NHibernate.Engine.Cascade.CascadeAssociation(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) at NHibernate.Engine.Cascade.CascadeProperty(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything) at NHibernate.Event.Default.AbstractFlushingEventListener.CascadeOnFlush(IEventSource session, IEntityPersister persister, Object key, Object anything) at NHibernate.Event.Default.AbstractFlushingEventListener.PrepareEntityFlushes(IEventSource session) at NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent event) at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event) at NHibernate.Impl.SessionImpl.Flush() at UCommerce.EntitiesV2.Repository`1.Save(T entity) at UCommerce.EntitiesV2.PurchaseOrder.Save() at UCommerce.Pipelines.Common.SavePurchaseOrderTask.Execute(PurchaseOrder purchaseOrder) at UCommerce.Pipelines.Pipeline`1.Execute(T subject)

    I see that it's complaining about PaymentMethodName being null. I don't know if it's related, but I have included the Name property per the documentation at http://www.publicvoid.dk/IntegratingUCommerceWithAPaymentProvider.aspx. However, I have not initialized it with any value, as from what I understand, it is supposed to be populated at runtime (presumably by uCommerce's logic). Is it possible I have misconfigured something somewhere?

    Thanks,

    -Sheppe

  • Sheppe 43 posts 139 karma points
    Jan 31, 2013 @ 19:32
    Sheppe
    0

    I could still use some help on this, if anyone can lend a hand.

    Thanks,

    -Sheppe

  • Sheppe 43 posts 139 karma points
    Feb 02, 2013 @ 16:17
    Sheppe
    101

    The problem was in how I was retrieving the po.

     

    What I was doing (wrong):

     

            var basket =SiteContext.Current.OrderContext.GetBasket();
           
    var po = basket.PurchaseOrder;
           
    var payment = po.Payments.FirstOrDefault();

     

    What needs to be done: 

     

            var po = TransactionLibrary.GetBasket().PurchaseOrder; var payment = po.Payments.FirstOrDefault();

    -Sheppe

Please Sign in or register to post replies

Write your reply to:

Draft