Difference between revisions of "Online Payment Module Architecture"

From Dolibarr ERP CRM Wiki
Jump to navigation Jump to search
m
Tag: 2017 source edit
Tag: 2017 source edit
 
(24 intermediate revisions by the same user not shown)
Line 3: Line 3:
 
     Links below will be automatically replicated on translated pages by PolyglotBot -->
 
     Links below will be automatically replicated on translated pages by PolyglotBot -->
 
<!-- END interlang links -->
 
<!-- END interlang links -->
 
 
{{TemplateDocDev}}
 
{{TemplateDocDev}}
 
{{TemplateModEN}}
 
{{TemplateModEN}}
Line 9: Line 8:
  
 
=Introduction=
 
=Introduction=
This page describe how the modules for online payments works.
+
This page describe how the Dolibarr modules for online payments works so a developer can be able to develop its own payment module with any external system.
  
This is how the [[Module Stripe]], the [[Module PayPal]] but also external modules like the [[Module HelloAsso]] are working. For core module, the code is hard coded, for external modules code is executed at the same place than core modules, but it is triggered by hooks instead of being hard coded.
+
This is how the way the [[Module Stripe]] and the [[Module PayPal]] works. External modules like the [[Module HelloAsso]], [[Module PayPlug]] are working too by using this architecture. For core module, the code is hard coded, for external modules code is executed at the same place than core modules, but it is triggered by hooks instead of being hard coded.
  
= Step 1 - The choice of the payment mode =
+
=Step 1 - The choice of the payment mode=
First step to make an online payment is done by calling the public page  
+
First step to make an online payment of any Dolibarr object (invoice, order, donation, ...) is done by calling the public page  
 
'''/public/payment/newpayment.php'''
 
'''/public/payment/newpayment.php'''
  
This page is common to all payment mode.
+
This page is common to all payment modes. The page accepts some parameters to know how to find the amount to pay. This is a list of all possible URLs:
It page accepts some parameters to know how to find the amount. This is a list of all possible URLs:
+
 
 +
*URL to offer an online payment page of any amount with no existing object (for this case the amount is provided as a parameter):
 +
 
 +
https://demo.dolibarr.org/public/payment/newpayment.php?amount=9.99&tag=your_tag
 +
 
 +
*URL to offer an online payment page for a sales order:
 +
 
 +
https://demo.dolibarr.org/public/payment/newpayment.php?source=order&ref=order_ref
  
 +
*URL to offer an online payment page for a customer invoice:
  
* URL to offer an online payment page of any amount with no existing object:
+
https://demo.dolibarr.org/public/payment/newpayment.php?source=invoice&ref=invoice_ref
  
http://mydolibarrdomain/public/payment/newpayment.php?amount=9.99&tag=your_tag
+
*URL to offer a Stripe online payment page for a contract line:
  
* URL to offer an online payment page for a sales order:
+
https://demo.dolibarr.org/public/payment/newpayment.php?source=contractline&ref=contractline_ref
  
http://mydolibarrdomain/public/payment/newpayment.php?source=order&ref=order_ref
+
*URL to offer a Stripe online payment page for a member subscription:
  
* URL to offer an online payment page for a customer invoice:
+
https://demo.dolibarr.org/public/payment/newpayment.php?source=membersubscription&ref=member_ref
  
http://mydolibarrdomain/public/payment/newpayment.php?source=invoice&ref=invoice_ref
+
*URL to offer a Stripe online payment page for payment of a donation:
  
* URL to offer a Stripe online payment page for a contract line:
+
https://demo.dolibarr.org/public/payment/newpayment.php?source=donation&ref=donation_ref
  
http://mydolibarrdomain/public/payment/newpayment.php?source=contractline&ref=contractline_ref
 
  
* URL to offer a Stripe online payment page for a member subscription:
+
The parameter are used by the page to find the amount to ask for the payment from the object information retrieved in URL.
  
http://mydolibarrdomain/public/payment/newpayment.php?source=membersubscription&ref=member_ref
+
Then the page search the list of all available payment modes by calling the function '''getValidOnlinePaymentMethods()'''. This functions calls all the hook method named '''getValidPayment''' of external modules to know which payment module is available and then calls the hook method '''doAddButton''' to get the HTML code of the button to show on the payment page for your payment system.
  
