How to implement Payment SDK

Algorithms

There are five algorithms you must create

initialize_payment

  1. Create an algorithm called initialize_payment with a parameter called params
1920
  1. Write your code in the code block
1519

There are three main components you need to make the algorithm work.

  • Settings object
  • Payment object
  • Response method
Tenant.notify(message: "Initialize Example payment", type: :info)
Tenant.notify(message: "#{params}", type: :info)

# params will contain fields
# - payment = Payment object

# get settings from the Settings datatype
setting = get_setting("EXAMPLE_SETTINGS")

# get Payment object for transaction
payment = params["payment"]

# print to the notification log
Tenant.notify(message: "Payment #{payment.to_hash}", type: :info)

# Example of how to use a template as the response
{ 
  "action" => "render",
  "template" => "Example::Example Payment Page",
  "data" => {
    "referenceId" => payment["referenceId"],
    "transId" => SecureRandom.uuid(),
    "amount" => payment["transactionData"]["amount"]
   }
}

# Example of how to send data to user page
#{
#  "action" => "return",
#  "data" => page
#}


# Example of how to redirect to another site
#{
#  "action" => "redirect",
#  "redirect_to" => "http://urltohostedpayments"
# }
        a. Get Settings object - To retrieve the record from the Settings datatype, call the get_setting algorithm 
            and pass the name of the record
setting = get_setting("EXAMPLE_SETTINGS")
        b. Get Payment object - retrieve the Payment object that is sent to the algorithm through 
             params
payment = params["payment"]
        c. Response method - There are three options for a response method:
                  - Render a template
{ 
  "action" => "render",
  "template" => "Example::Example Payment Page",
  "data" => {
    "referenceId" => payment["referenceId"],
    "transId" => SecureRandom.uuid(),
    "amount" => payment["transactionData"]["amount"]
   }
}
                - Send data to user page
{
  "action" => "return",
  "data" => page
}
                - Redirect to another site
{
 "action" => "redirect",
 "redirect_to" => "http://urltohostedpayments"
}
  1. Save the algorithm once completed.

process_payment

  1. Create an algorithm called process_payment with a parameter called params
777
  1. Write your code in the code block
1167
Tenant.notify(message: "Process Example process_payment", type: :info)
Tenant.notify(message: "#{params}", type: :info)
begin
    # lookup the Payment entry by referenceId
  	payment = get_payment(params["referenceId"])
  
    if payment.nil?
      Cenit.fail("No Payment entry found for referenceId #{params["referenceId"]}")
    end
  
  	# Check if the current status is Pending Payment and apply payment if so
  	if payment["transactionStatus"].casecmp?("Pending Payment")
      
      # update the transactionStatus to either Approved or Failed
      status = ""
      if params["status"].eql?("APR")
        status = "Approved"
      end
      
      payment["transactionStatus"] = status
      
      # update the transactionId with the response from the payment provider
      payment["transactionId"] = params["transId"]
      
      # save any parameters sent back from the payment provider for later use
      payment["transactionData"] = params
      
      # add the payment provider transaction id as the transactionData.referenceId
      payment["transactionData"]["referenceId"] = params["transId"]
      
      # set the transactionData.payee to the info returned from the payment provider
      payment["transactionData"]["payee"] = "#{params["payeeFirstname"]} #{params["payeeLastname"]}"
      
      # set the transactionData.payee to the info returned from the payment provider
      payment["transactionData"]["payeeAddress"] = "#{params["payeeAddress"]}"
      
      # optionally build a URL to the paymnet providers detail page
      payment["transactionData"]["detailURL"] = "https://paymentprovider/detail"

      # set the transactionData.type 
      payment["transactionData"]["type"] = "Credit Card"
      # payment["transactionData"]["type"] = "Check"
     
      # optionally set the convenience or service fee charged by the payment provder
      #payment["transactionData"]["convFee"] = 0

      # save the payment
      payment = save_payment(payment)

      # return a success message as required by the payment provider
      #{
      #  "action"=> "return",
      #  "code"=> "200",
      #  "data"=> "Payment completed successfully"
      #}
      
      # redirect to transactionData.redirectURL which 
      # will exist on the Payment after calling save_payment with the
      # transactionStatus of Approved or Failed
 	  {
        "action" => "redirect",
        "redirect_to" => payment["transactionData"]["redirectURL"]
      }
    elsif payment["transactionStatus"].casecmp?("Approved") || payment["transactionStatus"].casecmp?("Failed")
      {
        "action" => "redirect",
        "redirect_to" => payment["transactionData"]["redirectURL"]
      }
    else
      {
        "action"=> "return",
        "code"=> "500",
        "data"=> "Payment in invalid state of #{payment["transactionStatus"]} for further actions"
      }
    end
