Hi, 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 Authorize.net? Thanks!
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.
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.
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. Code: <?php include('../hook.conf'); // get the post data as array $data = json_decode(file_get_contents("php://input"),true); // Save the post data for later debugging file_put_contents('../datastore/postdata-'.date('Y-m-d_H-i').'.ser',serialize($data)); file_put_contents('../datastore/postdata-'.date('Y-m-d_H-i').'.txt',print_r($data,true)); $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; file_put_contents('../datastore/session.txt',$session); // Check if client exists $tmp = $remote->client_get($session_id,array('email' => $data['order']['buyer_email'])); $client = @$tmp[0]; file_put_contents('../datastore/client.txt',print_r($client,true)); // 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'; //die(print_r($params)); $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']; //die(print_r($params)); //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"; } $remote->logout($session_id); } 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; } ?>
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.
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.