function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
bvramkumarbvramkumar 

Using Payment Connect

Hello,

 

Has anybody worked on sites pages that uses Linvio PaymentConnect without redirecting to it's SitesCheckout page.

 

Thanks,

Vishnu

Best Answer chosen by Admin (Salesforce Developers) 
bvramkumarbvramkumar

There is no direct API of Linvio PaymentConnect yet to achieve this. The only one now is to fill the contact object with required details and associate it with payment object and then redirect to sitecheckout page. sitecheckout page is for One-Time payments. and for recurring payments you have to use sitesubscribeARB.

All Answers

sfdcfoxsfdcfox

I am working on that very subject as we speak. Not successful yet, but I should be able to provide some insight over the next few days.

bvramkumarbvramkumar

There is no direct API of Linvio PaymentConnect yet to achieve this. The only one now is to fill the contact object with required details and associate it with payment object and then redirect to sitecheckout page. sitecheckout page is for One-Time payments. and for recurring payments you have to use sitesubscribeARB.

This was selected as the best answer
sfdcfoxsfdcfox

More specifically, it actually is possible (I did achieve a level of success with this mechanism), but because of platform limitations, it's burdensome. You must two a two-step screen in order to successfully do this. Here's some snippets of data (this is a PayPal version):

 

 

// Step 1. We use Person Accounts in this example.
// Input: a bunch of parameters regarding contact information.
// Output: records ready to be processed by payment connect.
    Id recordTypeId = [select id from recordtype where ispersontype = true limit 1].Id;
    account a = new account(persontitle=title,firstname=firstname,lastname=lastname,
                personemail=email,personhasoptedoutofemail=(emailoptout=='1'||emailoptout=='true'),
                billingstreet=street,personmailingstreet=street,
                billingcity=city,personmailingcity=city,
                billingstate=state,personmailingstate=state,
                billingpostalcode=postalcode,personmailingpostalcode=postalcode,
                billingcountry=country,personmailingcountry=country,
                recordtypeid=recordtypeid);
    insert a;
Opportunity o = new opportunity(name='Web Payment',accountid=a.id,closedate=system.today(),stagename='Not Received',amount=amount);
    insert o;
                pymt__Processor_Connection__c pc = [select id from pymt__Processor_Connection__c  where RecordType.Name = 'PayPal' limit 1]; // Change this query.
pymt__PaymentX__c p = new pymt__PaymentX__c(pymt__contact__c=a.personcontactid,pymt__opportunity__c=o.id,name='Web Payment',pymt__processor_connection__c=pc.id);
    insert p;
    // (Store a.id, o.id, and p.id in controller, or even the entire object. Need this for step 2.)

// Step 2: On confirmation of details, like Site Checkout does, execute this code.
// Inputs: a bunch of credit card details, plus account, opportunity, and payment records.
// Output: none. Success is determined by a field, but since it is a asynchronous
//     request, we have to follow up later.
// IPAddress comes from "ipaddress = apexpages.currentpage().getheaders().get('X-Salesforce-SIP');"

            pymt.PayPalAPI.CustomerInfo cinfo = new pymt.PayPalAPI.customerinfo();
            pymt.PayPalAPI.shippinginfo sinfo = new pymt.PayPalAPI.shippinginfo();
            cinfo.firstname=a.firstname;
            cinfo.lastname=a.lastname;
            cinfo.email=a.personemail;
            cinfo.customerIP=ipaddress;
            sinfo.address=a.billingstreet;
            sinfo.city=a.billingcity;
            sinfo.state=a.billingstate;
            sinfo.postalcode=a.billingpostalcode;
            sinfo.country=a.billingcountry;
 pymt.PaymentX.TransactionResultExt result = pymt.PayPalConnector.chargeCreditCard('Payment Description',o.Amount,p.id,null,cinfo,sinfo,cardnumber,cardtype,expmonth+expyear,cvv,null,null,null,null,null,false);
        // result.pxSuccess == true means no problems with the attempt. Does not guarantee card is charged, only that paypal received the request.

This is their "Level 3" integration, and a total pain in the rear. The Recurring payments feature is even more burdensome, as you have to replace Step 2 with something like this:

 

 

 

// Inputs: Account, Opportunity, Payment, as before, plus credit card info.
// Output: Processed payment, as before.

map<string,string> paramMap = new map<string,string>();
      paramMap.put('METHOD','CreateRecurringPaymentsProfile');
      paramMap.put('SUBSCRIBERNAME',a.FirstName+' '+a.LastName);
      paramMap.put('PROFILESTARTDATE',string.valueof( datetime.newinstance( system.today().year(),system.today().month(),system.today().day())).replace(' ','T')+'.00Z');
      paramMap.put('DESC','Web Subscription');
      paramMap.put('BILLINGPERIOD',Period=='Year'?'Year':'Month');
      paramMap.put('BILLINGFREQUENCY',Period=='Quarter'?'3':'1');
      paramMap.put('AMT',String.valueOf(o.Amount.setScale(2)));
      paramMap.put('CURRENCYCODE','USD');
      paramMap.put('CREDITCARDTYPE',CardType);
      paramMap.put('ACCT',CardNumber);
      paramMap.put('EXPDATE',ExpMonth+ExpYear);
      paramMap.put('CVV2',CVV);
      paramMap.put('FIRSTNAME',a.FirstName);
      paramMap.put('LASTNAME',a.LastName);
      paramMap.put('STREET',a.BillingStreet);
      paramMap.put('CITY',a.BillingCity);
      paramMap.put('STATE',a.BillingState);
      paramMap.put('ZIP',a.BillingPostalCode);
      paramMap.put('COUNTRYCODE',a.BillingCountry);
      paramMap.put('CUSTOM','sfaccountid='+a.id+'&sfcontactid='+a.personcontactid+'&sfopportunityid='+o.id);
      string paramList = createNVP(paramMap);
      pymt.PayPalConnector.CreateRecurringPaymentsProfileResult result = pymt.PayPalConnector.createRecurringPaymentsProfile(pc.id, paramList);
        // result.resultCode=='Success' means all is well in the world.