rescue StandardError => ex
  code = ex.message =~ /^\[(\d+)\]/ ? $1.to_i : 500
  message = ex.message.gsub(/^\[(\d+)\] - /, '')
 
  {
      "action"=> "return",
      "code"=> code,
      "data"=> message
  }
end
        a. Lookup Payment record

                 - Begin the algorithm by looking up the Payment record by the referenceId
payment = get_payment(params["referenceId"])
                 - Add an if statement to check if the response from get_payment is null and to end the execution if it is
if payment.nil?
   Cenit.fail("No Payment entry found for referenceId #{params["referenceId"]}")
end
        b. Check if current status is Pending

                 - Check if the current status is Pending Payment and apply payment if so
if payment["transactionStatus"].casecmp?("Pending Payment")
                 - Update the transactionStatus to either Approved or Failed
status = ""
if params["status"].eql?("APR")
  status = "Approved"
end

payment["transactionStatus"] = status
                 - Update the transactionId with the response from the payment provider
payment["transactionId"] = params["transId"]
                 - Save any parameters sent back from the payment provider for later use
payment["transactionData"] = params
                 - Add the payment provider transaction id as the transactionData.referenceId
payment["transactionData"]["referenceId"] = params["transId"]
                 - Set the transactionData.payee to the info returned from the payment provider
payment["transactionData"]["payee"] = "#{params["payeeFirstname"]} #{params["payeeLastname"]}"
                 - Set the transactionData.payeeAddress to the info returned from the payment provider
payment["transactionData"]["payeeAddress"] = "#{params["payeeAddress"]}"
                 - Optionally build a URL to the payment providers detail page
payment["transactionData"]["detailURL"] = "https://paymentprovider/detail"
                 - Set the transactionData.type 
payment["transactionData"]["type"] = "Credit Card"

OR

payment["transactionData"]["type"] = "Check"
                 - Optionally set the convenience or service fee charged by the payment provder
payment["transactionData"]["convFee"] = 0
                 - Save the payment
payment = save_payment(payment)
        c. Redirect to transactionData.redirectURL which will exist on the Payment after calling save_payment with the transactionStatus of Approved or Failed
{
  "action" => "redirect",
  "redirect_to" => payment["transactionData"]["redirectURL"]
}
elsif payment["transactionStatus"].casecmp?("Approved") || payment["transactionStatus"].casecmp?("Failed")
{
  "action" => "redirect",
  "redirect_to" => payment["transactionData"]["redirectURL"]
}
else
{
  "action"=> "return",
  "code"=> "500",
  "data"=> "Payment in invalid state of #{payment["transactionStatus"]} for further actions"
}
end
        d. Ending code
rescue StandardError => ex
  code = ex.message =~ /^\[(\d+)\]/ ? $1.to_i : 500
  message = ex.message.gsub(/^\[(\d+)\] - /, '')
 
  {
      "action"=> "return",
      "code"=> code,
      "data"=> message
  }
end

payment_confirmation

  1. Create an algorithm called payment_confirmation with a parameter called params
698
  1. Write your code in the code block
