Billing Module and Payment Gateways

Discussion in 'Plugins/Modules/Addons' started by Honza, Jan 31, 2018.

  1. Honza

    Honza Member

    Basically the only reason why I'm still working with WHMCS instead of the Billing Module is lack of out-of-the-box working payment gateways. My understanding is that it now only works with PayPal.

    If I was considering to move forward and use the Billing Module instead of WHMCS is somebody able here to make the billing work with at least the major credit card processors such as Stripe or

  2. till

    till Super Moderator Staff Member ISPConfig Developer

    The billing module works with Paypal and SEPA debit payments at the moment, SEPA is only used in Europe. As far as I know, @florian030 is using the module with Sendowl, maybe he is willing to share his code. I'm using sendowl as well with the billing module, but my code might be a bit special as it is used here at howtoforge for the subscription payment processing.
  3. florian030

    florian030 ISPConfig Developer ISPConfig Developer

    I use this with sendowl and they offer you some additional gateways like stripe. IIRC stripe has a lot of payment-gateways.
    You can create a hook on sendowl pointing to your server and trigger some API-Calls for the billing-module depending on the data you received from sendowl. But i don't think, that you use a script without modifications. I have a very small script that matches most of my needs but this won't work on other systems.
  4. florian030

    florian030 ISPConfig Developer ISPConfig Developer

    I found an older version of this script, that you may can use with smaller modifications. IIRC this has two bugs:
    the invoice-number will be incorrect (placeholders not replaced) and the vat-settings may be wrong for clients with a vat-id from europe.
    that's the reason, why the send-invioce is commented.

    // get the post data as array
    $data = json_decode(file_get_contents("php://input"),true);
    // Save the post data for later debugging
    $error = '';
    function sendowl_price($val) {
      preg_match("/\d+\.\d+/", $val, $matches);
      return $matches[0];
    // Create remote client connection
    $remote = new SoapClient(null, array(  'location' => $conf['remote_uri'].'billing.php',
      'uri'  => $conf['remote_uri'],
      'trace' => 1,
      'exceptions' => 1));
    try {
      $session_id = $remote->login($conf['remote_user'], $conf['remote_password']);
      //echo $session_id;
      // Check if client exists
      $tmp = $remote->client_get($session_id,array('email' => $data['order']['buyer_email']));
      $client = @$tmp[0];
      // Add billing client if not exists
      if(!isset($client['client_id'])) {
      $language = ($data['order']['buyer_country'] == 'DE' || $data['order']['buyer_country'] == 'AT')?'de':'en';
      $company_name = (isset($data['order']['business_name']))?$data['order']['business_name']:'';
      $street = ($data['order']['billing_address2'] == '')?$data['order']['billing_address1']:$data['order']['billing_address1'].' '.$data['order']['billing_address2'];
      $username = str_replace('.','dot',str_replace('@','at',$data['order']['buyer_email']));
      // Add client with remote api
      $params = array(
      'company_name' => $company_name,
      'contact_name' => $data['order']['buyer_name'],
      'email' => $data['order']['buyer_email'],
      'street' => $street,
      'zip' => $data['order']['billing_postcode'],
      'city' => $data['order']['billing_city'],
      'state' => $data['order']['billing_region'],
      'country' => $data['order']['billing_country'],
      'username' => $username,
      'language' => $language,
      'paypal_email' => $data['order']['paypal_email'],
      'vat_id' => $data['order']['business_vat_number']
      //* Set a few defaults
      $params['mail_servers'] = 1;
      $params['web_servers'] = 1;
      $params['dns_servers'] = 1;
      $params['db_servers'] = 1;
      $params['web_php_options'] = 'no';
      $params['ssh_chroot'] = 'no';
      $params['usertheme'] = 'default';
      $client_id = $remote->client_add($session_id,0,$params);
      } else {
        $client_id = $client['client_id'];
      // Add the invoice
      $params = array();
      $params['payment_terms'] = 24;
      $params['invoice_company_id'] = 2;
      $invoice_id = $remote->billing_invoice_add($session_id,$client_id,$params);
      // add subscription items to invoice
      if(is_array($data['order']['cart']['cart_items'])) {
      foreach($data['order']['cart']['cart_items'] as $item) {
      if($item['quantity'] >= 0) {
      $params = array();
      $params['quantity'] = $item['quantity'];
      $params['price'] = sendowl_price($item['product']['price']);
      $params['vat'] = 'auto';
      //$params['_price_includes_vat'] = 'y';
      $params['description'] = $item['product']['name'];
      //echo $item['product']['price'];
      //print_r( $matches);
      $remote->billing_invoice_item_add($session_id, $invoice_id, $params);
      $remote->billing_invoice_finalize($session_id, $invoice_id);
      // Test the invoice, compare if invoice amount matches with values from sendowl
      $invoice = $remote->billing_invoice_get($session_id, $invoice_id);
      if(is_array($invoice)) {
      $so_price = sendowl_price($data['order']['settled_gross']);
      $isp_price = round($invoice['invoice_amount'],2);
      if($so_price == $isp_price) {
      // Send the invoice to the customer
      //  $additional_placeholders = array();
      //  $remote->billing_invoice_send($session_id, $invoice_id, $email_template_id, $additional_placeholders);
      } else {
      $error .= "Invoice amount does not match with amount from sendowl so = $so_price; isp = $isp_price.\n";
      } else {
      $error .= "Unable to get invoice $invoice_id\n";
    } catch (SoapFault $e) {
      $error .= print_r($e,true);
      $error .= $remote->__getLastResponse();
    if($error != '') {
      // send an error email
      mail($error_email,'SendOwl invoice error',$error."\n\n".print_r($data,true)."\n\n".print_r($invoice,true));
      //echo $error;
  5. till

    till Super Moderator Staff Member ISPConfig Developer

    The invoice placeholder not replaced issue has been fixed in the current billing module version.

    For these cases, the commented code already compares the calculated invoice amount with the amount that send owl calculated and notifies the admin instead of sending the invoice. So it should be safe to activate the invoice sending like that.
  6. florian030

    florian030 ISPConfig Developer ISPConfig Developer

    Maybe i should update my billing-module ;)

    It is safe to send invoices but i had the problem with the place-holders. I use a different script as a workaround for the placeholders but if the latest version fixes this, i can remove my workaround.

Share This Page