createNVP is just a function that puts all the parameters into a NVP string as you'd do for PayPal directly.

 

 

Note that you don't need to store CVV, CreditCardNumber, ExpDate, or any other details anywhere in your system. Once handed to PayPal, you'll receive notifications through their Payment Relay of updates to your opportunities/payments/etc. You can use the fields they've provided to trigger workflow rules (such as emails), when the record is processed successfully. Note that additional fields may be required depending on your specific use case (i.e. if there is a trial fee, trial period, etc). Note that my subscription above is infinitely recurring; you can provide additional options to limit the number of times it processes, etc.

 

In either event, you'll need to create a page that does something like this:

 

 

<apex:page ...>
  <apex:outputText rendered="{!step1}"> Please give me your data </apex:outputText>
  <apex:outputText rendered="{!step2}"> Please confirm your data </apex:outputText>
  <apex:outputText rendered='{!step3}"> Thank you! </apex:outputText>
</apex:page>

After over a month of experimentation, costly consultation with Linvio, and so on, we basically found that you might as well use SiteCheckout and save yourself the hassle.

 

bvramkumarbvramkumar

Hi sfdcfox

 

I am checking this post after a long time. Thanks a lot for the research. This might come handy to me in future...

 

Vishnu

Ron WildRon Wild

Thanks sfdcfox for posting this here.  This is a concern for us as well.

 

Perhaps I can shed a little more light on the matter.  There are two significant technical issues to deal with when doing visualforce/Sites customizations on top of PaymentConnect:

 

1. The Force.com platform does not allow you to make a DML database insert just prior to making an API callout in the same transaction. So if you wanted to store details about the customer and custom fields on the payment record and then send the credit card charge request on a single page, you'd get an error from Salesforce saying you have "uncommitted changes to the database".

 

At first glance, you might suggest making the call first and then saving the contact information and custom fields, but there's a catch there as well.  PayPal and AuthNet send an IPN or silent post in addition to responding to your api call, and since PaymentConnect handles both, you can end up with duplicate transaction records in the system.  We ensure that this doesn't happen by including the unique Payment record Id in the initial charge request and looking for it in all asynchronous posts handled by our relay scripts. So we're back to having to create the Payment record prior to requesting the charge.

 

We've created pre-built visualforce pages for checkout so you won't have to worry about these issues and can still deploy custom solutions to Sites, however these do require the record Id of the Payment or Recurring Payment Profile that you want to process as parameters.  This is the "two step process" sfdcfox is referring to above.  The developer sets up the transaction, storing contact details, creating an "In Process" Payment record and storing any custom field values you want to have in the system after the transaction has been processed succesfully.  Then the record Id is passed to the SiteCheckout or SiteSubscribe page along with optional parameters for where you want to redirect on cancel or finish, and the customer reviews/updates cardholder billing information and credit card details and submits.

 

2. The other issue has to do with the eccentricities of managed packages.  We use the $Site Template global variable in our prebuilt Sites checkout pages so that the developer can "skin" the pages with custom header, footer, css, etc and make the page an integral part of a bigger Sites implementation.  However, if you insert unmanaged $Resource or component references (e.g. <c:mycustomfooter>) in your your site template page, you'll get an error when trying to view a managed page on the site. 

 

Here's why:  Salesforce has a short-cut convention within managed packages that allows developers to leave off the package prefix when referencing resources, components, objects and fields.  This backfires in a site template, because the compiler thinks it is in the context of a managed package when it loads the page, and it assumes that the unmanaged resources and components in the template (which have no prefix) must be part of the package too ... and inserts the package prefix.   So when displaying a PaymentConnect packaged page,  "$Resource.mycssfile" becomes "$Resource.pymt_mycssfile" and can't be found.  Salesforce knows about the problem - we don't know when they plan to give us a solution.   Personally, I think having a standard prefix like "noprefix__" would do the trick.

 

It seems that even when we explain these two issues to first-time PaymentConnect integrators, we stil end up fixing code and re-explaining them ... and the problems always seem to pop up in the final minutes before a major project launch.  So it causes considerable stress and additional cost for everyone - including us.  We recommend leveraging the existing, pre-built checkout pages.  The prebuilt pages get updated with new releases, so your customizations are "future-proofed" and it will fast-track you to a custom solution. We also provide documentation and sample code for this type of integration.

 

However, if you absolutely have to go down the path of making direct calls to the PaymentConnect API classes, remember that these are undocumented and we can't offer free support for all the custom code out there.  You'll probably want to consider working with a Linvio partner who has done it before, or call Linvio about professional services.

 

Regards,

Ron Wild

President/CTO

Linvio, Inc.

 

 

 

chargent1.3880924678001516E12chargent1.3880924678001516E12
Hi Everyone- Do note that Chargent has an API that you can use tor things like this.  Our API is a big reason why we are so popular with developers.  Just ping us if you have any questions.https://appexchange.salesforce.com/listingDetail?listingId=a0N300000016jrcEAA