1181
Tenant.notify(message: "Process Example payment_confirmation", type: :info)
Tenant.notify(message: "#{params}", type: :info)
begin
    # lookup the Payment entry by referenceId
  	payment = get_payment(params["referenceId"])
  
    if payment.nil?
      Cenit.fail("No Payment entry found for referenceId #{params["referenceId"]}")
    end
  
 	 # Check if the Payment is Approved or Failed and redirect
  	if payment["transactionStatus"].casecmp?("Approved") || payment["transactionStatus"].casecmp?("Failed")
      
 	  {
        "action" => "redirect",
        "redirect_to" => payment["transactionData"]["redirectURL"]
      }
    else
      {
        "action"=> "return",
        "code"=> "500",
        "data"=> "Payment in invalid state of #{payment["transactionStatus"]} for further actions"
      }
    end
rescue StandardError => ex
  code = ex.message =~ /^\[(\d+)\]/ ? $1.to_i : 500
  message = ex.message.gsub(/^\[(\d+)\] - /, '')
 
  {
      "action"=> "return",
      "code"=> code,
      "data"=> message
  }
end
        a. Similarly to the process_payment algorithm, begin payment_confirmation by looking up the Payment record by referenceId and check if it is null
payment = get_payment(params["referenceId"])
  
  if payment.nil?
  Cenit.fail("No Payment entry found for referenceId #{params["referenceId"]}")
  end
       b. Check if the Payment status is Approved or Failed and redirect
if payment["transactionStatus"].casecmp?("Approved") || payment["transactionStatus"].casecmp?("Failed")

  {
    "action" => "redirect",
    "redirect_to" => payment["transactionData"]["redirectURL"]
  }
else
  {
    "action"=> "return",
    "code"=> "500",
    "data"=> "Payment in invalid state of #{payment["transactionStatus"]} for further actions"
  }
end
        c. End code
rescue StandardError => ex
  code = ex.message =~ /^\[(\d+)\]/ ? $1.to_i : 500
  message = ex.message.gsub(/^\[(\d+)\] - /, '')
 
  {
      "action"=> "return",
      "code"=> code,
      "data"=> message
  }
end
  1. Save algorithm once completed.

cancel_payment

  1. Create an algorithm called cancel_payment with a parameter called params
1920
  1. Write your code in the code block
1100
Tenant.notify(message: "Process Example cancel_payment", type: :info)
Tenant.notify(message: "#{params}", type: :info)

payment = get_payment(params["referenceId"])

if payment.nil?
  Cenit.fail("No Payment entry found for referenceId #{params["referenceId"]}")
end

payment["transactionStatus"] = "Cancel"
payment["transactionId"] = params["SECURETOKENID"]
payment["transactionData"] = params
payment = save_payment(payment)
  
if payment["transactionData"]["redirectURL"]
  {
    "action" => "redirect",
    "redirect_to" => payment["transactionData"]["redirectURL"]
  }
else
  {
        "action"=> "return",
        "code"=> "200",
    	"data"=> "Payment cancelled"
    }
end
        a. Lookup Payment record by reference Id and check if it is null or not
payment = get_payment(params["referenceId"])

if payment.nil?
  Cenit.fail("No Payment entry found for referenceId #{params["referenceId"]}")
end
        b. Set Payment record details and save Payment
payment["transactionStatus"] = "Cancel"
payment["transactionId"] = params["SECURETOKENID"]
payment["transactionData"] = params
payment = save_payment(payment)
        c. Set redirect
if payment["transactionData"]["redirectURL"]
  {
    "action" => "redirect",
    "redirect_to" => payment["transactionData"]["redirectURL"]
  }
else
  {
        "action"=> "return",
        "code"=> "200",
    	"data"=> "Payment cancelled"
    }
end
  1. Save algorithm

Using the SDK

  1. Go to laserfiche.velosimo.com and login
  2. Open your forms Process Designer Diagram and show details
  3. Select start in the diagram and the On Event Completion tab
1920
  1. Set redirect to website and the URL to the initialize_payment algorithm on the Velosimo site.

Example - https://dev.velosimo.io/app/payment_adapter/laserfiche/example/initialize_payment

payment_adapter = Velosimo tenant
example = Velosimo namespace
initialize_payment = Algorithm

574
  1. Submit a new form. Once submitted you will be redirected to an environment where you can test each algorithm created.
924
        a. Click Simulate Approved Postback
1692