Decouple Billing and S3 cloud storage stuff from Zend
This commit is contained in:
parent
49667e3d2d
commit
dbba5a7427
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once 'StorageBackend.php';
|
require_once 'StorageBackend.php';
|
||||||
require_once 'BillingController.php';
|
require_once 'Billing.php';
|
||||||
|
|
||||||
use Aws\S3\S3Client;
|
use Aws\S3\S3Client;
|
||||||
|
|
||||||
|
@ -68,13 +68,12 @@ class Amazon_S3 extends StorageBackend
|
||||||
{
|
{
|
||||||
$this->s3Client->deleteMatchingObjects(
|
$this->s3Client->deleteMatchingObjects(
|
||||||
$bucket = $this->getBucket(),
|
$bucket = $this->getBucket(),
|
||||||
$prefix = self::getAmazonS3FilePrefix());
|
$prefix = $this->getFilePrefix());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getAmazonS3FilePrefix()
|
public function getFilePrefix()
|
||||||
{
|
{
|
||||||
$clientCurrentAirtimeProduct = BillingController::getClientCurrentAirtimeProduct();
|
$clientCurrentAirtimeProduct = Billing::getClientCurrentAirtimeProduct();
|
||||||
$hostingId = $clientCurrentAirtimeProduct["id"];
|
$hostingId = $clientCurrentAirtimeProduct["id"];
|
||||||
return substr($hostingId, -2)."/".$hostingId;
|
return substr($hostingId, -2)."/".$hostingId;
|
||||||
}
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class FileStorageBackend extends StorageBackend
|
||||||
|
{
|
||||||
|
//Stub class
|
||||||
|
public function FileStorageBackend()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAbsoluteFilePath($resourceId)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
return $resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSignedURL($resourceId)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFileSize($resourceId)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
return filesize($resourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deletePhysicalFile($resourceId)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteAllCloudFileObjects()
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFilePrefix()
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once 'StorageBackend.php';
|
require_once 'StorageBackend.php';
|
||||||
require_once 'Amazon_S3.php';
|
require_once 'FileStorageBackend.php';
|
||||||
|
require_once 'Amazon_S3StorageBackend.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -23,7 +24,13 @@ class ProxyStorageBackend extends StorageBackend
|
||||||
//The storage backend in the airtime.conf directly corresponds to
|
//The storage backend in the airtime.conf directly corresponds to
|
||||||
//the name of the class that implements it (eg. Amazon_S3), so we
|
//the name of the class that implements it (eg. Amazon_S3), so we
|
||||||
//can easily create the right backend object dynamically:
|
//can easily create the right backend object dynamically:
|
||||||
$this->storageBackend = new $storageBackend($CC_CONFIG[$storageBackend]);
|
if ($storageBackend == "Amazon_S3") {
|
||||||
|
$this->storageBackend = new Amazon_S3StorageBackend($CC_CONFIG["Amazon_S3"]);
|
||||||
|
} else if ($storageBackend == "file") {
|
||||||
|
$this->storageBackend = new FileStorageBackend();
|
||||||
|
} else {
|
||||||
|
$this->storageBackend = new $storageBackend($CC_CONFIG[$storageBackend]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAbsoluteFilePath($resourceId)
|
public function getAbsoluteFilePath($resourceId)
|
||||||
|
@ -51,4 +58,8 @@ class ProxyStorageBackend extends StorageBackend
|
||||||
$this->storageBackend->deleteAllCloudFileObjects();
|
$this->storageBackend->deleteAllCloudFileObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFilePrefix()
|
||||||
|
{
|
||||||
|
$this->storageBackend->getFilePrefix();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,10 @@ abstract class StorageBackend
|
||||||
/** Deletes all objects (files) stored on the cloud service. To be used
|
/** Deletes all objects (files) stored on the cloud service. To be used
|
||||||
* for station termination */
|
* for station termination */
|
||||||
abstract public function deleteAllCloudFileObjects();
|
abstract public function deleteAllCloudFileObjects();
|
||||||
|
|
||||||
|
/** Get a prefix for the file (which is usually treated like a directory in the cloud) */
|
||||||
|
abstract public function getFilePrefix();
|
||||||
|
|
||||||
protected function getBucket()
|
protected function getBucket()
|
||||||
{
|
{
|
||||||
return $this->bucket;
|
return $this->bucket;
|
||||||
|
|
|
@ -0,0 +1,321 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Billing
|
||||||
|
{
|
||||||
|
public static function getAPICredentials()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
"username" => $_SERVER["WHMCS_USERNAME"],
|
||||||
|
"password" => $_SERVER["WHMCS_PASSWORD"],
|
||||||
|
"url" => "https://account.sourcefabric.com/includes/api.php?accesskey=".$_SERVER["WHMCS_ACCESS_KEY"],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the Airtime instance ID of the instance the customer is currently viewing. */
|
||||||
|
public static function getClientInstanceId()
|
||||||
|
{
|
||||||
|
$currentProduct = BillingController::getClientCurrentAirtimeProduct();
|
||||||
|
return $currentProduct["id"];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getProducts()
|
||||||
|
{
|
||||||
|
//Making this static to cache the products during a single HTTP request.
|
||||||
|
//This saves us roundtrips to WHMCS if getProducts() is called multiple times.
|
||||||
|
static $result = array();
|
||||||
|
if (!empty($result))
|
||||||
|
{
|
||||||
|
return $result["products"]["product"];
|
||||||
|
}
|
||||||
|
|
||||||
|
$credentials = self::getAPICredentials();
|
||||||
|
|
||||||
|
$postfields = array();
|
||||||
|
$postfields["username"] = $credentials["username"];
|
||||||
|
$postfields["password"] = md5($credentials["password"]);
|
||||||
|
$postfields["action"] = "getproducts";
|
||||||
|
$postfields["responsetype"] = "json";
|
||||||
|
//gid is the Airtime product group id on whmcs
|
||||||
|
$postfields["gid"] = "15";
|
||||||
|
|
||||||
|
$query_string = "";
|
||||||
|
foreach ($postfields AS $k=>$v) $query_string .= "$k=".urlencode($v)."&";
|
||||||
|
|
||||||
|
$result = self::makeRequest($credentials["url"], $query_string);
|
||||||
|
//Logging::info($result["products"]["product"]);
|
||||||
|
$products = $result["products"]["product"];
|
||||||
|
|
||||||
|
//Blacklist all free plans
|
||||||
|
foreach ($products as $k => $p) {
|
||||||
|
Logging::info($p);
|
||||||
|
if ($p["paytype"] === "free")
|
||||||
|
{
|
||||||
|
unset($products[$k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $products;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getProductPricesAndTypes()
|
||||||
|
{
|
||||||
|
$products = Billing::getProducts();
|
||||||
|
$productPrices = array();
|
||||||
|
$productTypes = array();
|
||||||
|
|
||||||
|
foreach ($products as $k => $p) {
|
||||||
|
$productPrices[$p["name"]] = array(
|
||||||
|
"monthly" => $p["pricing"]["USD"]["monthly"],
|
||||||
|
"annually" => $p["pricing"]["USD"]["annually"]
|
||||||
|
);
|
||||||
|
$productTypes[$p["pid"]] = $p["name"] . " ($" . $productPrices[$p['name']]['monthly'] . "/mo)";
|
||||||
|
}
|
||||||
|
return array($productPrices, $productTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the plan (or product in WHMCS lingo) that the customer is currently on.
|
||||||
|
* @return An associative array containing the fields for the product
|
||||||
|
* */
|
||||||
|
public static function getClientCurrentAirtimeProduct()
|
||||||
|
{
|
||||||
|
static $airtimeProduct = null;
|
||||||
|
//Ghetto caching to avoid multiple round trips to WHMCS
|
||||||
|
if ($airtimeProduct) {
|
||||||
|
return $airtimeProduct;
|
||||||
|
}
|
||||||
|
$credentials = self::getAPICredentials();
|
||||||
|
|
||||||
|
$postfields = array();
|
||||||
|
$postfields["username"] = $credentials["username"];
|
||||||
|
$postfields["password"] = md5($credentials["password"]);
|
||||||
|
$postfields["action"] = "getclientsproducts";
|
||||||
|
$postfields["responsetype"] = "json";
|
||||||
|
$postfields["clientid"] = Application_Model_Preference::GetClientId();
|
||||||
|
|
||||||
|
$query_string = "";
|
||||||
|
foreach ($postfields AS $k=>$v) $query_string .= "$k=".urlencode($v)."&";
|
||||||
|
|
||||||
|
$result = self::makeRequest($credentials["url"], $query_string);
|
||||||
|
|
||||||
|
//XXX: Debugging / local testing
|
||||||
|
if ($_SERVER['SERVER_NAME'] == "airtime.localhost") {
|
||||||
|
$_SERVER['SERVER_NAME'] = "bananas.airtime.pro";
|
||||||
|
}
|
||||||
|
|
||||||
|
//This code must run on airtime.pro for it to work... it's trying to match
|
||||||
|
//the server's hostname with the client subdomain. Once it finds a match
|
||||||
|
//between the product and the server's hostname/subdomain, then it
|
||||||
|
//returns the ID of that product (aka. the service ID of an Airtime instance)
|
||||||
|
foreach ($result["products"]["product"] as $product)
|
||||||
|
{
|
||||||
|
if (strpos($product["groupname"], "Airtime") === FALSE)
|
||||||
|
{
|
||||||
|
//Ignore non-Airtime products
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($product["status"] === "Active") {
|
||||||
|
$airtimeProduct = $product;
|
||||||
|
$subdomain = '';
|
||||||
|
|
||||||
|
foreach ($airtimeProduct['customfields']['customfield'] as $customField) {
|
||||||
|
if ($customField['name'] === SUBDOMAIN_WHMCS_CUSTOM_FIELD_NAME) {
|
||||||
|
$subdomain = $customField['value'];
|
||||||
|
if (($subdomain . ".airtime.pro") === $_SERVER['SERVER_NAME']) {
|
||||||
|
return $airtimeProduct;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception("Unable to match subdomain to a service ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getClientDetails()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$credentials = self::getAPICredentials();
|
||||||
|
|
||||||
|
$postfields = array();
|
||||||
|
$postfields["username"] = $credentials["username"];
|
||||||
|
$postfields["password"] = md5($credentials["password"]);
|
||||||
|
$postfields["action"] = "getclientsdetails";
|
||||||
|
$postfields["stats"] = true;
|
||||||
|
$postfields["clientid"] = Application_Model_Preference::GetClientId();
|
||||||
|
$postfields["responsetype"] = "json";
|
||||||
|
|
||||||
|
$query_string = "";
|
||||||
|
foreach ($postfields AS $k=>$v) $query_string .= "$k=".urlencode($v)."&";
|
||||||
|
|
||||||
|
$arr = self::makeRequest($credentials["url"], $query_string);
|
||||||
|
return $arr["client"];
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Logging::info($e->getMessage());
|
||||||
|
}
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function makeRequest($url, $query_string) {
|
||||||
|
try {
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 ); // WHMCS IP whitelist doesn't support IPv6
|
||||||
|
curl_setopt($ch, CURLOPT_POST, 1);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 5); //Aggressive 5 second timeout
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $query_string);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
||||||
|
$jsondata = curl_exec($ch);
|
||||||
|
if (curl_error($ch)) {
|
||||||
|
//die("Connection Error: ".curl_errno($ch).' - '.curl_error($ch));
|
||||||
|
throw new Exception("WHMCS server down or invalid request.");
|
||||||
|
}
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
return json_decode($jsondata, true);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Logging::info($e->getMessage());
|
||||||
|
}
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function ensureClientIdIsValid()
|
||||||
|
{
|
||||||
|
if (Application_Model_Preference::GetClientId() == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid client ID: " . Application_Model_Preference::GetClientId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if VAT should be applied to the order, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function checkIfVatShouldBeApplied($vatNumber, $countryCode)
|
||||||
|
{
|
||||||
|
if ($countryCode === 'UK') {
|
||||||
|
$countryCode = 'GB'; //VIES database has it as GB
|
||||||
|
}
|
||||||
|
//We don't charge you VAT if you're not in the EU
|
||||||
|
if (!Billing::isCountryInEU($countryCode))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//So by here, we know you're in the EU.
|
||||||
|
|
||||||
|
//No VAT number? Then we charge you VAT.
|
||||||
|
if (empty($vatNumber)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//Check if VAT number is valid
|
||||||
|
return Billing::validateVATNumber($vatNumber, $countryCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isCountryInEU($countryCode)
|
||||||
|
{
|
||||||
|
$euCountryCodes = array('BE', 'BG', 'CZ', 'DK', 'DE', 'EE', 'IE', 'EL', 'ES', 'FR',
|
||||||
|
'HR', 'IT', 'CY', 'LV', 'LT', 'LU', 'HU', 'MT', 'NL', 'AT',
|
||||||
|
'PL', 'PT', 'RO', 'SI', 'SK', 'FI', 'SE', 'UK', 'GB');
|
||||||
|
|
||||||
|
if (!in_array($countryCode, $euCountryCodes)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an EU VAT number is valid, using the EU VIES validation web API.
|
||||||
|
*
|
||||||
|
* @param string $vatNumber - A VAT identifier (number), with or without the two letter country code at the
|
||||||
|
* start (either one works) .
|
||||||
|
* @param string $countryCode - A two letter country code
|
||||||
|
* @return boolean true if the VAT number is valid, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function validateVATNumber($vatNumber, $countryCode)
|
||||||
|
{
|
||||||
|
$vatNumber = str_replace(array(' ', '.', '-', ',', ', '), '', trim($vatNumber));
|
||||||
|
|
||||||
|
//If the first two letters are a country code, use that as the country code and remove those letters.
|
||||||
|
$firstTwoCharacters = substr($vatNumber, 0, 2);
|
||||||
|
if (preg_match("/[a-zA-Z][a-zA-Z]/", $firstTwoCharacters) === 1) {
|
||||||
|
$countryCode = strtoupper($firstTwoCharacters); //The country code from the VAT number overrides your country.
|
||||||
|
$vatNumber = substr($vatNumber, 2);
|
||||||
|
}
|
||||||
|
$client = new SoapClient("http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl");
|
||||||
|
|
||||||
|
if($client){
|
||||||
|
$params = array('countryCode' => $countryCode, 'vatNumber' => $vatNumber);
|
||||||
|
try{
|
||||||
|
$r = $client->checkVat($params);
|
||||||
|
if($r->valid == true){
|
||||||
|
// VAT-ID is valid
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// VAT-ID is NOT valid
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch(SoapFault $e) {
|
||||||
|
Logging::error('VIES EU VAT validation error: '.$e->faultstring);
|
||||||
|
if ($e->faultstring == "INVALID_INPUT") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//If there was another error with the VAT validation service, we allow
|
||||||
|
//the VAT number to pass. (eg. SERVER_BUSY, MS_UNAVAILABLE, TIMEOUT, SERVICE_UNAVAILABLE)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Connection to host not possible, europe.eu down?
|
||||||
|
Logging::error('VIES EU VAT validation error: Host unreachable');
|
||||||
|
//If there was an error with the VAT validation service, we allow
|
||||||
|
//the VAT number to pass.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function addVatToInvoice($invoice_id)
|
||||||
|
{
|
||||||
|
$credentials = self::getAPICredentials();
|
||||||
|
|
||||||
|
//First we need to get the invoice details: sub total, and total
|
||||||
|
//so we can calcuate the amount of VAT to add
|
||||||
|
$invoicefields = array();
|
||||||
|
$invoicefields["username"] = $credentials["username"];
|
||||||
|
$invoicefields["password"] = md5($credentials["password"]);
|
||||||
|
$invoicefields["action"] = "getinvoice";
|
||||||
|
$invoicefields["invoiceid"] = $invoice_id;
|
||||||
|
$invoicefields["responsetype"] = "json";
|
||||||
|
|
||||||
|
$invoice_query_string = "";
|
||||||
|
foreach ($invoicefields as $k=>$v) $invoice_query_string .= "$k=".urlencode($v)."&";
|
||||||
|
|
||||||
|
//TODO: error checking
|
||||||
|
$result = Billing::makeRequest($credentials["url"], $invoice_query_string);
|
||||||
|
|
||||||
|
$vat_amount = $result["subtotal"] * (VAT_RATE/100);
|
||||||
|
$invoice_total = $result["total"] + $vat_amount;
|
||||||
|
|
||||||
|
//Second, update the invoice with the VAT amount and updated total
|
||||||
|
$postfields = array();
|
||||||
|
$postfields["username"] = $credentials["username"];
|
||||||
|
$postfields["password"] = md5($credentials["password"]);
|
||||||
|
$postfields["action"] = "updateinvoice";
|
||||||
|
$postfields["invoiceid"] = $invoice_id;
|
||||||
|
$postfields["tax"] = "$vat_amount";
|
||||||
|
$postfields["taxrate"] = strval(VAT_RATE);
|
||||||
|
$postfields["total"] = "$invoice_total";
|
||||||
|
$postfields["responsetype"] = "json";
|
||||||
|
|
||||||
|
$query_string = "";
|
||||||
|
foreach ($postfields as $k=>$v) $query_string .= "$k=".urlencode($v)."&";
|
||||||
|
|
||||||
|
//TODO: error checking
|
||||||
|
$result = Billing::makeRequest($credentials["url"], $query_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
require_once('Billing.php');
|
||||||
define('VAT_RATE', 19.00);
|
define('VAT_RATE', 19.00);
|
||||||
|
|
||||||
class BillingController extends Zend_Controller_Action {
|
class BillingController extends Zend_Controller_Action {
|
||||||
|
@ -23,7 +24,7 @@ class BillingController extends Zend_Controller_Action {
|
||||||
$CC_CONFIG = Config::getConfig();
|
$CC_CONFIG = Config::getConfig();
|
||||||
$baseUrl = Application_Common_OsPath::getBaseDir();
|
$baseUrl = Application_Common_OsPath::getBaseDir();
|
||||||
$this->view->headLink()->appendStylesheet($baseUrl.'css/billing.css?'.$CC_CONFIG['airtime_version']);
|
$this->view->headLink()->appendStylesheet($baseUrl.'css/billing.css?'.$CC_CONFIG['airtime_version']);
|
||||||
BillingController::ensureClientIdIsValid();
|
Billing::ensureClientIdIsValid();
|
||||||
|
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$form = new Application_Form_BillingUpgradeDowngrade();
|
$form = new Application_Form_BillingUpgradeDowngrade();
|
||||||
|
@ -31,18 +32,18 @@ class BillingController extends Zend_Controller_Action {
|
||||||
|
|
||||||
$formData = $request->getPost();
|
$formData = $request->getPost();
|
||||||
if ($form->isValid($formData)) {
|
if ($form->isValid($formData)) {
|
||||||
$credentials = self::getAPICredentials();
|
$credentials = Billing::getAPICredentials();
|
||||||
|
|
||||||
//Check if VAT should be applied or not to this invoice.
|
//Check if VAT should be applied or not to this invoice.
|
||||||
if (in_array("7", $formData["customfields"])) {
|
if (in_array("7", $formData["customfields"])) {
|
||||||
$apply_vat = BillingController::checkIfVatShouldBeApplied($formData["customfields"]["7"], $formData["country"]);
|
$apply_vat = Billing::checkIfVatShouldBeApplied($formData["customfields"]["7"], $formData["country"]);
|
||||||
} else {
|
} else {
|
||||||
$apply_vat = false;
|
$apply_vat = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$placeAnUpgradeOrder = true;
|
$placeAnUpgradeOrder = true;
|
||||||
|
|
||||||
$currentPlanProduct = BillingController::getClientCurrentAirtimeProduct();
|
$currentPlanProduct = Billing::getClientCurrentAirtimeProduct();
|
||||||
$currentPlanProductId = $currentPlanProduct["pid"];
|
$currentPlanProductId = $currentPlanProduct["pid"];
|
||||||
$currentPlanProductBillingCycle = strtolower($currentPlanProduct["billingcycle"]);
|
$currentPlanProductBillingCycle = strtolower($currentPlanProduct["billingcycle"]);
|
||||||
//If there's been no change in the plan or the billing cycle, we should not
|
//If there's been no change in the plan or the billing cycle, we should not
|
||||||
|
@ -61,7 +62,7 @@ class BillingController extends Zend_Controller_Action {
|
||||||
$postfields["action"] = "upgradeproduct";
|
$postfields["action"] = "upgradeproduct";
|
||||||
$postfields["clientid"] = Application_Model_Preference::GetClientId();
|
$postfields["clientid"] = Application_Model_Preference::GetClientId();
|
||||||
|
|
||||||
$postfields["serviceid"] = self::getClientInstanceId();
|
$postfields["serviceid"] = Billing::getClientInstanceId();
|
||||||
$postfields["type"] = "product";
|
$postfields["type"] = "product";
|
||||||
$postfields["newproductid"] = $formData["newproductid"];
|
$postfields["newproductid"] = $formData["newproductid"];
|
||||||
$postfields["newproductbillingcycle"] = $formData["newproductbillingcycle"];
|
$postfields["newproductbillingcycle"] = $formData["newproductbillingcycle"];
|
||||||
|
@ -92,7 +93,7 @@ class BillingController extends Zend_Controller_Action {
|
||||||
foreach ($clientfields AS $k=>$v) $client_query_string .= "$k=".urlencode($v)."&";
|
foreach ($clientfields AS $k=>$v) $client_query_string .= "$k=".urlencode($v)."&";
|
||||||
|
|
||||||
//Update the client details in WHMCS first
|
//Update the client details in WHMCS first
|
||||||
$result = $this->makeRequest($credentials["url"], $client_query_string);
|
$result = Billing::makeRequest($credentials["url"], $client_query_string);
|
||||||
Logging::info($result);
|
Logging::info($result);
|
||||||
if ($result["result"] == "error") {
|
if ($result["result"] == "error") {
|
||||||
$this->setErrorMessage();
|
$this->setErrorMessage();
|
||||||
|
@ -109,7 +110,7 @@ class BillingController extends Zend_Controller_Action {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Then place an upgrade order in WHMCS
|
//Then place an upgrade order in WHMCS
|
||||||
$result = $this->makeRequest($credentials["url"], $upgrade_query_string);
|
$result = Billing::makeRequest($credentials["url"], $upgrade_query_string);
|
||||||
if ($result["result"] == "error") {
|
if ($result["result"] == "error") {
|
||||||
Logging::info($_SERVER['HTTP_HOST']." - Account upgrade failed. - ".$result["message"]);
|
Logging::info($_SERVER['HTTP_HOST']." - Account upgrade failed. - ".$result["message"]);
|
||||||
$this->setErrorMessage();
|
$this->setErrorMessage();
|
||||||
|
@ -123,7 +124,7 @@ class BillingController extends Zend_Controller_Action {
|
||||||
$this->_helper->viewRenderer->setNoRender(true);
|
$this->_helper->viewRenderer->setNoRender(true);
|
||||||
|
|
||||||
if ($apply_vat) {
|
if ($apply_vat) {
|
||||||
$this->addVatToInvoice($result["invoiceid"]);
|
Billing::addVatToInvoice($result["invoiceid"]);
|
||||||
}
|
}
|
||||||
self::viewInvoice($result["invoiceid"]);
|
self::viewInvoice($result["invoiceid"]);
|
||||||
}
|
}
|
||||||
|
@ -149,7 +150,7 @@ class BillingController extends Zend_Controller_Action {
|
||||||
$formData = $request->getPost();
|
$formData = $request->getPost();
|
||||||
|
|
||||||
//Set the return JSON value
|
//Set the return JSON value
|
||||||
$this->_helper->json(array("result"=>BillingController::isCountryInEU($formData["country"])));
|
$this->_helper->json(array("result"=>Billing::isCountryInEU($formData["country"])));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function vatValidatorAction()
|
public function vatValidatorAction()
|
||||||
|
@ -170,135 +171,9 @@ class BillingController extends Zend_Controller_Action {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set the return JSON value
|
//Set the return JSON value
|
||||||
$this->_helper->json(array("result"=>BillingController::checkIfVatShouldBeApplied($vatNumber, $formData["country"])));
|
$this->_helper->json(array("result"=>Billing::checkIfVatShouldBeApplied($vatNumber, $formData["country"])));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return True if VAT should be applied to the order, false otherwise.
|
|
||||||
*/
|
|
||||||
private static function checkIfVatShouldBeApplied($vatNumber, $countryCode)
|
|
||||||
{
|
|
||||||
if ($countryCode === 'UK') {
|
|
||||||
$countryCode = 'GB'; //VIES database has it as GB
|
|
||||||
}
|
|
||||||
//We don't charge you VAT if you're not in the EU
|
|
||||||
if (!BillingController::isCountryInEU($countryCode))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//So by here, we know you're in the EU.
|
|
||||||
|
|
||||||
//No VAT number? Then we charge you VAT.
|
|
||||||
if (empty($vatNumber)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//Check if VAT number is valid
|
|
||||||
return BillingController::validateVATNumber($vatNumber, $countryCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function isCountryInEU($countryCode)
|
|
||||||
{
|
|
||||||
$euCountryCodes = array('BE', 'BG', 'CZ', 'DK', 'DE', 'EE', 'IE', 'EL', 'ES', 'FR',
|
|
||||||
'HR', 'IT', 'CY', 'LV', 'LT', 'LU', 'HU', 'MT', 'NL', 'AT',
|
|
||||||
'PL', 'PT', 'RO', 'SI', 'SK', 'FI', 'SE', 'UK', 'GB');
|
|
||||||
|
|
||||||
if (!in_array($countryCode, $euCountryCodes)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if an EU VAT number is valid, using the EU VIES validation web API.
|
|
||||||
*
|
|
||||||
* @param string $vatNumber - A VAT identifier (number), with or without the two letter country code at the
|
|
||||||
* start (either one works) .
|
|
||||||
* @param string $countryCode - A two letter country code
|
|
||||||
* @return boolean true if the VAT number is valid, false otherwise.
|
|
||||||
*/
|
|
||||||
private static function validateVATNumber($vatNumber, $countryCode)
|
|
||||||
{
|
|
||||||
$vatNumber = str_replace(array(' ', '.', '-', ',', ', '), '', trim($vatNumber));
|
|
||||||
|
|
||||||
//If the first two letters are a country code, use that as the country code and remove those letters.
|
|
||||||
$firstTwoCharacters = substr($vatNumber, 0, 2);
|
|
||||||
if (preg_match("/[a-zA-Z][a-zA-Z]/", $firstTwoCharacters) === 1) {
|
|
||||||
$countryCode = strtoupper($firstTwoCharacters); //The country code from the VAT number overrides your country.
|
|
||||||
$vatNumber = substr($vatNumber, 2);
|
|
||||||
}
|
|
||||||
$client = new SoapClient("http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl");
|
|
||||||
|
|
||||||
if($client){
|
|
||||||
$params = array('countryCode' => $countryCode, 'vatNumber' => $vatNumber);
|
|
||||||
try{
|
|
||||||
$r = $client->checkVat($params);
|
|
||||||
if($r->valid == true){
|
|
||||||
// VAT-ID is valid
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// VAT-ID is NOT valid
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch(SoapFault $e) {
|
|
||||||
Logging::error('VIES EU VAT validation error: '.$e->faultstring);
|
|
||||||
if ($e->faultstring == "INVALID_INPUT") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//If there was another error with the VAT validation service, we allow
|
|
||||||
//the VAT number to pass. (eg. SERVER_BUSY, MS_UNAVAILABLE, TIMEOUT, SERVICE_UNAVAILABLE)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Connection to host not possible, europe.eu down?
|
|
||||||
Logging::error('VIES EU VAT validation error: Host unreachable');
|
|
||||||
//If there was an error with the VAT validation service, we allow
|
|
||||||
//the VAT number to pass.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private function addVatToInvoice($invoice_id)
|
|
||||||
{
|
|
||||||
$credentials = self::getAPICredentials();
|
|
||||||
|
|
||||||
//First we need to get the invoice details: sub total, and total
|
|
||||||
//so we can calcuate the amount of VAT to add
|
|
||||||
$invoicefields = array();
|
|
||||||
$invoicefields["username"] = $credentials["username"];
|
|
||||||
$invoicefields["password"] = md5($credentials["password"]);
|
|
||||||
$invoicefields["action"] = "getinvoice";
|
|
||||||
$invoicefields["invoiceid"] = $invoice_id;
|
|
||||||
$invoicefields["responsetype"] = "json";
|
|
||||||
|
|
||||||
$invoice_query_string = "";
|
|
||||||
foreach ($invoicefields as $k=>$v) $invoice_query_string .= "$k=".urlencode($v)."&";
|
|
||||||
|
|
||||||
//TODO: error checking
|
|
||||||
$result = $this->makeRequest($credentials["url"], $invoice_query_string);
|
|
||||||
|
|
||||||
$vat_amount = $result["subtotal"] * (VAT_RATE/100);
|
|
||||||
$invoice_total = $result["total"] + $vat_amount;
|
|
||||||
|
|
||||||
//Second, update the invoice with the VAT amount and updated total
|
|
||||||
$postfields = array();
|
|
||||||
$postfields["username"] = $credentials["username"];
|
|
||||||
$postfields["password"] = md5($credentials["password"]);
|
|
||||||
$postfields["action"] = "updateinvoice";
|
|
||||||
$postfields["invoiceid"] = $invoice_id;
|
|
||||||
$postfields["tax"] = "$vat_amount";
|
|
||||||
$postfields["taxrate"] = strval(VAT_RATE);
|
|
||||||
$postfields["total"] = "$invoice_total";
|
|
||||||
$postfields["responsetype"] = "json";
|
|
||||||
|
|
||||||
$query_string = "";
|
|
||||||
foreach ($postfields as $k=>$v) $query_string .= "$k=".urlencode($v)."&";
|
|
||||||
|
|
||||||
//TODO: error checking
|
|
||||||
$result = $this->makeRequest($credentials["url"], $query_string);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function setErrorMessage($msg=null)
|
private function setErrorMessage($msg=null)
|
||||||
{
|
{
|
||||||
|
@ -318,21 +193,12 @@ class BillingController extends Zend_Controller_Action {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function getAPICredentials()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
"username" => $_SERVER["WHMCS_USERNAME"],
|
|
||||||
"password" => $_SERVER["WHMCS_PASSWORD"],
|
|
||||||
"url" => "https://account.sourcefabric.com/includes/api.php?accesskey=".$_SERVER["WHMCS_ACCESS_KEY"],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function viewInvoice($invoice_id)
|
private static function viewInvoice($invoice_id)
|
||||||
{
|
{
|
||||||
$whmcsurl = "https://account.sourcefabric.com/dologin.php";
|
$whmcsurl = "https://account.sourcefabric.com/dologin.php";
|
||||||
$autoauthkey = $_SERVER["WHMCS_AUTOAUTH_KEY"];
|
$autoauthkey = $_SERVER["WHMCS_AUTOAUTH_KEY"];
|
||||||
$timestamp = time(); //whmcs timezone?
|
$timestamp = time(); //whmcs timezone?
|
||||||
$client = self::getClientDetails();
|
$client = Billing::getClientDetails();
|
||||||
$email = $client["email"];
|
$email = $client["email"];
|
||||||
$hash = sha1($email.$timestamp.$autoauthkey);
|
$hash = sha1($email.$timestamp.$autoauthkey);
|
||||||
$goto = "viewinvoice.php?id=".$invoice_id;
|
$goto = "viewinvoice.php?id=".$invoice_id;
|
||||||
|
@ -347,12 +213,12 @@ class BillingController extends Zend_Controller_Action {
|
||||||
|
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$form = new Application_Form_BillingClient();
|
$form = new Application_Form_BillingClient();
|
||||||
BillingController::ensureClientIdIsValid();
|
Billing::ensureClientIdIsValid();
|
||||||
if ($request->isPost()) {
|
if ($request->isPost()) {
|
||||||
$formData = $request->getPost();
|
$formData = $request->getPost();
|
||||||
if ($form->isValid($formData)) {
|
if ($form->isValid($formData)) {
|
||||||
|
|
||||||
$credentials = self::getAPICredentials();
|
$credentials = Billing::getAPICredentials();
|
||||||
|
|
||||||
$postfields = array();
|
$postfields = array();
|
||||||
$postfields["username"] = $credentials["username"];
|
$postfields["username"] = $credentials["username"];
|
||||||
|
@ -371,7 +237,7 @@ class BillingController extends Zend_Controller_Action {
|
||||||
$query_string = "";
|
$query_string = "";
|
||||||
foreach ($postfields AS $k=>$v) $query_string .= "$k=".urlencode($v)."&";
|
foreach ($postfields AS $k=>$v) $query_string .= "$k=".urlencode($v)."&";
|
||||||
|
|
||||||
$result = $this->makeRequest($credentials["url"], $query_string);
|
$result = Billing::makeRequest($credentials["url"], $query_string);
|
||||||
|
|
||||||
if ($result["result"] == "error") {
|
if ($result["result"] == "error") {
|
||||||
$this->setErrorMessage();
|
$this->setErrorMessage();
|
||||||
|
@ -394,9 +260,9 @@ class BillingController extends Zend_Controller_Action {
|
||||||
$CC_CONFIG = Config::getConfig();
|
$CC_CONFIG = Config::getConfig();
|
||||||
$baseUrl = Application_Common_OsPath::getBaseDir();
|
$baseUrl = Application_Common_OsPath::getBaseDir();
|
||||||
$this->view->headLink()->appendStylesheet($baseUrl.'css/billing.css?'.$CC_CONFIG['airtime_version']);
|
$this->view->headLink()->appendStylesheet($baseUrl.'css/billing.css?'.$CC_CONFIG['airtime_version']);
|
||||||
|
|
||||||
BillingController::ensureClientIdIsValid();
|
Billing::ensureClientIdIsValid();
|
||||||
$credentials = self::getAPICredentials();
|
$credentials = Billing::getAPICredentials();
|
||||||
|
|
||||||
$postfields = array();
|
$postfields = array();
|
||||||
$postfields["username"] = $credentials["username"];
|
$postfields["username"] = $credentials["username"];
|
||||||
|
@ -408,7 +274,7 @@ class BillingController extends Zend_Controller_Action {
|
||||||
$query_string = "";
|
$query_string = "";
|
||||||
foreach ($postfields AS $k=>$v) $query_string .= "$k=".urlencode($v)."&";
|
foreach ($postfields AS $k=>$v) $query_string .= "$k=".urlencode($v)."&";
|
||||||
|
|
||||||
$result = self::makeRequest($credentials["url"], $query_string);
|
$result = Billing::makeRequest($credentials["url"], $query_string);
|
||||||
|
|
||||||
if ($result["invoices"]) {
|
if ($result["invoices"]) {
|
||||||
$this->view->invoices = $result["invoices"]["invoice"];;
|
$this->view->invoices = $result["invoices"]["invoice"];;
|
||||||
|
@ -419,184 +285,11 @@ class BillingController extends Zend_Controller_Action {
|
||||||
|
|
||||||
public function invoiceAction()
|
public function invoiceAction()
|
||||||
{
|
{
|
||||||
BillingController::ensureClientIdIsValid();
|
Billing::ensureClientIdIsValid();
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$invoice_id = $request->getParam('invoiceid');
|
$invoice_id = $request->getParam('invoiceid');
|
||||||
self::viewInvoice($invoice_id);
|
self::viewInvoice($invoice_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the Airtime instance ID of the instance the customer is currently viewing. */
|
|
||||||
private static function getClientInstanceId()
|
|
||||||
{
|
|
||||||
$currentProduct = BillingController::getClientCurrentAirtimeProduct();
|
|
||||||
return $currentProduct["id"];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getProducts()
|
|
||||||
{
|
|
||||||
//Making this static to cache the products during a single HTTP request.
|
|
||||||
//This saves us roundtrips to WHMCS if getProducts() is called multiple times.
|
|
||||||
static $result = array();
|
|
||||||
if (!empty($result))
|
|
||||||
{
|
|
||||||
return $result["products"]["product"];
|
|
||||||
}
|
|
||||||
|
|
||||||
$credentials = self::getAPICredentials();
|
|
||||||
|
|
||||||
$postfields = array();
|
|
||||||
$postfields["username"] = $credentials["username"];
|
|
||||||
$postfields["password"] = md5($credentials["password"]);
|
|
||||||
$postfields["action"] = "getproducts";
|
|
||||||
$postfields["responsetype"] = "json";
|
|
||||||
//gid is the Airtime product group id on whmcs
|
|
||||||
$postfields["gid"] = "15";
|
|
||||||
|
|
||||||
$query_string = "";
|
|
||||||
foreach ($postfields AS $k=>$v) $query_string .= "$k=".urlencode($v)."&";
|
|
||||||
|
|
||||||
$result = self::makeRequest($credentials["url"], $query_string);
|
|
||||||
//Logging::info($result["products"]["product"]);
|
|
||||||
$products = $result["products"]["product"];
|
|
||||||
|
|
||||||
//Blacklist all free plans
|
|
||||||
foreach ($products as $k => $p) {
|
|
||||||
Logging::info($p);
|
|
||||||
if ($p["paytype"] === "free")
|
|
||||||
{
|
|
||||||
unset($products[$k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $products;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getProductPricesAndTypes()
|
|
||||||
{
|
|
||||||
$products = BillingController::getProducts();
|
|
||||||
|
|
||||||
foreach ($products as $k => $p) {
|
|
||||||
$productPrices[$p["name"]] = array(
|
|
||||||
"monthly" => $p["pricing"]["USD"]["monthly"],
|
|
||||||
"annually" => $p["pricing"]["USD"]["annually"]
|
|
||||||
);
|
|
||||||
$productTypes[$p["pid"]] = $p["name"] . " ($" . $productPrices[$p['name']]['monthly'] . "/mo)";
|
|
||||||
}
|
|
||||||
return array($productPrices, $productTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the plan (or product in WHMCS lingo) that the customer is currently on.
|
|
||||||
* @return An associative array containing the fields for the product
|
|
||||||
* */
|
|
||||||
public static function getClientCurrentAirtimeProduct()
|
|
||||||
{
|
|
||||||
static $airtimeProduct = null;
|
|
||||||
//Ghetto caching to avoid multiple round trips to WHMCS
|
|
||||||
if ($airtimeProduct) {
|
|
||||||
return $airtimeProduct;
|
|
||||||
}
|
|
||||||
$credentials = self::getAPICredentials();
|
|
||||||
|
|
||||||
$postfields = array();
|
|
||||||
$postfields["username"] = $credentials["username"];
|
|
||||||
$postfields["password"] = md5($credentials["password"]);
|
|
||||||
$postfields["action"] = "getclientsproducts";
|
|
||||||
$postfields["responsetype"] = "json";
|
|
||||||
$postfields["clientid"] = Application_Model_Preference::GetClientId();
|
|
||||||
|
|
||||||
$query_string = "";
|
|
||||||
foreach ($postfields AS $k=>$v) $query_string .= "$k=".urlencode($v)."&";
|
|
||||||
|
|
||||||
$result = self::makeRequest($credentials["url"], $query_string);
|
|
||||||
|
|
||||||
//XXX: Debugging / local testing
|
|
||||||
if ($_SERVER['SERVER_NAME'] == "airtime.localhost") {
|
|
||||||
$_SERVER['SERVER_NAME'] = "bananas.airtime.pro";
|
|
||||||
}
|
|
||||||
|
|
||||||
//This code must run on airtime.pro for it to work... it's trying to match
|
|
||||||
//the server's hostname with the client subdomain. Once it finds a match
|
|
||||||
//between the product and the server's hostname/subdomain, then it
|
|
||||||
//returns the ID of that product (aka. the service ID of an Airtime instance)
|
|
||||||
foreach ($result["products"]["product"] as $product)
|
|
||||||
{
|
|
||||||
if (strpos($product["groupname"], "Airtime") === FALSE)
|
|
||||||
{
|
|
||||||
//Ignore non-Airtime products
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ($product["status"] === "Active") {
|
|
||||||
$airtimeProduct = $product;
|
|
||||||
$subdomain = '';
|
|
||||||
|
|
||||||
foreach ($airtimeProduct['customfields']['customfield'] as $customField) {
|
|
||||||
if ($customField['name'] === SUBDOMAIN_WHMCS_CUSTOM_FIELD_NAME) {
|
|
||||||
$subdomain = $customField['value'];
|
|
||||||
if (($subdomain . ".airtime.pro") === $_SERVER['SERVER_NAME']) {
|
|
||||||
return $airtimeProduct;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new Exception("Unable to match subdomain to a service ID");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getClientDetails()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$credentials = self::getAPICredentials();
|
|
||||||
|
|
||||||
$postfields = array();
|
|
||||||
$postfields["username"] = $credentials["username"];
|
|
||||||
$postfields["password"] = md5($credentials["password"]);
|
|
||||||
$postfields["action"] = "getclientsdetails";
|
|
||||||
$postfields["stats"] = true;
|
|
||||||
$postfields["clientid"] = Application_Model_Preference::GetClientId();
|
|
||||||
$postfields["responsetype"] = "json";
|
|
||||||
|
|
||||||
$query_string = "";
|
|
||||||
foreach ($postfields AS $k=>$v) $query_string .= "$k=".urlencode($v)."&";
|
|
||||||
|
|
||||||
$arr = self::makeRequest($credentials["url"], $query_string);
|
|
||||||
return $arr["client"];
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Logging::info($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function makeRequest($url, $query_string) {
|
|
||||||
try {
|
|
||||||
$ch = curl_init();
|
|
||||||
curl_setopt($ch, CURLOPT_URL, $url);
|
|
||||||
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 ); // WHMCS IP whitelist doesn't support IPv6
|
|
||||||
curl_setopt($ch, CURLOPT_POST, 1);
|
|
||||||
curl_setopt($ch, CURLOPT_TIMEOUT, 5); //Aggressive 5 second timeout
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $query_string);
|
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
|
||||||
$jsondata = curl_exec($ch);
|
|
||||||
if (curl_error($ch)) {
|
|
||||||
//die("Connection Error: ".curl_errno($ch).' - '.curl_error($ch));
|
|
||||||
throw new Exception("WHMCS server down or invalid request.");
|
|
||||||
}
|
|
||||||
curl_close($ch);
|
|
||||||
|
|
||||||
return json_decode($jsondata, true);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Logging::info($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function ensureClientIdIsValid()
|
|
||||||
{
|
|
||||||
if (Application_Model_Preference::GetClientId() == null)
|
|
||||||
{
|
|
||||||
throw new Exception("Invalid client ID: " . Application_Model_Preference::GetClientId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ class Application_Form_BillingClient extends Zend_Form
|
||||||
{
|
{
|
||||||
/*$this->setDecorators(array(
|
/*$this->setDecorators(array(
|
||||||
array('ViewScript', array('viewScript' => 'form/billing-purchase.phtml'))));*/
|
array('ViewScript', array('viewScript' => 'form/billing-purchase.phtml'))));*/
|
||||||
$client = BillingController::getClientDetails();
|
$client = Billing::getClientDetails();
|
||||||
$this->setAttrib("id", "clientdetails_form");
|
$this->setAttrib("id", "clientdetails_form");
|
||||||
|
|
||||||
$notEmptyValidator = Application_Form_Helper_ValidationTypes::overrideNotEmptyValidator();
|
$notEmptyValidator = Application_Form_Helper_ValidationTypes::overrideNotEmptyValidator();
|
||||||
|
|
|
@ -5,9 +5,9 @@ class Application_Form_BillingUpgradeDowngrade extends Zend_Form
|
||||||
{
|
{
|
||||||
$productPrices = array();
|
$productPrices = array();
|
||||||
$productTypes = array();
|
$productTypes = array();
|
||||||
list($productPrices, $productTypes) = BillingController::getProductPricesAndTypes();
|
list($productPrices, $productTypes) = Billing::getProductPricesAndTypes();
|
||||||
|
|
||||||
$currentPlanProduct = BillingController::getClientCurrentAirtimeProduct();
|
$currentPlanProduct = Billing::getClientCurrentAirtimeProduct();
|
||||||
$currentPlanProductId = $currentPlanProduct["pid"];
|
$currentPlanProductId = $currentPlanProduct["pid"];
|
||||||
|
|
||||||
$currentPlanProductBillingCycle = $currentPlanProduct["billingcycle"];
|
$currentPlanProductBillingCycle = $currentPlanProduct["billingcycle"];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
require_once 'php-amqplib/amqp.inc';
|
require_once 'php-amqplib/amqp.inc';
|
||||||
require_once 'Amazon_S3.php';
|
require_once 'Amazon_S3StorageBackend.php';
|
||||||
|
|
||||||
class Application_Model_RabbitMq
|
class Application_Model_RabbitMq
|
||||||
{
|
{
|
||||||
|
@ -81,7 +81,7 @@ class Application_Model_RabbitMq
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function SendMessageToAnalyzer($tmpFilePath, $importedStorageDirectory, $originalFilename,
|
public static function SendMessageToAnalyzer($tmpFilePath, $importedStorageDirectory, $originalFilename,
|
||||||
$callbackUrl, $apiKey, $currentStorageBackend)
|
$callbackUrl, $apiKey, $currentStorageBackend, $filePrefix)
|
||||||
{
|
{
|
||||||
//Hack for Airtime Pro. The RabbitMQ settings for communicating with airtime_analyzer are global
|
//Hack for Airtime Pro. The RabbitMQ settings for communicating with airtime_analyzer are global
|
||||||
//and shared between all instances on Airtime Pro.
|
//and shared between all instances on Airtime Pro.
|
||||||
|
@ -118,7 +118,7 @@ class Application_Model_RabbitMq
|
||||||
// customer's file/s; File restoration is done via the S3 Browser
|
// customer's file/s; File restoration is done via the S3 Browser
|
||||||
// client. The client will hang if there are too many files under the
|
// client. The client will hang if there are too many files under the
|
||||||
// same folder.
|
// same folder.
|
||||||
$data['file_prefix'] = Amazon_S3::getAmazonS3FilePrefix();
|
$data['file_prefix'] = $filePrefix;
|
||||||
|
|
||||||
$jsonData = json_encode($data);
|
$jsonData = json_encode($data);
|
||||||
//self::sendMessage($exchange, 'topic', false, $jsonData, 'airtime-uploads');
|
//self::sendMessage($exchange, 'topic', false, $jsonData, 'airtime-uploads');
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
require_once 'ProxyStorageBackend.php';
|
||||||
|
|
||||||
class Rest_MediaController extends Zend_Rest_Controller
|
class Rest_MediaController extends Zend_Rest_Controller
|
||||||
{
|
{
|
||||||
const MUSIC_DIRS_STOR_PK = 1;
|
const MUSIC_DIRS_STOR_PK = 1;
|
||||||
|
@ -368,9 +370,11 @@ class Rest_MediaController extends Zend_Rest_Controller
|
||||||
|
|
||||||
//Dispatch a message to airtime_analyzer through RabbitMQ,
|
//Dispatch a message to airtime_analyzer through RabbitMQ,
|
||||||
//notifying it that there's a new upload to process!
|
//notifying it that there's a new upload to process!
|
||||||
|
$storageBackend = new ProxyStorageBackend($CC_CONFIG["current_backend"]);
|
||||||
Application_Model_RabbitMq::SendMessageToAnalyzer($newTempFilePath,
|
Application_Model_RabbitMq::SendMessageToAnalyzer($newTempFilePath,
|
||||||
$importedStorageDirectory, basename($originalFilename),
|
$importedStorageDirectory, basename($originalFilename),
|
||||||
$callbackUrl, $apiKey, $CC_CONFIG["current_backend"]);
|
$callbackUrl, $apiKey, $CC_CONFIG["current_backend"],
|
||||||
|
$storageBackend->getFilePrefix());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getOwnerId()
|
private function getOwnerId()
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
<?php echo("var products = " . json_encode(BillingController::getProducts()) . ";\n");
|
<?php echo("var products = " . json_encode(Billing::getProducts()) . ";\n");
|
||||||
echo("var vatRate = " . json_encode(VAT_RATE) . ";");
|
echo("var vatRate = " . json_encode(VAT_RATE) . ";");
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
@ -255,7 +255,7 @@ $(document).ready(function() {
|
||||||
-->
|
-->
|
||||||
<p id="current_plan"><b>Current Plan:</b>
|
<p id="current_plan"><b>Current Plan:</b>
|
||||||
<?php
|
<?php
|
||||||
$currentProduct = BillingController::getClientCurrentAirtimeProduct();
|
$currentProduct = Billing::getClientCurrentAirtimeProduct();
|
||||||
echo($currentProduct["name"]);
|
echo($currentProduct["name"]);
|
||||||
//echo Application_Model_Preference::GetPlanLevel();
|
//echo Application_Model_Preference::GetPlanLevel();
|
||||||
?>
|
?>
|
||||||
|
|
Loading…
Reference in New Issue