* URL to offer a Stripe online payment page for payment of a donation:
+
Note: You can have a look at the code of the PayPlug module to get sources of examples: https://github.com/DoliCloud/DoliMods/tree/master/htdocs/payplugdolicloud
  
http://mydolibarrdomain/public/payment/newpayment.php?source=donation&ref=donation_ref
+
== Implementing the hook getValidOnlinePaymentMethods ==
 +
So any payment module must first complete this list with its own ID. For this, the module must implement the hook '''getValidPayment''' of the context '''newpayment'''.  
 +
This means you must add this in the hook file (See the page [[Module development]] for more information on how to make a new virgin module with its hook file):
 +
<syntaxhighlight lang="php">
 +
public function getValidPayment($parameters, &$object, &$action, $hookmanager)
 +
{
 +
$error = "";
  
 +
$validpaymentmethod = array();
  
The parameter are used by the page to find the amount to ask for the payment from the object retrieved in URL.
+
if (array_key_exists("paymentmethod", $parameters) && (empty($parameters["paymentmethod"]) || $parameters["paymentmethod"] == 'mypaymentcode') && isModEnabled('mymodulename')) {
 +
$validpaymentmethod['mypaymentcode'] = 'valid';
 +
}
  
Then the page search the list of all available payment mode by calling getValidOnlinePaymentMethods(). To complete this list to add your own module, you must implement the hook '''getValidPayment''' of the context '''nexpayment'''.
+
if (!$error) {
<syntaxHighlight lang="php">
+
$this->results["validpaymentmethod"] = $validpaymentmethod;
$hookmanager->resarray = array('mypaymentcode => 'valid');
+
return 0;
</syntaxHighlight>
+
} else {
 +
$this->errors[] = $error;
 +
return -1;
 +
}
 +
}
 +
</syntaxhighlight>
  
Then for each entry found the page suggest the payment mode as a different button "Pay using MyPaymentMode". To output HTML code of your button, you must use the hook '''doAddButton''' for the context "newpayment". Your hook must return an
+
If you built a module that add this hook, then the '''/public/payment/newpayment.php''' page will know a new payment mode must be suggested.  
<syntaxHighlight lang="php">
+
 
$this->resarray = array('mypaymentcode' => 'MyPaymentMode Label on Button')
+
== Implementing the hook getValidOnlinePaymentMethods ==
</syntaxHighlight>
+
To output the HTML code of your button, you must add the hook method '''doAddButton''' for the context "newpayment" in your hook module file. Your hook must return the string with HTML code into ->resprints.
 +
<syntaxhighlight lang="php">
 +
public function doAddButton($parameters, &$object, &$action, $hookmanager)
 +
{
 +
global $langs;
 +
 
 +
$resprints = "";
 +
$error = "";
 +
 
 +
if (array_key_exists("paymentmethod", $parameters) && (empty($parameters["paymentmethod"]) || $parameters["paymentmethod"] == 'mypaymentcode') && isModEnabled('mymodulename')) {
 +
$resprints .= '<button class="buttonpaymentsmall">'.$langs->trans("Pay with mysystem").'</button>';
 +
$resprints .= '<script>myjavascript code</script>';
 +
}
 +
 
 +
if (!$error) {
 +
$this->resprints = $resprints;
 +
return 0; // or return 1 to replace standard code
 +
} else {
 +
$this->errors[] = $error;
 +
return -1;
 +
}
 +
}
 +
 
 +
 
 +
$this->resarray = array('mypaymentcode' => 'MyPaymentMode Label on the button')
 +
</syntaxhighlight>
  
 
If you want you can also implement the hook '''checkStatus''' to retrieve information from your payment platform to show information on the payment page.
 
If you want you can also implement the hook '''checkStatus''' to retrieve information from your payment platform to show information on the payment page.
  
=> Once done, you can already test your module integration by checking that a new entry to pay appear on the payment page.
+
=> Once done, you can already test your module integration by checking that a new entry to pay appears on the newpayment page.
  
= Step 2 - User choose the payment mode =
+
=Step 2 - User choose the payment mode=
  
 
When the user has clicked on a payment mode, the same page is called but with a parameter '''action=dopayment'''.  
 
When the user has clicked on a payment mode, the same page is called but with a parameter '''action=dopayment'''.  
Line 69: Line 114:
  
 
Among information automatically saved into session, you ha:ve
 
Among information automatically saved into session, you ha:ve
* the amount into $_SESSION['FinalPaymentAmount']
+
 
* currency code
+
*the amount into $_SESSION['FinalPaymentAmount']
* ip address of user
+
*currency code
 +
*ip address of user
 +
 
 
You can complete with any variable of your choice. A lot of information about the payment are available into variable $FULLTAG that contains information on the source of the payment (the mode but also the object of Dolibarr the payment may be related to). Content of the $FULLTAG string must be provided to the payment system because it is required to have it returned in the fallback URL called once a payment has been done (see STEP 4)
 
You can complete with any variable of your choice. A lot of information about the payment are available into variable $FULLTAG that contains information on the source of the payment (the mode but also the object of Dolibarr the payment may be related to). Content of the $FULLTAG string must be provided to the payment system because it is required to have it returned in the fallback URL called once a payment has been done (see STEP 4)
  
 
Depending on the payment mode, the page may prepare the payment on the remote system. It may be an API call or a redirect to another page. Then the page should:
 
Depending on the payment mode, the page may prepare the payment on the remote system. It may be an API call or a redirect to another page. Then the page should:
* show the form to allow the user payment page embedded into the dolibarr newpayment page (example with Stripe payment mode).  
+
 
* or the page may also choose to make a redirect to another page (on remote system) that ask this information (example with Paypal payment mode).
+
*show the form to allow the user payment page embedded into the dolibarr newpayment page (example with Stripe payment mode).
 +
*or the page may also choose to make a redirect to another page (on remote system) that ask this information (example with Paypal payment mode).
  
 
For all of this, you must implement the hook '''doPayment''' in the context 'newpayment'.
 
For all of this, you must implement the hook '''doPayment''' in the context 'newpayment'.
  
If you need to embed you own form, the content must returned by the hook, for example:  
+
If you need to embed you own HTML form, the content must be returned by the hook into ->resPrint, for example:  
 
<syntaxhighlight lang="php">
 
<syntaxhighlight lang="php">
 
this->resPrint = '<script>my javascript</script><form><input type="text" name="credit card num"></form>';
 
this->resPrint = '<script>my javascript</script><form><input type="text" name="credit card num"></form>';
Line 95: Line 143:
 
=> You can now test that after the click on your payment mode, the redirect to you home page is ok or the form is shown.
 
=> You can now test that after the click on your payment mode, the redirect to you home page is ok or the form is shown.
  
= Step 3 - Entering payment information =
+
=Step 3 - Entering payment information=
  
 
When the form to enter payment information are submitted (whatever is the page that handle it), the payment system should send a redirect to the page '''/public/payment/paymentok.php''' or '''public/payment/paymentko.php''' depending on status of payment.
 
When the form to enter payment information are submitted (whatever is the page that handle it), the payment system should send a redirect to the page '''/public/payment/paymentok.php''' or '''public/payment/paymentko.php''' depending on status of payment.
  
* If the page to enter the payment was an external page, this external page must do a redirect to the one or the other (depending on success or not) but in both cases, the content of the variable $FULLTAG must be provided inside a parameter '''fulltag'''.
+
*If the page to enter the payment was an external page, this external page must do a redirect to the one or the other (depending on success or not) but in both cases, the content of the variable $FULLTAG must be provided inside a parameter '''fulltag'''.
 +
 
 +
*If the page to enter payment was the newpayment page, using the a custom form, you can retrieve the submit of the form inside the hook doAction. You must use a parameter submited by your form to make the difference between the use of the hook in this step, after a payment has been done, or the use of the hook at the previous step (when the page is shown to output the form to enter payment information).
  
* If the page to enter payment was the newpayment page, using the a custom form, you can retrieve the submit of the form inside the hook doAction. You must use a parameter submited by your form to make the difference between the use of the hook in this step, after a payment has been done, or the use of the hook at the previous step (when the page is shown to output the form to enter payment information).
+
=Step 4 - Fallback on result page=
 +
When payment is complete, the user finally reach the page '''/public/payment/paymentok.php''' or '''/public/payment/paymentko.php'''.
 +
The page paymentko.php will just return a message to explain the payment has failed. The page paymentok.php, will use the parameter '''fulltag''' and variables saved into session to make complementary actions (like validating remotely the payment, registering the payment in the Dolibarr application, closing the invoice, sending emails...). The paymentok/ko page can retrieve information from:
  
= Step 4 - Fallback on result page =
+
*Parameter "fulltag" AG (this parameter was defined into the public/payment/newpayment.php page). With this parameter, the page paymentok.php will be able to make all complementary action like closing invoice or order or recording a subscription for a membership subscription, and more...
When payment is complete, the use finally reach the page paymentok.php or paymentko.php.
+
*Some payment mode include also more parameters like PAYERID for Paypal. Only FULLTAG should be mandatory.
The page paymentko will just return a message to explain the payment has failed. The page paymentok, will use the parameter fulltag and variables saved into session to make complementary actions like (registering the payment in the application, closing the invoice, sending an email...). The paymentok/ko page can retrieve information from:
 
* Parameter "fulltag" AG (this parameter was defined into the public/payment/newpayment.php page). With this parameter, the page paymentok.php will be able to make all complementary action like closing invoice or order or recording a subscription for a membership subscription, and more...
 
* Some payment mode include also more parameters like PAYERID for Paypal. Only FULLTAG should be mandatory.
 
  
 
Some other parameters may be retrieved in the session like:
 
Some other parameters may be retrieved in the session like:
* $_SESSION['ipaddress']
 
* $_SESSION['errormessage']  An error message to show
 
  
 +
*$_SESSION['ipaddress']
 +
*$_SESSION['errormessage']  An error message to show
  
= Other features =
+
=Other features=
 
To complete...
 
To complete...

Latest revision as of 20:39, 25 June 2025


Introduction

This page describe how the Dolibarr modules for online payments works so a developer can be able to develop its own payment module with any external system.

This is how the way the Module Stripe and the Module PayPal works. External modules like the Module HelloAsso, Module PayPlug are working too by using this architecture. For core module, the code is hard coded, for external modules code is executed at the same place than core modules, but it is triggered by hooks instead of being hard coded.

Step 1 - The choice of the payment mode

First step to make an online payment of any Dolibarr object (invoice, order, donation, ...) is done by calling the public page /public/payment/newpayment.php

This page is common to all payment modes. The page accepts some parameters to know how to find the amount to pay. This is a list of all possible URLs:

  • URL to offer an online payment page of any amount with no existing object (for this case the amount is provided as a parameter):

https://demo.dolibarr.org/public/payment/newpayment.php?amount=9.99&tag=your_tag

  • URL to offer an online payment page for a sales order:

https://demo.dolibarr.org/public/payment/newpayment.php?source=order&ref=order_ref

  • URL to offer an online payment page for a customer invoice:

https://demo.dolibarr.org/public/payment/newpayment.php?source=invoice&ref=invoice_ref

  • URL to offer a Stripe online payment page for a contract line:

https://demo.dolibarr.org/public/payment/newpayment.php?source=contractline&ref=contractline_ref

  • URL to offer a Stripe online payment page for a member subscription:

https://demo.dolibarr.org/public/payment/newpayment.php?source=membersubscription&ref=member_ref

  • URL to offer a Stripe online payment page for payment of a donation:

https://demo.dolibarr.org/public/payment/newpayment.php?source=donation&ref=donation_ref


The parameter are used by the page to find the amount to ask for the payment from the object information retrieved in URL.

Then the page search the list of all available payment modes by calling the function getValidOnlinePaymentMethods(). This functions calls all the hook method named getValidPayment of external modules to know which payment module is available and then calls the hook method doAddButton to get the HTML code of the button to show on the payment page for your payment system.

Note: You can have a look at the code of the PayPlug module to get sources of examples: https://github.com/DoliCloud/DoliMods/tree/master/htdocs/payplugdolicloud

Implementing the hook getValidOnlinePaymentMethods

So any payment module must first complete this list with its own ID. For this, the module must implement the hook getValidPayment of the context newpayment. This means you must add this in the hook file (See the page Module development for more information on how to make a new virgin module with its hook file):

public function getValidPayment($parameters, &$object, &$action, $hookmanager)
{
$error = "";

$validpaymentmethod = array();

if (array_key_exists("paymentmethod", $parameters) && (empty($parameters["paymentmethod"]) || $parameters["paymentmethod"] == 'mypaymentcode') && isModEnabled('mymodulename')) {
$validpaymentmethod['mypaymentcode'] = 'valid';
}

if (!$error) {
$this->results["validpaymentmethod"] = $validpaymentmethod;
return 0;
} else {
$this->errors[] = $error;
return -1;
}
}

If you built a module that add this hook, then the /public/payment/newpayment.php page will know a new payment mode must be suggested.

Implementing the hook getValidOnlinePaymentMethods

To output the HTML code of your button, you must add the hook method doAddButton for the context "newpayment" in your hook module file. Your hook must return the string with HTML code into ->resprints.

public function doAddButton($parameters, &$object, &$action, $hookmanager)
{
global $langs;

$resprints = "";
$error = "";

if (array_key_exists("paymentmethod", $parameters) && (empty($parameters["paymentmethod"]) || $parameters["paymentmethod"] == 'mypaymentcode') && isModEnabled('mymodulename')) {
$resprints .= '<button class="buttonpaymentsmall">'.$langs->trans("Pay with mysystem").'</button>';
$resprints .= '<script>myjavascript code</script>';
}

if (!$error) {
$this->resprints = $resprints;
return 0; // or return 1 to replace standard code
} else {
$this->errors[] = $error;
return -1;
}
}


$this->resarray = array('mypaymentcode' => 'MyPaymentMode Label on the button')

If you want you can also implement the hook checkStatus to retrieve information from your payment platform to show information on the payment page.

=> Once done, you can already test your module integration by checking that a new entry to pay appears on the newpayment page.

Step 2 - User choose the payment mode

When the user has clicked on a payment mode, the same page is called but with a parameter action=dopayment.

If the payment mode needs to, some information about the payment are stored into session so it will be possible to retrieve them later when falling back on the result of payment page.

Among information automatically saved into session, you ha:ve

  • the amount into $_SESSION['FinalPaymentAmount']
  • currency code
  • ip address of user

You can complete with any variable of your choice. A lot of information about the payment are available into variable $FULLTAG that contains information on the source of the payment (the mode but also the object of Dolibarr the payment may be related to). Content of the $FULLTAG string must be provided to the payment system because it is required to have it returned in the fallback URL called once a payment has been done (see STEP 4)

Depending on the payment mode, the page may prepare the payment on the remote system. It may be an API call or a redirect to another page. Then the page should:

  • show the form to allow the user payment page embedded into the dolibarr newpayment page (example with Stripe payment mode).
  • or the page may also choose to make a redirect to another page (on remote system) that ask this information (example with Paypal payment mode).

For all of this, you must implement the hook doPayment in the context 'newpayment'.

If you need to embed you own HTML form, the content must be returned by the hook into ->resPrint, for example:

this->resPrint = '<script>my javascript</script><form><input type="text" name="credit card num"></form>';

If you need to make a redirect to an external page, do it into this hook with:

header("Location: myexternalpaymenturl?keyforfulltag=$FULLTAG&myotherparameters");
exit;

Do not return value, just do an exit after the redirect.


=> You can now test that after the click on your payment mode, the redirect to you home page is ok or the form is shown.

Step 3 - Entering payment information

When the form to enter payment information are submitted (whatever is the page that handle it), the payment system should send a redirect to the page /public/payment/paymentok.php or public/payment/paymentko.php depending on status of payment.

  • If the page to enter the payment was an external page, this external page must do a redirect to the one or the other (depending on success or not) but in both cases, the content of the variable $FULLTAG must be provided inside a parameter fulltag.
  • If the page to enter payment was the newpayment page, using the a custom form, you can retrieve the submit of the form inside the hook doAction. You must use a parameter submited by your form to make the difference between the use of the hook in this step, after a payment has been done, or the use of the hook at the previous step (when the page is shown to output the form to enter payment information).

Step 4 - Fallback on result page

When payment is complete, the user finally reach the page /public/payment/paymentok.php or /public/payment/paymentko.php. The page paymentko.php will just return a message to explain the payment has failed. The page paymentok.php, will use the parameter fulltag and variables saved into session to make complementary actions (like validating remotely the payment, registering the payment in the Dolibarr application, closing the invoice, sending emails...). The paymentok/ko page can retrieve information from:

  • Parameter "fulltag" AG (this parameter was defined into the public/payment/newpayment.php page). With this parameter, the page paymentok.php will be able to make all complementary action like closing invoice or order or recording a subscription for a membership subscription, and more...
  • Some payment mode include also more parameters like PAYERID for Paypal. Only FULLTAG should be mandatory.

Some other parameters may be retrieved in the session like:

  • $_SESSION['ipaddress']
  • $_SESSION['errormessage'] An error message to show

Other features

To complete...