Jump to content

Kangaroo

Members
  • Posts

    132
  • Joined

  • Last visited

  • Days Won

    1

Reputation Activity

  1. Like
    Kangaroo reacted to Squidix Web Hosting in Search Service Fields In Smart Search   
    Thanks!
  2. Like
    Kangaroo reacted to Tyson in Blesta Module And Plugin Developer   
    I think this will be easier once the marketplace is available, where developers can list each of them for download.
  3. Like
    Kangaroo reacted to Joseph H in Blesta Module And Plugin Developer   
    I've worked with him fixing a module. He is good, I personally trust his abilities.
  4. Like
    Kangaroo reacted to Wouter in Sad State Of Domain Management And Blesta   
    Today I started developing our custom code for Blesta, because we're coming from WHMCS where we created much custom code for. Now, I see this "bad" (when I compare it to WHMCS) domain management, I can't continue to switch to Blesta because of this.   

    I hope a better domain management will being implemented in the near future. I don't think you'll need to do this per module, which will get very messy over time (all different way's of handling things).
     
    My ideas for the domain management, which you may consider while implementing this:
    - Centralized WHOIS information over multiple registries, with ability to "override" this for a specific domain by the customer.
    - Centralized nameservers over multiple registries, with ability to "override" this for a specific domain by the customer.
    - Proper transfer handling (including a cron).
    - TLD syncing with automated price updates
    - WHOIS through the preferred registry for a TLD
    - Some TLD's have different requirements (e.g. a domain needs to be renewed x days before expiry).
     
    Thanks! 
  5. Like
    Kangaroo reacted to Cody in Support Manager Last Reply   
    Excellent. Closing this as fixed for 3.0.4 (CORE-781).
  6. Like
    Kangaroo reacted to Paul in Requesting A Feature: Please Read Before Posting!   
    Please post 1 feature request per thread, and include as much information about the feature as possible.
     
    Having 1 feature request per thread allows the thread to focus entirely on that feature. One of our goals is to gauge community interest in a particular feature, which helps us prioritize the feature if we decide to add it. If we do add the feature to our project management system, we will usually post a task ID associated with it. The feature can then be tracked in the thread to completion.
     
    Posting multiple feature requests in a single thread waters down the request, and it will usually receive fewer responses. So, sticking to 1 request per thread increases the odds of it being implemented! 
  7. Like
    Kangaroo got a reaction from PauloV in [Plugin] Support Manager Pro - Tickets Delete, Merge, Spam, Multiple Tickets.   
    I have all faith it will work fine. Thanks for the reply.
  8. Like
    Kangaroo reacted to Kangaroo in [Plugin] Support Manager Pro - Tickets Delete, Merge, Spam, Multiple Tickets.   
    I have all faith it will work fine. Thanks for the reply.
  9. Like
    Kangaroo got a reaction from PauloV in Support Manager Pro   
    is the support manager pro working well ? Is there any updates for 3.5 ? Will it work better than the existing support Extension ?
  10. Like
    Kangaroo reacted to Tyson in Edit Client Info When Logged From Admin Side   
    Thanks for the info. This issue was also reported in another thread, and has been fixed in CORE-1699, currently available in v3.5.0. I would recommend upgrading to the latest version of Blesta, or updating client information from the admin interface instead.
  11. Like
    Kangaroo reacted to Cody in Release 3.5.0   
    Version 3.5.0 is now available. You can download it in the Client Area.

    Installing Blesta

    See Installing Blesta in the User Manual for instructions.

    Upgrading Blesta

    See Upgrading Blesta in the User Manual for instructions.

    Migrating to Blesta

    See Migrating to Blesta in the User Manual for instructions.

    Overview
    Upgrade/Downgrade Config Options SolusVM Improvements Custom Reports Much more... PHP 5.5+ Users

    Included in this release is a /hotfix-php5.5/ directory. Please use this directory to overwrite the default /blesta/app/app_controller.php, /blesta/app/app_model.php, and /blesta/app/models/license.php files.

    Release Notes

    See Blesta Core - Version 3.5.0-b1.
    See Blesta Core - Version 3.5.0-b2.
    See Blesta Core - Version 3.5.0-b3.
    See Blesta Core - Version 3.5.0-b4.
    See Blesta Core - Version 3.5.0-b5.
    See Blesta Core - Version 3.5.0.
    For older releases see all Change Logs.
  12. Like
    Kangaroo reacted to Joseph H in Blesta Module And Plugin Developer   
    I completely Agree with you @Naja7host , some of us create modules but never wan't to share worrying of a competitor getting an advantage.
     
    We do need more premium modules/plugins for Blesta, Sometimes developing modules is too expensive if you need a lof of modules like i do, but having a place to buy modules will be cheaper for me as the client and will be much profitable for the developer I believe. and will surely remove this 
     
  13. Like
    Kangaroo reacted to Blesta Addons in Blesta Module And Plugin Developer   
    and what about the custom works ?
     
    i know there are a lot of module/plugins already done by devs but is not available for other clients .
     
    i have some that will be or other maybe for free and some PAID , but not now .
     
    when i client hire me to develop a module/plugin and tell me that the work should not be selled to others, i never never accept . i accept only if the client accept my two conditions
     
    1 - i have the right to sell the work (module/plugin) to others after X mounth from finishing the work .
    2 - i have the right to publish the work freely after X mounth from finishing the work .
     
    for my vision, the client pay for the service and not for my CODE . i can conserve the work in the background and releasing it only if a i found/feel that work is for a MADE-HOUSE custom solution .
     
    so be happy , ihave some modules/plugins will be for the community in some next mounths
  14. Like
    Kangaroo reacted to Michael in Blesta Module And Plugin Developer   
    We've got a small list here: https://licensecart.com/community-addons
  15. Like
    Kangaroo got a reaction from Serendesk in Tester Available For Blesta Existing Users   
    hi there,
     
    I would like to offer my services to test peoples ordering system. To screen shot different parts of the ordering system and the email I receive.
     
    I think this would be great.
     
    There is no charge for this service Just a little love around here.
     
    I hope this is the right thread to paste this into.
     
    Cheers,
    Tom
  16. Like
    Kangaroo reacted to Joseph H in Sad State Of Domain Management And Blesta   
    It's true that the domain management side is still far behind, but one thing we are all hoping Is When it comes out It will be superb. I believe Blesta knows how Important such features are to any hosting Business.
  17. Like
    Kangaroo reacted to eXtremeSHOK in Sad State Of Domain Management And Blesta   
    Lets face the fact Blesta's domain management is TOTAL CRAP.. WHMCS and Clientexec do it way better in every way.
     
    Blesta does NOT have a proper domain offering, period. seems to be that its just not a priority.
     
    Domains are totally unique to generic products and should be treaded as such.
     
    For webhosters, domains are part of hosting, the most important part.
      The enom module for Blesta is 10 years behind that of WHMCS..currently we have the bare minimal basics.
      What if one wants to only sell a domain ? Does not appear blesta support domain only products.  
    Domain Transfers ?
     
    Renew pricing ? Allot of domain renewals cost more than the initial registration fee
     
    Name spinning ?
     
    Importing and sync of prices from enom & namecheap ?
     
    Importing and sync of TLD's and new TLD's from enom & namecheap ?
     
    What about .co.uk that requires a 90day before expire renew ?
     
    Direct managment of the domain hosted on the registrars nameserver ?
     
    Proper whois lookup or usage of dig to check if non api domains are registered/available ?
     
    A domain email module, where domain orders are emailed, still does whois checking for availability. Some tld's are still stuck in 1970.
     
    Domain availability widget ?
     
    ^^ BLESTA FAILS FOR ALL OF THE ABOVE
     
    ---
     
    I challenge Blesta to make a billing brawl using domain management and include enom's module...
       
    btw if you want a reseller enom account, or access to the enom api sandbox , contact me and ill sort you out with an account.
  18. Like
    Kangaroo got a reaction from Paul in Greetings From Melbourne   
    Its great to be alive. God bless Blesta.
  19. Like
    Kangaroo got a reaction from Paul in Stuck When Importing.   
    Struggled like a litle B* but  F* you whmcs here's the file used if anyone else has this issue.
    <?php /** * Generic WHMCS Migrator * * @package blesta * @subpackage blesta.plugins.import_manager.components.migrators.whmcs * @copyright Copyright (c) 2010, Phillips Data, Inc. * @license http://www.blesta.com/license/'>http://www.blesta.com/license/ The Blesta License Agreement * @link http://www.blesta.com/ Blesta */ class WhmcsMigrator extends Migrator { /** * @var array An array of settings */ protected $settings; /** * @var boolean True to fetch all records instead of looping through PDOStatement */ protected $fetchall = false; /** * @var boolean Enable/disable debugging */ protected $enable_debug = false; /** * @var string The default country */ private $default_country = "US"; /** * @var string The default first name */ private $default_firstname = "unknown"; /** * @var string The default last name */ private $default_lastname = "unknown"; /** * @var array An array of credits */ private $credits = array(); private $default_currency = "AUD"; /** * Runs the import, sets any Input errors encountered */ public function import() { Loader::loadModels($this, array("Companies")); Configure::set("Whmcs.import_fetchall", false); if (Configure::get("Whmcs.import_fetchall")) { $this->fetchall = true; ini_set("memory_limit", "512M"); } $actions = array( "importStaff", // works "importClients", // works "importContacts", // works "importTaxes", // works "importCurrencies", // works "importInvoices", // works "importTransactions", // works "importPackages", // works "importPackageOptions", // works "importServices", // works "importSupportDepartments", // works "importSupportTickets", // works "importMisc" // works ); // I hate WHMCS!!!!!!!! $errors = array(); $this->startTimer("total time"); $this->decrypt_count = 0; $this->startTimer("decrypt"); $this->pauseTimer("decrypt"); foreach ($actions as $action) { try { // Only import packages if no mappings exist if ($action == "importPackages" && isset($this->mappings['packages'])) continue; $this->debug($action); $this->debug("-----------------"); $this->startTimer($action); $this->{$action}(); $this->endTimer($action); $this->debug("-----------------\n"); } catch (Exception $e) { $errors[] = $action . ": " . $e->getMessage() . " on line " . $e->getLine(); } } if (!empty($errors)) { array_unshift($errors, Language::_("Whmcs5_2.!error.import", true)); $this->Input->setErrors(array('error' => $errors)); } $this->debug("decrypted " . $this->decrypt_count . " values using WHMCS' custom algorithm"); $this->endTimer("decrypt"); $this->endTimer("total time"); if ($this->enable_debug) { $this->debug(print_r($this->Input->errors(), true)); exit; } } /** * Import staff */ protected function importStaff() { Loader::loadModels($this, array("StaffGroups")); Loader::loadModels($this, array("Users")); $this->loadModel("WhmcsAdmins"); // Create "Support" staff group (no permissions) $staff_group = array( 'company_id' => Configure::get("Blesta.company_id"), 'name' => "Support", 'permission_group' => array(), 'permission' => array() ); $this->StaffGroups->add($staff_group); $staff_groups = $this->StaffGroups->getAll(Configure::get("Blesta.company_id")); $groups = array(); foreach ($staff_groups as $group) { if ($group->name == "Administrators") { $groups[0] = $group->id; $groups[1] = $group->id; } elseif ($group->name == "Billing") { $groups[2] = $group->id; } elseif ($group->name == "Support") { $groups[3] = $group->id; } } $admins = $this->fetchall ? $this->WhmcsAdmins->get()->fetchAll() : $this->WhmcsAdmins->get(); foreach ($admins as $admin) { $this->Users->begin(); // Set aside assigned support departments $this->mappings['admin_departs'][$admin->id] = $admin->supportdepts; try { $user_id = $this->createUser(array( 'username' => $this->decode($admin->username), 'password' => $admin->password, 'date_added' => $this->Users->dateToUtc(date("c")) )); $vars = array( 'user_id' => $user_id, 'first_name' => $this->decode($admin->firstname), 'last_name' => $this->decode($admin->lastname), 'email' => $this->decode($admin->email), 'status' => $admin->disabled == "0" ? "active" : "inactive", 'groups' => isset($groups[$admin->roleid]) ? array($groups[$admin->roleid]) : null ); $staff_id = $this->addStaff($vars, $admin->id); if ($staff_id) $this->Users->commit(); else $this->Users->rollback(); } catch (Exception $e) { $this->local->reset(); $this->Users->rollback(); } } unset($admins); } /** * Import clients */ protected function importClients() { Loader::loadModels($this, array("Accounts", "Clients", "ClientGroups")); $this->loadModel("WhmcsClients"); // Initialize crypto (AES in ECB) Loader::loadComponents($this, array("Security")); $aes = $this->Security->create("Crypt", "AES", array(1)); // 1 = CRYPT_AES_MODE_ECB $aes->disablePadding(); // Set default client group $client_groups = $this->ClientGroups->getAll(Configure::get("Blesta.company_id")); $this->mappings['client_groups'][0] = $client_groups[0]->id; // Import client groups $groups = $this->fetchall ? $this->WhmcsClients->getGroups()->fetchAll() : $this->WhmcsClients->getGroups(); foreach ($groups as $group) { $group_id = $this->ClientGroups->add(array( 'name' => $this->decode($group->groupname), 'company_id' => Configure::get("Blesta.company_id"), 'color' => str_replace("#", "", $group->groupcolour) )); $this->mappings['client_groups'][$group->id] = $group_id; } unset($groups); // Import clients $clients = $this->fetchall ? $this->WhmcsClients->get()->fetchAll() : $this->WhmcsClients->get(); $this->local->begin(); foreach ($clients as $client) { // Create user $user_id = null; try { $user_id = $this->createUser(array( 'username' => $this->decode($client->email), 'password' => $client->password, 'date_added' => $client->datecreated )); } catch (Exception $e) { $this->local->reset(); } if (!$user_id) continue; // Create client $vars = array( 'id_format' => "{num}", 'id_value' => $client->id, 'user_id' => $user_id, 'client_group_id' => $this->mappings['client_groups'][$client->groupid], 'status' => strtolower($client->status) == "closed" ? "inactive" : "active" ); $this->local->insert("clients", $vars); $client_id = $this->local->lastInsertId(); $this->mappings['clients'][$client->id] = $client_id; // Create primary contact $vars = array( 'client_id' => $client_id, 'contact_type' => "primary", 'first_name' => $this->decode(trim($client->firstname) != "" ? $client->firstname : $this->default_firstname), 'last_name' => $this->decode(trim($client->lastname) != "" ? $client->lastname : $this->default_lastname), 'company' => $this->decode($client->companyname != "" ? $client->companyname : null), 'email' => $this->decode($client->email), 'address1' => $this->decode($client->address1), 'address2' => $this->decode($client->address2 != "" ? $client->address2 : null), 'city' => $this->decode($client->city), 'state' => $client->state != "" ? substr($client->state, 0, 3) : null, 'zip' => $this->decode($client->postcode != "" ? $client->postcode : null), 'country' => $client->country != "" ? $client->country : $this->default_country, 'date_added' => $this->Companies->dateToUtc($client->datecreated) ); $this->local->insert("contacts", $vars); $contact_id = $this->local->lastInsertId(); $this->mappings['primary_contacts'][$client->id] = $contact_id; // Save client settings $settings = array( 'autodebit' => $client->disableautocc == "on" ? "false" : "true", 'autosuspend' => "true", 'default_currency' => $client->currency_code, 'inv_address_to' => $contact_id, 'inv_method' => "email", 'language' => "en_us", 'tax_exempt' => $client->taxexempt == "on" ? "true" : "false", 'tax_id' => null, 'username_type' => "email" ); $this->Clients->setSettings($client_id, $settings); // Add contact phone number if ($client->phonenumber != "") { $vars = array( 'contact_id' => $contact_id, 'number' => $this->decode($client->phonenumber), 'type' => "phone", 'location' => "home" ); $this->local->insert("contact_numbers", $vars); } $aes->setKey($this->mysqlAesKey(md5($this->settings['key'] . $client->id))); if ($client->cardnum != "") $client->cardnum = $aes->decrypt($client->cardnum); if ($client->expdate != "") $client->expdate = $aes->decrypt($client->expdate); if ($client->bankacct != "") $client->bankacct = $aes->decrypt($client->bankacct); if ($client->bankcode != "") $client->bankcode = $aes->decrypt($client->bankcode); // Add the payment account if ($client->cardnum != "") { $vars = array( 'contact_id' => $this->mappings['primary_contacts'][$client->id], 'first_name' => $this->decode(trim($client->firstname) != "" ? $client->firstname : $this->default_firstname), 'last_name' => $this->decode(trim($client->lastname) != "" ? $client->lastname : $this->default_lastname), 'address1' => $this->decode($client->address1 != "" ? $client->address1 : null), 'address2' => $this->decode($client->address2 != "" ? $client->address2 : null), 'city' => $this->decode($client->city != "" ? $client->city : null), 'state' => $this->decode($client->state != "" ? $client->state : null), 'zip' => $this->decode($client->postcode != "" ? $client->postcode : null), 'country' => $client->country != "" ? $client->country : $this->default_country, 'number' => $client->cardnum, 'expiration' => "20" . substr($client->expdate, 2, 2) . substr($client->expdate, 0, 2) ); $account_id = $this->Accounts->addCc($vars); // Set account for autodebit if ($account_id) { $vars = array( 'client_id' => $this->mappings['clients'][$client->id], 'account_id' => $account_id, 'type' => "cc" ); $this->local->insert("client_account", $vars); } } } $this->local->commit(); unset($clients); // Import custom client fields $custom_fields = $this->WhmcsClients->getCustomFields()->fetchAll(); $this->local->begin(); foreach ($custom_fields as $custom_field) { // Add each field to each client group foreach ($this->mappings['client_groups'] as $remote_group_id => $group_id) { $vars = array( 'client_group_id' => $group_id, 'name' => $this->decode($custom_field->fieldname), 'type' => $this->getFieldType($this->decode($custom_field->fieldtype)), 'values' => $this->getFieldValues($this->decode($custom_field->fieldoptions)), 'regex' => $this->decode($custom_field->regexpr != "" ? $custom_field->regexpr : null), 'show_client' => $custom_field->adminonly == "on" ? "0" : "1" ); $this->local->insert("client_fields", $vars); $this->mappings['client_fields'][$custom_field->id][$remote_group_id] = $this->local->lastInsertId(); } // Insert custom client values for this field $custom_values = $this->fetchall ? $this->WhmcsClients->getCustomFieldValues($custom_field->id)->fetchAll() : $this->WhmcsClients->getCustomFieldValues($custom_field->id); foreach ($custom_values as $custom_value) { if (!isset($this->mappings['clients'][$custom_value->relid])) continue; $vars = array( 'client_field_id' => $this->mappings['client_fields'][$custom_field->id][$custom_value->groupid], 'client_id' => $this->mappings['clients'][$custom_value->relid], 'value' => $this->decode($custom_value->value) ); $this->local->duplicate("value", "=", $vars['value'])->insert("client_values", $vars); } unset($custom_values); } $this->local->commit(); // Import client notes $notes = $this->fetchall ? $this->WhmcsClients->getNotes()->fetchAll() : $this->WhmcsClients->getNotes(); $this->local->begin(); foreach ($notes as $note) { if (!isset($this->mappings['clients'][$note->userid])) continue; $note->note = $this->decode($note->note); $title = wordwrap($note->note, 32, "\n", true); if (strpos($title, "\n") > 0) $title = substr($title, 0, strpos($title, "\n")); $vars = array( 'client_id' => $this->mappings['clients'][$note->userid], 'staff_id' => isset($this->mappings['staff'][$note->adminid]) ? $this->mappings['staff'][$note->adminid] : 0, 'title' => $title, 'description' => trim($title) == trim($note->note) ? null : $note->note, 'stickied' => $note->sticky ? 1 : 0, 'date_added' => $this->Companies->dateToUtc($note->created), 'date_updated' => $this->Companies->dateToUtc($note->modified) ); $this->local->insert("client_notes", $vars); } $this->local->commit(); unset($notes); } /** * Import contacts */ protected function importContacts() { $this->loadModel("WhmcsContacts"); $contacts = $this->fetchall ? $this->WhmcsContacts->get()->fetchAll() : $this->WhmcsContacts->get(); $this->local->begin(); foreach ($contacts as $contact) { $vars = array( 'client_id' => $this->mappings['clients'][$contact->userid], 'contact_type' => "billing", 'first_name' => $this->decode($contact->firstname), 'last_name' => $this->decode($contact->lastname), 'company' => $this->decode($contact->companyname != "" ? $contact->companyname : null), 'email' => $this->decode($contact->email), 'address1' => $this->decode($contact->address1 != "" ? $contact->address1 : null), 'address2' => $this->decode($contact->address2 != "" ? $contact->address2 : null), 'city' => $this->decode($contact->city != "" ? $contact->city : null), 'state' => $this->decode($contact->state != "" ? substr($contact->state, 0, 3) : null), 'zip' => $this->decode($contact->postcode != "" ? $contact->postcode : null), 'country' => $contact->country != "" ? $contact->country : $this->default_country, 'date_added' => $this->Companies->dateToUtc(date("c")) ); $this->local->insert("contacts", $vars); $contact_id = $this->local->lastInsertId(); $this->mappings['contacts'][$contact->id] = $contact_id; // Add contact phone number if ($contact->phonenumber != "") { $vars = array( 'contact_id' => $contact_id, 'number' => $this->decode($contact->phonenumber), 'type' => "phone", 'location' => "home" ); $this->local->insert("contact_numbers", $vars); } } $this->local->commit(); unset($contacts); } /** * Import taxes */ protected function importTaxes() { $this->loadModel("WhmcsTaxes"); $taxes = $this->fetchall ? $this->WhmcsTaxes->get()->fetchAll() : $this->WhmcsTaxes->get(); $this->local->begin(); foreach ($taxes as $tax) { $state = $this->local->select()->from("states")-> where("country_alpha2", "=", $tax->country)-> where("name", "=", trim($tax->state))->fetch(); $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'level' => $tax->level, 'name' => $this->decode($tax->name), 'state' => $state ? $state->code : null, 'country' => $tax->country != "" ? $tax->country : null, 'amount' => $tax->taxrate ); $this->local->insert("taxes", $vars); $tax_id = $this->local->lastInsertId(); $this->mappings['taxes'][$tax->id] = $tax_id; } $this->local->commit(); unset($taxes); } /** * Import currencies */ protected function importCurrencies() { $this->loadModel("WhmcsCurrencies"); $currencies = $this->fetchall ? $this->WhmcsCurrencies->get()->fetchAll() : $this->WhmcsCurrencies->get(); foreach ($currencies as $currency) { $vars = array( 'code' => $currency->code, 'company_id' => Configure::get("Blesta.company_id"), 'format' => $this->getCurrencyFormat((int)$currency->format), 'prefix' => $this->decode($currency->prefix != "" ? $currency->prefix : null), 'suffix' => $this->decode($currency->suffix != "" ? $currency->suffix : null), 'exchange_rate' => $currency->rate, 'exchange_updated' => null ); $this->local-> duplicate("format", "=", $vars['format'])-> duplicate("prefix", "=", $vars['prefix'])-> duplicate("suffix", "=", $vars['suffix'])-> duplicate("exchange_rate", "=", $vars['exchange_rate'])-> insert("currencies", $vars); // Set default currency if ($currency->default == "1") { $this->Companies->setSetting(Configure::get("Blesta.company_id"), "default_currency", $currency->code); } } unset($currencies); } /** * Import invoices */ protected function importInvoices() { $this->loadModel("WhmcsConfiguration"); $this->loadModel("WhmcsInvoices"); Loader::loadModels($this, array("Invoices")); $cascade_tax = false; // Get compound tax setting $cascade = $this->WhmcsConfiguration->get("TaxL2Compound")->fetch(); if ($cascade && $cascade->value == "on") $cascade_tax = true; $invoices = $this->fetchall ? $this->WhmcsInvoices->get()->fetchAll() : $this->WhmcsInvoices->get(); $this->local->begin(); foreach ($invoices as $invoice) { // Get tax rules $level1 = $this->getTaxRule(1, $invoice->taxrate); $level2 = $this->getTaxRule(2, $invoice->taxrate2); $status = "active"; switch (strtolower($invoice->status)) { case "refunded": case "cancelled": $status = "void"; break; default: $status = "active"; break; } if (!$invoice->currency) { $invoice->currency = "AUD"; } $vars = array( 'id_format' => $this->decode($invoice->invoicenum != "" ? $invoice->invoicenum : "{num}"), 'id_value' => $invoice->invoicenum != "" ? 0 : $invoice->id, 'client_id' => $this->mappings['clients'][$invoice->userid], 'date_billed' => $this->Companies->dateToUtc($invoice->date), 'date_due' => $this->Companies->dateToUtc($invoice->duedate), 'date_closed' => strtolower($invoice->status) != "paid" || $invoice->datepaid == "0000-00-00 00:00:00" ? null : $this->Companies->dateToUtc($invoice->datepaid), 'date_autodebit' => null, 'status' => $status, 'previous_due' => 0, 'currency' => $invoice->currency, 'note_public' => $invoice->notes, 'note_private' => null, ); // Manually add the invoice so we can set the correct tax IDs and invoice ID $this->local->insert("invoices", $vars); $local_invoice_id = $this->local->lastInsertId(); $this->mappings['invoices'][$invoice->id] = $local_invoice_id; $this->mappings['invoice_tax_rules'][$invoice->id] = array( 'level1' => $level1, 'level2' => $level2 ); if (!$invoice->currency) { $invoice->currency = "AUD"; } if ($invoice->credit > 0) { $this->credits[] = array( 'invoice_id' => $local_invoice_id, 'client_id' => $this->mappings['clients'][$invoice->userid], 'amount' => $invoice->credit, 'currency' => $invoice->currency, 'transaction_id' => "invoice credit", 'transaction_type' => "other", 'transaction_type_id' => $this->getTransactionTypeId("in_house_credit"), 'status' => 'approved', 'date_added' => $this->Companies->dateToUtc($invoice->date, "c") ); } } $this->local->commit(); unset($invoices); // Import line items $lines = $this->fetchall ? $this->WhmcsInvoices->getLines()->fetchAll() : $this->WhmcsInvoices->getLines(); $this->local->begin(); foreach ($lines as $line) { if (!isset($this->mappings['invoices'][$line->invoiceid])) continue; // Import lines $vars = array( 'invoice_id' => $this->mappings['invoices'][$line->invoiceid], 'service_id' => null, 'description' => $this->decode($line->description), 'qty' => 1, 'amount' => $line->amount, 'order' => 0 ); $this->local->insert("invoice_lines", $vars); $line_id = $this->local->lastInsertId(); // Import tax lines if ($line->taxed > 0) { if ($this->mappings['invoice_tax_rules'][$line->invoiceid]['level1']) { $vars = array( 'line_id' => $line_id, 'tax_id' => $this->mappings['invoice_tax_rules'][$line->invoiceid]['level1']->id ); $this->local->insert("invoice_line_taxes", $vars); } if ($this->mappings['invoice_tax_rules'][$line->invoiceid]['level2']) { $vars = array( 'line_id' => $line_id, 'tax_id' => $this->mappings['invoice_tax_rules'][$line->invoiceid]['level2']->id, 'cascade' => $cascade_tax ? 1 : 0 ); $this->local->insert("invoice_line_taxes", $vars); } } } $this->local->commit(); unset($lines); // Update totals if (isset($this->mappings['invoices'])) { foreach ($this->mappings['invoices'] as $remote_invoice_id => $local_invoice_id) { $subtotal = $this->Invoices->getSubtotal($local_invoice_id); $total = $this->Invoices->getTotal($local_invoice_id); $this->local->where("id", "=", $local_invoice_id)-> update("invoices", array('subtotal' => $subtotal, 'total' => $total)); } } $periods = array( 'Days' => "day", 'Weeks' => "week", 'Months' => "month", 'Years' => "year" ); // Import recurring invoices $lines = $this->fetchall ? $this->WhmcsInvoices->getRecurringLines()->fetchAll() : $this->WhmcsInvoices->getRecurringLines(); $this->local->begin(); foreach ($lines as $line) { if (!$line->currency) { $line->currency = "AUD"; } if (!isset($periods[$line->recurcycle])) continue; $vars = array( 'client_id' => $this->mappings['clients'][$line->userid], 'term' => $line->recur, 'period' => $periods[$line->recurcycle], 'duration' => $line->recurfor > 0 ? $line->recurfor : null, 'date_renews' => $this->Companies->dateToUtc($line->duedate), 'currency' => $line->currency, 'lines' => array( array( 'description' => $this->decode($line->description), 'qty' => 1, 'amount' => $line->amount, 'tax' => 0 ) ), 'delivery' => array('email') ); $recurring_id = $this->Invoices->addRecurring($vars); if ($recurring_id) $this->mappings['recurring_invoices'][$line->id] = $recurring_id; } $this->local->commit(); unset($lines); if (isset($this->mappings['recurring_invoices'])) { // Record each recurring invoice instance $this->local->begin(); foreach ($this->mappings['recurring_invoices'] as $remote_id => $recurring_id) { $lines = $this->fetchall ? $this->WhmcsInvoices->getRecurInstances($remote_id)->fetchAll() : $this->WhmcsInvoices->getRecurInstances($remote_id); foreach ($lines as $line) { $vars = array( 'invoice_recur_id' => $recurring_id, 'invoice_id' => $this->mappings['invoices'][$line->invoiceid] ); $this->local->insert("invoices_recur_created", $vars); } unset($lines); } $this->local->commit(); } } /** * Import transactions */ protected function importTransactions() { $this->loadModel("WhmcsAccounts"); $this->loadModel("WhmcsCurrencies"); Loader::loadModels($this, array("Invoices")); $default_currency = $this->WhmcsCurrencies->getDefaultCode(); if (!$default_currency) { $default_currency = "AUD"; } $invoice_ids = array(); // Add invoice credits $this->local->begin(); foreach ($this->credits as $credit) { $transaction_id = $this->addTransaction($credit, null); $vars = array( 'date' => $credit['date_added'], 'amounts' => array( array( 'invoice_id' => $credit['invoice_id'], 'amount' => $credit['amount'], ) ) ); $this->Transactions->apply($transaction_id, $vars); if (!in_array($credit['invoice_id'], $invoice_ids)) $invoice_ids[] = $credit['invoice_id']; } $this->local->commit(); unset($this->credits); $transactions = $this->fetchall ? $this->WhmcsAccounts->get(true)->fetchAll() : $this->WhmcsAccounts->get(true); $this->local->begin(); foreach ($transactions as $transaction) { if (!isset($this->mappings['clients'][$transaction->userid])) continue; $currency = $default_currency; if (!$currency) { $currency = "AUD"; } if ($transaction->trans_currency != "") $currency = $transaction->trans_currency; elseif ($transaction->client_currency != "") $currency = $transaction->client_currency; // Only add income transactions if ($transaction->amountin > 0) { $status = ($transaction->refund > 0 ? "refunded" : "approved"); $vars = array( 'client_id' => $this->mappings['clients'][$transaction->userid], 'amount' => $transaction->amountin, 'currency' => $currency, 'transaction_id' => $transaction->transid, 'status' => $status, 'date_added' => $this->Companies->dateToUtc($transaction->date, "c") ); $transaction_id = $this->addTransaction($vars, $transaction->id); // If the transactions was refunded add a new transaction for the difference if ($status == "refunded" && $transaction->refund < $transaction->amountin) { $vars = array( 'client_id' => $this->mappings['clients'][$transaction->userid], 'amount' => $transaction->amountin - $transaction->refund, 'currency' => $currency, 'transaction_id' => $transaction->transid, 'status' => "approved", 'date_added' => $this->Companies->dateToUtc($transaction->date, "c") ); $transaction_id = $this->addTransaction($vars, $transaction->id); } } // Apply payment if (isset($this->mappings['invoices'][$transaction->invoiceid]) && $transaction->amountin > 0) { $vars = array( 'date' => $this->Companies->dateToUtc($transaction->date, "c"), 'amounts' => array( array( 'invoice_id' => $this->mappings['invoices'][$transaction->invoiceid], 'amount' => $transaction->amountin - ($transaction->refund > 0 ? $transaction->refund : 0), ) ) ); $this->Transactions->apply($transaction_id, $vars); if (!in_array($this->mappings['invoices'][$transaction->invoiceid], $invoice_ids)) $invoice_ids[] = $this->mappings['invoices'][$transaction->invoiceid]; } } $this->local->commit(); unset($transactions); // Add client credits $credits = $this->fetchall ? $this->WhmcsAccounts->getOpenCredits()->fetchAll() : $this->WhmcsAccounts->getOpenCredits(); $this->local->begin(); foreach ($credits as $credit) { if (!$credit->currency) { $credit->currency = "AUD"; } if (!isset($this->mappings['clients'][$credit->userid])) continue; $vars = array( 'client_id' => $this->mappings['clients'][$credit->userid], 'amount' => $credit->credit, 'currency' => $credit->currency, 'type' => 'other', 'transaction_type_id' => $this->getTransactionTypeId("in_house_credit"), 'transaction_id' => null, 'status' => 'approved', 'date_added' => $this->Companies->dateToUtc(date("c")) ); $transaction_id = $this->addTransaction($vars, $transaction->id); } $this->local->commit(); unset($credits); // Update paid totals $this->local->begin(); foreach ($invoice_ids as $invoice_id) { // Update paid total $paid = $this->Invoices->getPaid($invoice_id); $this->local->where("id", "=", $invoice_id)-> update("invoices", array('paid' => $paid)); } $this->local->commit(); $this->balanceClientCredit(); } /** * Verifies that total transaction credit for a each client matches credit * set in WHMCS */ protected function balanceClientCredit() { if ($this->settings['balance_credit'] != "true") return; $this->loadModel("WhmcsAccounts"); if (!isset($this->Transactions)) Loader::loadModels($this, array("Transactions")); if (!isset($this->Invoices)) Loader::loadModels($this, array("Invoices")); // Fetch all client credit values $credits = $this->WhmcsAccounts->getCredits(); $date = date("c"); foreach ($credits as $credit) { if (!isset($this->mappings['clients'][$credit->userid])) continue; $client_id = $this->mappings['clients'][$credit->userid]; $total_credit = $this->Transactions->getTotalCredit($client_id, $credit->currency); $credit_diff = round($total_credit-$credit->credit, 4); // We have excess credit, so consume it if ($credit_diff > 0) { // Create an invoice to balance credits $vars = array( 'client_id' => $client_id, 'currency' => $credit->currency, 'date_billed' => $date, 'date_due' => $date, 'status' => "active", 'lines' => array( array( 'description' => "Automatic credit balance adjustment.", 'qty' => 1, 'amount' => $credit_diff ) ) ); $invoice_id = $this->Invoices->add($vars); // Consume the credit $amounts = array( array( 'invoice_id' => $invoice_id, 'amount' => $credit_diff ) ); $this->Transactions->applyFromCredits($client_id, $credit->currency, $amounts); } elseif ($credit_diff < 0) { // Create transaction to hold the credit diff $vars = array( 'client_id' => $client_id, 'amount' => -1*$credit_diff, 'currency' => $credit->currency, 'type' => 'other', 'transaction_type_id' => $this->getTransactionTypeId("in_house_credit"), 'transaction_id' => null, 'status' => 'approved', 'date_added' => $this->Companies->dateToUtc($date) ); $transaction_id = $this->addTransaction($vars, $transaction->id); } } } /** * Import modules */ protected function importModules() { $this->loadModel("WhmcsProducts"); // Import generic server module required for all package assigned to no module $this->installModuleRow(array('id' => "generic_server", 'type' => "generic_server")); // Import servers $rows = $this->fetchall ? $this->WhmcsProducts->getServers()->fetchAll() : $this->WhmcsProducts->getServers(); foreach ($rows as $row) { $this->installModuleRow((array)$row); } unset($rows); // Import registrars foreach ($this->WhmcsProducts->getReigstrars() as $registrar) { $row = $this->WhmcsProducts->getRegistrarFields($registrar); foreach ($row as &$value) { $value = $this->decryptData($value); } $row['id'] = $registrar; $row['type'] = $registrar; $this->installModuleRow($row, "registrar"); } } /** * Import packages */ protected function importPackages() { $this->importModules(); $this->loadModel("WhmcsProducts"); $this->loadModel("WhmcsConfiguration"); Loader::loadModels($this, array("PackageGroups")); // Add imported package group $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'name' => "Imported", 'type' => "standard" ); $package_group_id = $this->PackageGroups->add($vars); $products = $this->WhmcsProducts->get()->fetchAll(); $i=1; $this->local->begin(); foreach ($products as $product) { if (!isset($this->mappings['modules'][$product->servertype])) $product->servertype = "generic_server"; $pricing = $this->WhmcsProducts->getPricing($product->id); $mapping = $this->getModuleMapping($product->servertype); // Add package $vars = array( 'id_format' => "{num}", 'id_value' => $product->id, 'module_id' => $this->mappings['modules'][$product->servertype], 'name' => $this->decode($product->name), 'description' => strip_tags($this->decode($product->description)), 'description_html' => $this->decode($product->description), 'qty' => $product->stockcontrol == "on" ? $product->qty : null, 'module_row' => 0, // WHMCS doesn't associate a service with a product 'module_group' => null, 'taxable' => $product->tax, 'status' => $product->retired == "1" ? "inactive" : "active", 'company_id' => Configure::get("Blesta.company_id") ); $this->local->insert("packages", $vars); $this->mappings['packages'][$product->id] = $this->local->lastInsertId(); // Assign group $this->local->insert("package_group", array('package_id' => $this->mappings['packages'][$product->id], 'package_group_id' => $package_group_id)); // Add package pricing $this->addPackagePricing($pricing, $this->mappings['packages'][$product->id]); // Import package meta $this->addPackageMeta((array)$product, $mapping); $i = max(++$i, $product->id); } $this->local->commit(); $taxable = 0; $tax_domains = $this->WhmcsConfiguration->get("TaxDomains")->fetch(); if ($tax_domains) $taxable = $tax_domains->value == "on" ? 1 : 0; $tlds = $this->WhmcsProducts->getTlds(); $this->local->begin(); foreach ($tlds as $tld) { $pricing = $this->WhmcsProducts->getTldPricing($tld->extension); $registrar = trim($tld->autoreg); if ($registrar == "") continue; $mapping = $this->getModuleMapping($registrar, "registrar"); $vars = array( 'id_format' => "{num}", 'id_value' => max($tld->id, $i++), 'module_id' => $this->mappings['modules'][$registrar], 'name' => "Domain Registration (" . $tld->extension . ")", 'description' => null, 'description_html' => null, 'qty' => null, 'module_row' => !isset($this->mappings['module_rows'][$registrar][$registrar]) ? 0 : $this->mappings['module_rows'][$registrar][$registrar], 'module_group' => null, 'taxable' => $taxable, 'status' => "active", 'company_id' => Configure::get("Blesta.company_id") ); // Add the package $this->local->insert("packages", $vars); $this->mappings['packages'][$tld->extension . $registrar] = $this->local->lastInsertId(); // Assign group $this->local->insert("package_group", array('package_id' => $this->mappings['packages'][$tld->extension . $registrar], 'package_group_id' => $package_group_id)); // Add package pricing $this->addPackagePricing($pricing, $this->mappings['packages'][$tld->extension . $registrar]); // Import package meta $product = array( 'id' => $tld->extension . $registrar, 'tlds' => array($tld->extension) ); $this->addPackageMeta($product, $mapping); } $this->local->commit(); } /** * Import package options */ protected function importPackageOptions() { $this->loadModel("WhmcsProducts"); Loader::loadModels($this, array("PackageOptionGroups", "PackageOptions")); $option_types = $this->WhmcsProducts->getConfigOptionTypes(); $option_groups = $this->WhmcsProducts->getConfigOptionGroups(); foreach ($option_groups as $option_group) { $packages = array(); // Map WHMCS packages to packages in Blesta foreach ($option_group->packages as $package_id) { if (isset($this->mappings['packages'][$package_id])) { $packages[] = $this->mappings['packages'][$package_id]; } } $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'name' => $option_group->name, 'description' => $option_group->description, 'packages' => $packages ); $option_group_id = $this->PackageOptionGroups->add($vars); // Record package group mapping $this->mappings['package_options_groups'][$option_group->id] = $option_group_id; // Import package options $options = $this->WhmcsProducts->getConfigOptions($option_group->id); foreach ($options as $option) { $values = array(); foreach ($option->values as $value) { $is_qty = isset($option_types[$option->optiontype]) && $option_types[$option->optiontype] == "quantity"; $values[] = array( 'name' => $value->optionname, 'value' => $is_qty ? null : $value->optionname, 'min' => $is_qty ? max(0, $option->qtyminimum) : null, 'max' => $is_qty && $option->qtymaximum > 0 ? max(1, $option->qtymaximum) : null, 'step' => $is_qty ? "1" : null, 'pricing' => $this->WhmcsProducts->getPricing($value->id, "configoptions") ); } // WHMCS only supports one group per option... weak! $groups = array($this->mappings['package_options_groups'][$option->gid]); $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'label' => $option->optionname, 'name' => $option->optionname, 'type' => isset($option_types[$option->optiontype]) ? $option_types[$option->optiontype] : "select", 'values' => $values, 'groups' => $groups ); $option_id = $this->PackageOptions->add($vars); // Record package option mapping $this->mappings['package_options'][$option->id] = $option_id; // Record package option value mappings $opt_values = $this->PackageOptions->getValues($option_id); foreach ($opt_values as $v => $val) { $this->mappings['option_values'][$option->values[$v]->id] = $val->id; } } } } /** * Import services */ protected function importServices() { $this->loadModel("WhmcsServices"); $this->loadModel("WhmcsProducts"); Loader::loadModels($this, array("Clients", "Packages")); $servers = array(); $rows = $this->fetchall ? $this->WhmcsProducts->getServers()->fetchAll() : $this->WhmcsProducts->getServers(); foreach ($rows as $row) { $servers[$row->id] = $row; } unset($rows); $services = $this->fetchall ? $this->WhmcsServices->get()->fetchAll() : $this->WhmcsServices->get(); $this->local->begin(); foreach ($services as $service) { // If the client doesn't exist, we can't import the service if (!isset($this->mappings['clients'][$service->userid])) continue; // If the package doesn't exist, we can't import the service if (!isset($this->mappings['packages'][$service->packageid])) continue; $package = $this->Packages->get($this->mappings['packages'][$service->packageid]); if (!isset($this->mappings['modules'])) { if (!isset($this->ModuleManager)) Loader::loadModels($this, array("ModuleManager")); $module = $this->ModuleManager->get($package->module_id, false, false); if ($module) $modules[$package->module_id] = $module->class; } else $modules = array_flip($this->mappings['modules']); $mapping = $this->getModuleMapping(isset($modules[$package->module_id]) ? $modules[$package->module_id] : "generic_server"); // Get currency this client is invoiced in $currency = $this->getCurrency($this->mappings['clients'][$service->userid]); if (!$currency) { $currency = "AUD"; } if ($package->module_row > 0) $module_row_id = $package->module_row; else { if (isset($mapping['module_row_key']) && isset($servers[$service->server]->{$mapping['module_row_key']})) $module_row_id = $this->getModuleRowId($package->module_id, $servers[$service->server]->{$mapping['module_row_key']}, null); else $module_row_id = $this->getModuleRowId($package->module_id, null, isset($modules[$package->module_id]) ? $modules[$package->module_id] : null); } if (!$module_row_id) continue; $status = $this->getServiceStatus($service->domainstatus); $pricing = $this->getPricing($this->WhmcsServices->getTerm($service->billingcycle), $package, $currency, $service->amount); $override_price = (($p = number_format($pricing->price, 2, '.', '')) == number_format($service->amount, 2, '.', '') ? $p : null); $override_currency = ($override_price === null ? null : $currency); $vars = array( 'parent_service_id' => null, 'package_group_id' => null, 'id_format' => "{num}", 'id_value' => $service->id, 'pricing_id' => $pricing->id, 'client_id' => $this->mappings['clients'][$service->userid], 'module_row_id' => $module_row_id, 'coupon_id' => null, 'qty' => 1, 'override_price' => $override_price, 'override_currency' => $override_currency, 'status' => $status, 'date_added' => $this->Companies->dateToUtc($service->regdate . " 00:00:00"), 'date_renews' => $service->nextinvoicedate == "0000-00-00" ? null : $this->Companies->dateToUtc($service->nextinvoicedate . " 00:00:00"), 'date_last_renewed' => null, 'date_suspended' => $status == "suspended" ? $this->Companies->dateToUtc(date("c")) : null, 'date_canceled' => $status == "canceled" ? $this->Companies->dateToUtc(date("c")) : null ); $this->local->insert("services", $vars); $service_id = $this->local->lastInsertId(); $this->mappings['services'][$service->id] = $service_id; $this->addServiceFields((array)$service, $mapping); } $this->local->commit(); unset($services); $option_types = $this->WhmcsProducts->getConfigOptionTypes(); // Import options for services $options = $this->WhmcsServices->getConfigOptions(); $this->local->begin(); foreach ($options as $option) { // Ensure parent service exists if (!isset($this->mappings['services'][$option->relid])) continue; $currency = $this->getCurrency($this->mappings['clients'][$option->userid]); if (!$currency) { $currency = "AUD"; } $value_id = $this->mappings['option_values'][$option->optionid]; $pricing = $this->getOptionPricing($this->WhmcsServices->getTerm($option->billingcycle), $value_id, $currency); if (!$pricing) { continue; } $vars = array( 'service_id' => $this->mappings['services'][$option->relid], 'option_pricing_id' => $pricing->id, // option isn't a quantity type, set qty to 1 'qty' => $option_types[$option->optiontype] == "quantity" ? $option->qty : 1 ); $this->local->insert("service_options", $vars); } $this->local->commit(); unset($options); $services = $this->fetchall ? $this->WhmcsServices->getDomains()->fetchAll() : $this->WhmcsServices->getDomains(); $this->local->begin(); foreach ($services as $service) { // If the client doesn't exist, we can't import the service if (!isset($this->mappings['clients'][$service->userid])) continue; if ($service->registrar == "") $service->registrar = "generic_registrar"; $tld = $this->getTld($service->domain, $service->registrar); // If package does not exist, we can't import the service if (!isset($this->mappings['packages'][$tld . $service->registrar])) continue; $package = $this->Packages->get($this->mappings['packages'][$tld . $service->registrar]); $mapping = $this->getModuleMapping($service->registrar, "registrar"); // Get currency this client is invoiced in $currency = $this->getCurrency($this->mappings['clients'][$service->userid]); if (!$currency) { $currency = "AUD"; } $module_row_id = $this->mappings['module_rows'][$service->registrar][$service->registrar]; if (!$module_row_id) continue; $status = $this->getServiceStatus($service->status); $pricing = $this->getPricing($this->WhmcsServices->getTerm($service->registrationperiod), $package, $currency, $service->recurringamount); $override_price = (($p = number_format($pricing->price, 2, '.', '')) == number_format($service->recurringamount, 2, '.', '') ? $p : null); $override_currency = ($override_price === null ? null : $currency); $vars = array( 'parent_service_id' => null, 'package_group_id' => null, 'id_format' => "{num}", 'id_value' => $service->id, 'pricing_id' => $pricing->id, 'client_id' => $this->mappings['clients'][$service->userid], 'module_row_id' => $module_row_id, 'coupon_id' => null, 'qty' => 1, 'override_price' => $override_price, 'override_currency' => $override_currency, 'status' => $status, 'date_added' => $this->Companies->dateToUtc($service->registrationdate . " 00:00:00"), 'date_renews' => $service->nextinvoicedate == "0000-00-00" ? null : $this->Companies->dateToUtc($service->nextinvoicedate . " 00:00:00"), 'date_last_renewed' => null, 'date_suspended' => $status == "suspended" ? $this->Companies->dateToUtc(date("c")) : null, 'date_canceled' => $status == "canceled" ? $this->Companies->dateToUtc(date("c")) : null ); $this->local->insert("services", $vars); $service_id = $this->local->lastInsertId(); $this->mappings['services'][$service->id] = $service_id; $this->addServiceFields((array)$service, $mapping); } $this->local->commit(); unset($services); } /** * Import support departments */ protected function importSupportDepartments() { Loader::loadModels($this, array("PluginManager")); // Install support plugin if not already installed if (!$this->PluginManager->isInstalled("support_manager", Configure::get("Blesta.company_id"))) $this->PluginManager->add(array('dir' => "support_manager", 'company_id' => Configure::get("Blesta.company_id"))); $this->loadModel("WhmcsSupportDepartments"); $departments = $this->fetchall ? $this->WhmcsSupportDepartments->get()->fetchAll() : $this->WhmcsSupportDepartments->get(); $this->local->begin(); foreach ($departments as $department) { $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'name' => $this->decode($department->name), 'description' => $this->decode($department->description), 'email' => $this->decode($department->email), 'method' => $department->piperepliesonly == "on" ? "pipe" : "pop3", 'default_priority' => "medium", 'host' => $this->decode($department->host), 'user' => $this->decode($department->login), 'pass' => $this->decryptData($department->password), 'port' => $department->port, 'security' => "none", 'box_name' => null, 'mark_messages' => "deleted", 'clients_only' => $department->clientsonly == "on" ? 1 : 0, 'status' => $department->hidden == "on" ? "hidden" : "visible" ); $this->local->insert("support_departments", $vars); $department_id = $this->local->lastInsertId(); $this->mappings['support_departments'][$department->id] = $department_id; } $this->local->commit(); unset($departments); // Assign admins to support departments $this->local->begin(); foreach ($this->mappings['admin_departs'] as $remote_admin_id => $departs) { if (!isset($this->mappings['staff'][$remote_admin_id])) continue; $departs = explode(",", $departs); foreach ($departs as $depart_id) { $depart_id = trim($depart_id); if (isset($this->mappings['support_departments'][$depart_id])) { $vars = array( 'department_id' => $this->mappings['support_departments'][$depart_id], 'staff_id' => $this->mappings['staff'][$remote_admin_id] ); $this->local-> duplicate("staff_id", "=", $this->mappings['staff'][$remote_admin_id])-> insert("support_staff_departments", $vars); } } // Add schedules $days = array("sun", "mon", "tue", "wed", "thu", "fri", "sat"); foreach ($days as $day) { $vars = array( 'staff_id' => $this->mappings['staff'][$remote_admin_id], 'company_id' => Configure::get("Blesta.company_id"), 'day' => $day, 'start_time' => "00:00:00", 'end_time' => "00:00:00" ); try { $this->local->insert("support_staff_schedules", $vars); } catch (Exception $e) { $this->local->reset(); } } // Add notices $keys = array("ticket_emails"); foreach ($keys as $key) { $vars = array( 'key' => $key, 'company_id' => Configure::get("Blesta.company_id"), 'staff_id' => $this->mappings['staff'][$remote_admin_id], 'value' => serialize(array('emergency' => "true", 'critical' => "true", 'high' => "true", 'medium' => "true", 'low' => "true")) ); try { $this->local->insert("support_staff_settings", $vars); } catch (Exception $e) { $this->local->reset(); } } } $this->local->commit(); } /** * Import support tickets */ protected function importSupportTickets() { $this->loadModel("WhmcsSupportTickets"); $priorities = array( 'High' => 'high', 'Medium' => 'medium', 'Low' => 'low' ); $statuses = array( 'Open' => 'open', 'Answered' => 'closed', 'Customer-Reply' => 'awaiting_reply', 'Closed' => 'closed', 'In Progress' => 'in_progress' ); $tickets = $this->fetchall ? $this->WhmcsSupportTickets->get()->fetchAll() : $this->WhmcsSupportTickets->get(); $this->local->begin(); foreach ($tickets as $ticket) { $vars = array( 'code' => is_numeric($ticket->tid) ? (int)$ticket->tid : preg_replace("/[^0-9]+/", "", $ticket->tid), 'department_id' => isset($this->mappings['support_departments'][$ticket->did]) ? $this->mappings['support_departments'][$ticket->did] : 0, 'staff_id' => null, 'service_id' => null, 'client_id' => $ticket->userid > 0 && isset($this->mappings['clients'][$ticket->userid]) ? $this->mappings['clients'][$ticket->userid] : null, 'email' => $this->decode($ticket->email != "" ? $ticket->email : null), 'summary' => $this->decode($ticket->title), 'priority' => isset($priorities[$ticket->urgency]) ? $priorities[$ticket->urgency] : 'medium', 'status' => isset($statuses[$ticket->status]) ? $statuses[$ticket->status] : 'open', 'date_added' => $this->Companies->dateToUtc($ticket->date), 'date_closed' => isset($statuses[$ticket->status]) && $statuses[$ticket->status] == "closed" ? $this->Companies->dateToUtc($ticket->lastreply) : null, ); $this->local->insert("support_tickets", $vars); $this->mappings['support_tickets'][$ticket->id] = $this->local->lastInsertId(); // Add ticket body $vars = array( 'ticket_id' => $this->mappings['support_tickets'][$ticket->id], 'staff_id' => $ticket->admin_id && isset($this->mappings['staff'][$ticket->admin_id]) ? $this->mappings['staff'][$ticket->admin_id] : null, 'type' => "reply", 'details' => $this->decode($ticket->message), 'date_added' => $this->Companies->dateToUtc($ticket->date), ); $this->local->insert("support_replies", $vars); } $this->local->commit(); unset($tickets); // Import ticket replies $replies = $this->fetchall ? $this->WhmcsSupportTickets->getReplies()->fetchAll() : $this->WhmcsSupportTickets->getReplies(); $this->local->begin(); foreach ($replies as $reply) { if (!isset($this->mappings['support_tickets'][$reply->tid])) continue; $vars = array( 'ticket_id' => $this->mappings['support_tickets'][$reply->tid], 'staff_id' => $reply->admin_id && isset($this->mappings['staff'][$reply->admin_id]) ? $this->mappings['staff'][$reply->admin_id] : null, 'type' => "reply", 'details' => $this->decode($reply->message), 'date_added' => $this->Companies->dateToUtc($reply->date), ); $this->local->insert("support_replies", $vars); } $this->local->commit(); unset($replies); // Import ticket notes $notes = $this->fetchall ? $this->WhmcsSupportTickets->getNotes()->fetchAll() : $this->WhmcsSupportTickets->getNotes(); $this->local->begin(); foreach ($notes as $note) { if (!isset($this->mappings['support_tickets'][$note->ticketid])) continue; $vars = array( 'ticket_id' => $this->mappings['support_tickets'][$note->ticketid], 'staff_id' => $note->admin_id && isset($this->mappings['staff'][$note->admin_id]) ? $this->mappings['staff'][$note->admin_id] : null, 'type' => "note", 'details' => $this->decode($note->message), 'date_added' => $this->Companies->dateToUtc($note->date), ); $this->local->insert("support_replies", $vars); } $this->local->commit(); unset($notes); // Import predefined categories $categories = $this->fetchall ? $this->WhmcsSupportTickets->getResponseCategories()->fetchAll() : $this->WhmcsSupportTickets->getResponseCategories(); $this->local->begin(); foreach ($categories as $category) { $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'parent_id' => isset($this->mappings['support_response_categories'][$category->parentid]) ? $this->mappings['support_response_categories'][$category->parentid] : null, 'name' => $this->decode($category->name) ); $this->local->insert("support_response_categories", $vars); $this->mappings['support_response_categories'][$category->id] = $this->local->lastInsertId(); } $this->local->commit(); unset($categories); // Import predefined replies $responses = $this->fetchall ? $this->WhmcsSupportTickets->getResponses()->fetchAll() : $this->WhmcsSupportTickets->getResponses(); $this->local->begin(); foreach ($responses as $response) { if (!isset($this->mappings['support_response_categories'][$response->catid])) continue; $vars = array( 'category_id' => $this->mappings['support_response_categories'][$response->catid], 'name' => $this->decode($response->name), 'details' => $this->decode($response->reply) ); $this->local->insert("support_responses", $vars); } $this->local->commit(); unset($responses); } /** * Import miscellaneous */ protected function importMisc() { $this->loadModel("WhmcsEmails"); $this->loadModel("WhmcsConfiguration"); $this->loadModel("WhmcsCalendar"); $from_name = $this->WhmcsConfiguration->get("SystemEmailsFromName")->fetch(); $from_email = $this->WhmcsConfiguration->get("SystemEmailsFromEmail")->fetch(); // Mail log $this->startTimer("mail log"); $this->local->begin(); foreach ($this->WhmcsEmails->get() as $message) { if ($message->to == "") continue; $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'to_client_id' => $message->userid > 0 && isset($this->mappings['clients'][$message->userid]) ? $this->mappings['clients'][$message->userid] : null, 'from_staff_id' => null, 'to_address' => $this->decode($message->to), 'from_address' => $this->decode($from_email->value), 'from_name' => $this->decode($from_name->value), 'cc_address' => $this->decode($message->cc != "" ? $message->cc : null), 'subject' => $this->decode($message->subject != "" ? $message->subject : " "), 'body_text' => strip_tags($this->decode($message->message)), 'body_html' => $this->decode($message->message), 'sent' => 1, 'error' => null, 'date_sent' => $this->Companies->dateToUtc($message->date) ); $this->local->insert("log_emails", $vars); } $this->local->commit(); $this->endTimer("mail log"); // Configurations $this->startTimer("settings"); $settings = $this->fetchall ? $this->WhmcsConfiguration->get()->fetchAll() : $this->WhmcsConfiguration->get(); $this->local->begin(); foreach ($settings as $setting) { $setting->value = $this->decode($setting->value); switch ($setting->setting) { case "MailType": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "mail_delivery", $setting->value == "mail" ? "php" : $setting->value); break; case "SMTPHost": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "smtp_host", $setting->value); break; case "SMTPUsername": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "smtp_user", $setting->value); break; case "SMTPPassword": if ($setting->value != "") $this->Companies->setSetting(Configure::get("Blesta.company_id"), "smtp_user", $this->decryptData($setting->value)); break; case "SMTPPort": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "smtp_port", $setting->value); break; case "SMTPSSL": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "smtp_security", $setting->value); break; case "CreateInvoiceDaysBefore": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "inv_days_before_renewal", $setting->value); break; case "SendInvoiceReminderDays": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "notice1", $setting->value != 0 ? -1 * $setting->value : "disabled"); break; case "SendFirstOverdueInvoiceReminder": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "notice2", $setting->value != 0 ? $setting->value : "disabled"); break; case "SendSecondOverdueInvoiceReminder": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "notice3", $setting->value != 0 ? $setting->value : "disabled"); break; case "CCProcessDaysBefore": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "autodebit_days_before_due", $setting->value); break; case "AutoSuspensionDays": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "suspend_services_days_after_due", $setting->value); break; } } $this->local->commit(); $this->endTimer("settings"); unset($settings); // Import calendar events $this->startTimer("calendar events"); $events = $this->fetchall ? $this->WhmcsCalendar->get()->fetchAll() : $this->WhmcsCalendar->get(); $this->local->begin(); foreach ($events as $event) { $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'staff_id' => isset($this->mappings['staff'][$event->adminid]) ? $this->mappings['staff'][$event->adminid] : 0, 'shared' => 0, 'title' => $this->decode($event->title . " " . $event->desc), 'url' => null, 'start_date' => $this->Companies->dateToUtc($event->start), 'end_date' => $event->end != 0 ? $this->Companies->dateToUtc($event->end) : $this->Companies->dateToUtc($event->start), 'all_day' => $event->allday ); $this->local->insert("calendar_events", $vars); } $this->local->commit(); $this->endTimer("calendar events"); unset($events); // Import todo events $this->startTimer("todo events"); $events = $this->fetchall ? $this->WhmcsCalendar->getTodos()->fetchAll() : $this->WhmcsCalendar->getTodos(); $this->local->begin(); foreach ($events as $event) { $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'staff_id' => isset($this->mappings['staff'][$event->admin]) ? $this->mappings['staff'][$event->admin] : 0, 'shared' => 0, 'title' => $this->decode($event->title . " " . $event->description), 'url' => null, 'start_date' => $this->Companies->dateToUtc($event->date), 'end_date' => $this->Companies->dateToUtc($event->duedate), 'all_day' => 1 ); $this->local->insert("calendar_events", $vars); } $this->local->commit(); $this->startTimer("todo events"); unset($events); } /** * Load the given local model * * @param string $name The name of the model to load */ protected function loadModel($name) { $name = Loader::toCamelCase($name); $file = Loader::fromCamelCase($name); Loader::load($this->path . DS . "models" . DS . $file . ".php"); $this->{$name} = new $name($this->remote); } /** * Creates a user * * @param array $user An array of key/value pairs including: * - username * - password * - date_added */ private function createUser(array $user) { $this->local->insert("users", $user); return $this->local->lastInsertId(); } /** * Returns the field type * * @param string WHMCS field type * @return string Blesta field type */ private function getFieldType($type) { switch ($type) { case "text": case "textarea": return $type; break; case "dropdown": return "select"; case "tickbox": return "checkbox"; default: return "text"; } } /** * Returns the serialized selection of field values * * @param string WHMCS serialized values * @return string Blesta serialized values */ private function getFieldValues($values) { if ($values == "") return null; $values = explode(",", $values); return serialize(array_combine($values, $values)); } /** * Returns the currency format * * @param int WHMCS currency format value * @return string Blesta currency format value */ private function getCurrencyFormat($format) { switch ($format) { default: case 1: case 2: return "#,###.##"; case 3: return "#.###,##"; case 4: return "#,###"; } } /** * Returns the local tax rule for the given level and rate * * @param int $level * @param float $rate * @return mixed A stdClass object representing the local tax rule, false if no rule exists */ private function getTaxRule($level, $rate) { return $this->local->select()->from("taxes")-> where("company_id", "=", Configure::get("Blesta.company_id"))-> where("level", "=", $level)->where("amount", "=", $rate)->fetch(); } /** * Returns the transaction type ID * * @param string $type The version 2 transaction type * @return string The transaction type ID */ private function getTransactionTypeId($type) { static $trans_types = null; if (!isset($this->Transactions)) Loader::loadModels($this, array("Transactions")); if ($trans_types == null) $trans_types = $this->Transactions->getTypes(); switch ($type) { default: case "other": case "credit": return null; case "cash": case "check": foreach ($trans_types as $trans_type) { if ($trans_type->name == $type) return $trans_type->id; } case "in_house_credit": foreach ($trans_types as $trans_type) { if ($trans_type->name == "in_house_credit") return $trans_type->id; } case "money_order": foreach ($trans_types as $trans_type) { if ($trans_type->name == "money_order") return $trans_type->id; } } return null; } /** * Convert WHMCS service status into Blesta service status * * @param string $status * @return string The service status */ private function getServiceStatus($status) { $status = strtolower($status); switch ($status) { case "active": case "pending": case "suspended": return $status; case "fraud": case "terminated": case "cancelled": return "canceled"; } return "in_review"; } /** * Decrypts data from WHMCS * * @param string $data The data to decrypt * @return string The decrypted data */ private function decryptData($str) { $this->decrypt_count++; $this->unpauseTimer("decrypt"); $key = $this->settings['key']; $y = base64_decode($str); $x = null; // Key derivation $key = sha1(md5(md5($key)) . md5($key)); $temp_key = null; for ($i=0; $i<strlen($key); $i+=2) { $temp_key .= chr(hexdec($key[$i] . $key[$i + 1])); } $key = $temp_key; $key_length = strlen($key); // Extract key seed from input $key_seed = substr($y, 0, $key_length); $y = substr($y, $key_length, strlen($y) - $key_length); // Calculate final key $z = null; for ($i=0; $i<$key_length; $i++) { $z .= chr(ord($key_seed[$i]) ^ ord($key[$i])); } // Decrypt for ($i=0; $i<strlen($y); $i++) { // Generate new key schedule for each block if ($i != 0 && $i % $key_length == 0) { $temp = sha1($z . substr($x, $i - $key_length, $key_length)); $z = null; for ($j=0; $j<strlen($temp); $j+=2) { $z .= chr(hexdec($temp[$j] . $temp[$j+1])); } } $x .= chr(ord($z[$i % $key_length]) ^ ord($y[$i])); } $this->pauseTimer("decrypt"); return $x; } /** * Formats the given key into a mysql AES key * * @param string $key The AES key to format * @return string The mysql formatted AES key */ private function mysqlAesKey($key) { $new_key = str_repeat(chr(0), 16); for($i=0,$len=strlen($key);$i<$len;$i++) { $new_key[$i%16] = $new_key[$i%16] ^ $key[$i]; } return $new_key; } /** * Installs the module row * * @param array $row An array of key/value pairs, including but not limited to: * - type The module name in WHMCS * - id The row ID in WHMCS * @param string $module_type The type of module ('server' or 'registrar') * @return int The module row ID installed (also saved in mappings['modules'] property) */ private function installModuleRow($row, $module_type = "server") { if (!isset($this->ModuleManager)) Loader::loadModels($this, array("ModuleManager")); $mapping = $this->getModuleMapping($row['type'], $module_type); $module_id = $this->installModule($row['type'], $mapping); if (!$module_id) return null; // Install the module row $this->local->insert("module_rows", array('module_id' => $module_id)); $module_row_id = $this->local->lastInsertId(); $this->mappings['module_rows'][$row['type']][$row['id']] = $module_row_id; // Install the module row meta fields if (isset($mapping['module_row_meta'])) { foreach ($mapping['module_row_meta'] as $meta_row) { $vars = (array)$meta_row; $vars['value'] = null; $vars['module_row_id'] = $module_row_id; if (is_object($meta_row->value)) { $row_key = strtolower($meta_row->value->module); if (isset($meta_row->value->module) && array_key_exists($row_key, $row)) $vars['value'] = $row[$row_key]; } else $vars['value'] = $meta_row->value; if (isset($meta_row->callback)) $vars['value'] = call_user_func_array($meta_row->callback, array($vars['value'])); if ($vars['serialized'] == 1) $vars['value'] = serialize($vars['value']); if ($vars['encrypted'] == 1) $vars['value'] = $this->ModuleManager->systemEncrypt($vars['value']); $this->local->insert("module_row_meta", $vars, array("module_row_id", "key", "value", "serialized", "encrypted")); } } return $module_row_id; } /** * Installs the given module and returns the module ID, if already installed simply returns the module ID * * @param string $module The WHMCS module name * @param array An array of mapping fields for this particular module (optional, will automatically load if not given) * @return int The ID of the module in Blesta */ private function installModule($module, $mapping = null) { if (!isset($this->ModuleManager)) Loader::loadModels($this, array("ModuleManager")); if ($mapping == null) $mapping = $this->getModuleMapping($module); // Return module if already mapped if (isset($this->mappings['modules'][$module])) return $this->mappings['modules'][$module]; // Check if module is already installed $mod = $this->local->select(array("id"))->from("modules")-> where("company_id", "=", Configure::get("Blesta.company_id"))-> where("class", "=", $mapping['module'])->fetch(); if ($mod) { $this->mappings['modules'][$module] = $mod->id; return $mod->id; } // Install the module since it does not already exist $module_id = null; try { $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'class' => $mapping['module'] ); $module_id = $this->ModuleManager->add($vars); } catch (Exception $e) { // Module couldn't be added } $this->mappings['modules'][$module] = (int)$module_id; return $module_id; } /** * Adds package pricing * * @param array $pricing A numerically indexed array of pricing info including: * - term * - period * - price * - setup_fee * - cancel_fee * - currency * @param string $package_id The Blesta package ID to add pricing to */ private function addPackagePricing($pricing, $package_id) { // Add package pricing $pricing_id = null; foreach ($pricing as $price) { if (version_compare(BLESTA_VERSION, "3.1.0-b1", ">=")) { $vars = $price; $vars['company_id'] = Configure::get("Blesta.company_id"); $this->local->insert("pricings", $vars); $pricing_id = $this->local->lastInsertId(); $this->local->insert("package_pricing", array( 'package_id' => $package_id, 'pricing_id' => $pricing_id ) ); $pricing_id = $this->local->lastInsertId(); } else { $vars = $price; $vars['package_id'] = $package_id; $this->local->insert("package_pricing", $vars); $pricing_id = $this->local->lastInsertId(); } } return $pricing_id; } /** * Adds package meta for the given package * * @param array $package An array of package info including: * - id The ID of the package in WHMCS * - * misc package fields * @param array $mapping An array of module mapping config settings */ private function addPackageMeta($package, $mapping) { // Add package meta if (isset($mapping['package_meta'])) { foreach ($mapping['package_meta'] as $meta) { $vars = (array)$meta; $vars['package_id'] = $this->mappings['packages'][$package['id']]; $vars['value'] = null; if (is_object($meta->value)) { if (isset($meta->value->package)) { $meta_key = strtolower($meta->value->package); if (array_key_exists($meta_key, $package)) { $vars['value'] = $package[$meta_key]; if ($meta_key == "password") $vars['value'] = $this->decryptData($package[$meta_key]); } } } else $vars['value'] = $meta->value; if (isset($meta->callback)) $vars['value'] = call_user_func_array($meta->callback, array($vars['value'])); if ($vars['serialized'] == 1) $vars['value'] = serialize($vars['value']); if ($vars['encrypted'] == 1) $vars['value'] = $this->ModuleManager->systemEncrypt($vars['value']); $this->local->insert("package_meta", $vars, array("package_id", "key", "value", "serialized", "encrypted")); } } } /** * Adds service fields * * @param array $service An array of key/value pairs for the remote service including: * - id The ID of the service on the remote server * - * other fields * @param array $mapping An array of module mapping config settings */ private function addServiceFields($service, $mapping) { if (!isset($this->Services)) Loader::loadModels($this, array("Services")); foreach ($mapping['service_fields'] as $key => $field) { $value = array_key_exists($key, $service) ? $service[$key] : null; if ($key == "password" && $value != "") $value = $this->decryptData($value); if (!is_object($field)) continue; if (isset($field->callback)) $value = call_user_func_array($field->callback, array($value)); if ($field->serialized > 0) $value = serialize($value); if ($field->encrypted > 0) $value = $this->Services->systemEncrypt($value); $vars = array( 'service_id' => $this->mappings['services'][$service['id']], 'key' => $field->key, 'value' => $value != null ? $this->decode($value) : "", 'serialized' => $field->serialized, 'encrypted' => $field->encrypted ); $this->local->insert("service_fields", $vars); } } /** * Get the pricing for the given term, package, and currency * * @param array $term An array of term info including: * - term * - period * @param stdClass $package The package in Blesta * @param string $currency The currency to fetch the pricing ID in, will fallback to any currency for the matching term and period * @param string $amount The service amount * @return stdClass An object containing the pricing */ private function getPricing($term, $package, $currency = null, $amount = null) { if (!is_array($term)) return null; $pricing_id = null; if ($package) { foreach ($package->pricing as $price) { if ($price->term == $term['term'] && $price->period == $term['period']) { $pricing_id = $price->id; if ($price->currency == $currency) { return $price; } } } } // If no pricing found, add default pricing $pricing = array( array( 'term' => $term['term'], 'period' => $term['period'], 'currency' => $currency ? $currency : "USD", 'price' => $amount !== null ? $amount : 0, ) ); $pricing_id = $this->addPackagePricing($pricing, $package->id); $fields = array("package_pricing.id", "package_pricing.pricing_id", "package_pricing.package_id", "pricings.term", "pricings.period", "pricings.price", "pricings.setup_fee", "pricings.cancel_fee", "pricings.currency", "packages.taxable"); return $this->local->select($fields)->from("package_pricing")-> innerJoin("pricings", "pricings.id", "=", "package_pricing.pricing_id", false)-> innerJoin("packages", "packages.id", "=", "package_pricing.package_id", false)-> where("package_pricing.id", "=", $pricing_id)->fetch(); } /** * Get the pricing for the given term, option value ID, and currency * * @param array $term An array of term info including: * - term * - period * @param int $value_id The option value ID in Blesta * @param string $currency The currency to fetch the pricing ID in * @return stdClass An object containing the pricing */ private function getOptionPricing($term, $value_id, $currency) { if (!is_array($term)) return null; $fields = array("package_option_pricing.id", "package_option_pricing.pricing_id", "package_option_pricing.option_value_id", "pricings.term", "pricings.period", "pricings.price", "pricings.setup_fee", "pricings.cancel_fee", "pricings.currency"); return $this->local->select($fields)->from("package_option_pricing")-> innerJoin("pricings", "pricings.id", "=", "package_option_pricing.pricing_id", false)-> where("pricings.currency", "=", $currency)-> where("pricings.period", "=", $term['period'])-> where("pricings.term", "=", $term['term'])-> where("package_option_pricing.option_value_id", "=", $value_id)->fetch(); } /** * Returns the local module row ID used for the remote service * * @param int $local_module_id The local ID of the module * @param string $row_value The module row field value for the remote service that uniquely identifies the module row * @param string $remote_module The name of the module on the remote server * @return int The local module row ID for the service */ private function getModuleRowId($local_module_id, $row_value = null, $remote_module = null) { $module_row = false; if ($row_value) { $module_row = $this->local->select(array("module_rows.*"))->from("module_rows")-> innerJoin("module_row_meta", "module_row_meta.module_row_id", "=", "module_rows.id", false)-> where("module_row_meta.value", "=", $row_value)-> where("module_rows.module_id", "=", $local_module_id)->fetch(); } // If no field, attempt to look up module row based on module name, since // the universal module uses the module name to create module rows else { $module_row = $this->local->select(array("module_rows.*"))->from("module_rows")-> innerJoin("modules", "modules.id", "=", "module_rows.module_id", false)-> on("module_row_meta.module_row_id", "=", "module_rows.id", false)-> innerJoin("module_row_meta", "module_row_meta.key", "=", "name")-> where("modules.class", "=", "universal_module")-> where("module_row_meta.value", "=", $remote_module)-> where("module_rows.module_id", "=", $local_module_id)->fetch(); } if ($module_row) { return $module_row->id; } else { $module_row = $this->local->select(array("module_rows.*"))->from("module_rows")-> where("module_rows.module_id", "=", $local_module_id)->fetch(); return $module_row->id; } } /** * Fetch the currency in used by the given client * * @param int $client_id * @return string The currency code for the client */ private function getCurrency($client_id) { if (!isset($this->Clients)) Loader::loadModels($this, array("Clients")); static $currencies = array(); if (!isset($currencies[$client_id])) { $default_currency = $this->Clients->getSetting($client_id, "default_currency"); if ($default_currency) $currencies[$client_id] = $default_currency->value; } // Get currency this client is invoiced in return isset($currencies[$client_id]) ? $currencies[$client_id] : "USD"; } /** * Looks for the TLD of the given domain based on the packages created for the given registrar * * @param string $domain * @param string $registrar The registrar * @return string The TLD */ private function getTld($domain, $registrar) { $tld = $domain; do { $tld = strstr(ltrim($tld, "."), "."); } while (!isset($this->mappings['packages'][$tld . $registrar]) && $tld != ""); return $tld; } /** * Decodes the HTML entities of the given string * * @param string $str The string to decode * @return string The decoded string */ protected function decode($str) { if ($str === null) return $str; return html_entity_decode($str, ENT_QUOTES, "UTF-8"); } /** * Set debug data * * @param string $str The debug data */ protected function debug($str) { static $set_buffering = false; if ($this->enable_debug) { if (!$set_buffering) { ini_set('output_buffering', 'off'); ini_set('zlib.output_compression', false); @ob_end_flush(); ini_set('implicit_flush', true); ob_implicit_flush(true); header("Content-type: text/plain"); header('Cache-Control: no-cache'); $set_buffering = true; } echo $str . "\n"; @ob_flush(); flush(); } } /** * Start a timer for the given task * * @param string $task */ protected function startTimer($task) { $this->task[$task] = array('start' => microtime(true), 'end' => 0, 'total' => 0); } /** * Pause a timer for the given task * * @param string $task */ protected function pauseTimer($task) { $this->task[$task]['end'] = microtime(true); $this->task[$task]['total'] += ($this->task[$task]['end'] - $this->task[$task]['start']); } /** * Unpause a timer for the given task * * @param string $task */ protected function unpauseTimer($task) { $this->task[$task]['start'] = microtime(true); } /** * End a timer for the given task, output to debug * * @param string $task */ protected function endTimer($task) { if ($this->task[$task]['start'] > $this->task[$task]['end']) $this->pauseTimer($task); if ($this->enable_debug) { $this->debug($task . " took: " . round($this->task[$task]['total'], 4) . " seconds"); } } } ?>
  20. Like
    Kangaroo got a reaction from Michael in Stuck When Importing.   
    Struggled like a litle B* but  F* you whmcs here's the file used if anyone else has this issue.
    <?php /** * Generic WHMCS Migrator * * @package blesta * @subpackage blesta.plugins.import_manager.components.migrators.whmcs * @copyright Copyright (c) 2010, Phillips Data, Inc. * @license http://www.blesta.com/license/'>http://www.blesta.com/license/ The Blesta License Agreement * @link http://www.blesta.com/ Blesta */ class WhmcsMigrator extends Migrator { /** * @var array An array of settings */ protected $settings; /** * @var boolean True to fetch all records instead of looping through PDOStatement */ protected $fetchall = false; /** * @var boolean Enable/disable debugging */ protected $enable_debug = false; /** * @var string The default country */ private $default_country = "US"; /** * @var string The default first name */ private $default_firstname = "unknown"; /** * @var string The default last name */ private $default_lastname = "unknown"; /** * @var array An array of credits */ private $credits = array(); private $default_currency = "AUD"; /** * Runs the import, sets any Input errors encountered */ public function import() { Loader::loadModels($this, array("Companies")); Configure::set("Whmcs.import_fetchall", false); if (Configure::get("Whmcs.import_fetchall")) { $this->fetchall = true; ini_set("memory_limit", "512M"); } $actions = array( "importStaff", // works "importClients", // works "importContacts", // works "importTaxes", // works "importCurrencies", // works "importInvoices", // works "importTransactions", // works "importPackages", // works "importPackageOptions", // works "importServices", // works "importSupportDepartments", // works "importSupportTickets", // works "importMisc" // works ); // I hate WHMCS!!!!!!!! $errors = array(); $this->startTimer("total time"); $this->decrypt_count = 0; $this->startTimer("decrypt"); $this->pauseTimer("decrypt"); foreach ($actions as $action) { try { // Only import packages if no mappings exist if ($action == "importPackages" && isset($this->mappings['packages'])) continue; $this->debug($action); $this->debug("-----------------"); $this->startTimer($action); $this->{$action}(); $this->endTimer($action); $this->debug("-----------------\n"); } catch (Exception $e) { $errors[] = $action . ": " . $e->getMessage() . " on line " . $e->getLine(); } } if (!empty($errors)) { array_unshift($errors, Language::_("Whmcs5_2.!error.import", true)); $this->Input->setErrors(array('error' => $errors)); } $this->debug("decrypted " . $this->decrypt_count . " values using WHMCS' custom algorithm"); $this->endTimer("decrypt"); $this->endTimer("total time"); if ($this->enable_debug) { $this->debug(print_r($this->Input->errors(), true)); exit; } } /** * Import staff */ protected function importStaff() { Loader::loadModels($this, array("StaffGroups")); Loader::loadModels($this, array("Users")); $this->loadModel("WhmcsAdmins"); // Create "Support" staff group (no permissions) $staff_group = array( 'company_id' => Configure::get("Blesta.company_id"), 'name' => "Support", 'permission_group' => array(), 'permission' => array() ); $this->StaffGroups->add($staff_group); $staff_groups = $this->StaffGroups->getAll(Configure::get("Blesta.company_id")); $groups = array(); foreach ($staff_groups as $group) { if ($group->name == "Administrators") { $groups[0] = $group->id; $groups[1] = $group->id; } elseif ($group->name == "Billing") { $groups[2] = $group->id; } elseif ($group->name == "Support") { $groups[3] = $group->id; } } $admins = $this->fetchall ? $this->WhmcsAdmins->get()->fetchAll() : $this->WhmcsAdmins->get(); foreach ($admins as $admin) { $this->Users->begin(); // Set aside assigned support departments $this->mappings['admin_departs'][$admin->id] = $admin->supportdepts; try { $user_id = $this->createUser(array( 'username' => $this->decode($admin->username), 'password' => $admin->password, 'date_added' => $this->Users->dateToUtc(date("c")) )); $vars = array( 'user_id' => $user_id, 'first_name' => $this->decode($admin->firstname), 'last_name' => $this->decode($admin->lastname), 'email' => $this->decode($admin->email), 'status' => $admin->disabled == "0" ? "active" : "inactive", 'groups' => isset($groups[$admin->roleid]) ? array($groups[$admin->roleid]) : null ); $staff_id = $this->addStaff($vars, $admin->id); if ($staff_id) $this->Users->commit(); else $this->Users->rollback(); } catch (Exception $e) { $this->local->reset(); $this->Users->rollback(); } } unset($admins); } /** * Import clients */ protected function importClients() { Loader::loadModels($this, array("Accounts", "Clients", "ClientGroups")); $this->loadModel("WhmcsClients"); // Initialize crypto (AES in ECB) Loader::loadComponents($this, array("Security")); $aes = $this->Security->create("Crypt", "AES", array(1)); // 1 = CRYPT_AES_MODE_ECB $aes->disablePadding(); // Set default client group $client_groups = $this->ClientGroups->getAll(Configure::get("Blesta.company_id")); $this->mappings['client_groups'][0] = $client_groups[0]->id; // Import client groups $groups = $this->fetchall ? $this->WhmcsClients->getGroups()->fetchAll() : $this->WhmcsClients->getGroups(); foreach ($groups as $group) { $group_id = $this->ClientGroups->add(array( 'name' => $this->decode($group->groupname), 'company_id' => Configure::get("Blesta.company_id"), 'color' => str_replace("#", "", $group->groupcolour) )); $this->mappings['client_groups'][$group->id] = $group_id; } unset($groups); // Import clients $clients = $this->fetchall ? $this->WhmcsClients->get()->fetchAll() : $this->WhmcsClients->get(); $this->local->begin(); foreach ($clients as $client) { // Create user $user_id = null; try { $user_id = $this->createUser(array( 'username' => $this->decode($client->email), 'password' => $client->password, 'date_added' => $client->datecreated )); } catch (Exception $e) { $this->local->reset(); } if (!$user_id) continue; // Create client $vars = array( 'id_format' => "{num}", 'id_value' => $client->id, 'user_id' => $user_id, 'client_group_id' => $this->mappings['client_groups'][$client->groupid], 'status' => strtolower($client->status) == "closed" ? "inactive" : "active" ); $this->local->insert("clients", $vars); $client_id = $this->local->lastInsertId(); $this->mappings['clients'][$client->id] = $client_id; // Create primary contact $vars = array( 'client_id' => $client_id, 'contact_type' => "primary", 'first_name' => $this->decode(trim($client->firstname) != "" ? $client->firstname : $this->default_firstname), 'last_name' => $this->decode(trim($client->lastname) != "" ? $client->lastname : $this->default_lastname), 'company' => $this->decode($client->companyname != "" ? $client->companyname : null), 'email' => $this->decode($client->email), 'address1' => $this->decode($client->address1), 'address2' => $this->decode($client->address2 != "" ? $client->address2 : null), 'city' => $this->decode($client->city), 'state' => $client->state != "" ? substr($client->state, 0, 3) : null, 'zip' => $this->decode($client->postcode != "" ? $client->postcode : null), 'country' => $client->country != "" ? $client->country : $this->default_country, 'date_added' => $this->Companies->dateToUtc($client->datecreated) ); $this->local->insert("contacts", $vars); $contact_id = $this->local->lastInsertId(); $this->mappings['primary_contacts'][$client->id] = $contact_id; // Save client settings $settings = array( 'autodebit' => $client->disableautocc == "on" ? "false" : "true", 'autosuspend' => "true", 'default_currency' => $client->currency_code, 'inv_address_to' => $contact_id, 'inv_method' => "email", 'language' => "en_us", 'tax_exempt' => $client->taxexempt == "on" ? "true" : "false", 'tax_id' => null, 'username_type' => "email" ); $this->Clients->setSettings($client_id, $settings); // Add contact phone number if ($client->phonenumber != "") { $vars = array( 'contact_id' => $contact_id, 'number' => $this->decode($client->phonenumber), 'type' => "phone", 'location' => "home" ); $this->local->insert("contact_numbers", $vars); } $aes->setKey($this->mysqlAesKey(md5($this->settings['key'] . $client->id))); if ($client->cardnum != "") $client->cardnum = $aes->decrypt($client->cardnum); if ($client->expdate != "") $client->expdate = $aes->decrypt($client->expdate); if ($client->bankacct != "") $client->bankacct = $aes->decrypt($client->bankacct); if ($client->bankcode != "") $client->bankcode = $aes->decrypt($client->bankcode); // Add the payment account if ($client->cardnum != "") { $vars = array( 'contact_id' => $this->mappings['primary_contacts'][$client->id], 'first_name' => $this->decode(trim($client->firstname) != "" ? $client->firstname : $this->default_firstname), 'last_name' => $this->decode(trim($client->lastname) != "" ? $client->lastname : $this->default_lastname), 'address1' => $this->decode($client->address1 != "" ? $client->address1 : null), 'address2' => $this->decode($client->address2 != "" ? $client->address2 : null), 'city' => $this->decode($client->city != "" ? $client->city : null), 'state' => $this->decode($client->state != "" ? $client->state : null), 'zip' => $this->decode($client->postcode != "" ? $client->postcode : null), 'country' => $client->country != "" ? $client->country : $this->default_country, 'number' => $client->cardnum, 'expiration' => "20" . substr($client->expdate, 2, 2) . substr($client->expdate, 0, 2) ); $account_id = $this->Accounts->addCc($vars); // Set account for autodebit if ($account_id) { $vars = array( 'client_id' => $this->mappings['clients'][$client->id], 'account_id' => $account_id, 'type' => "cc" ); $this->local->insert("client_account", $vars); } } } $this->local->commit(); unset($clients); // Import custom client fields $custom_fields = $this->WhmcsClients->getCustomFields()->fetchAll(); $this->local->begin(); foreach ($custom_fields as $custom_field) { // Add each field to each client group foreach ($this->mappings['client_groups'] as $remote_group_id => $group_id) { $vars = array( 'client_group_id' => $group_id, 'name' => $this->decode($custom_field->fieldname), 'type' => $this->getFieldType($this->decode($custom_field->fieldtype)), 'values' => $this->getFieldValues($this->decode($custom_field->fieldoptions)), 'regex' => $this->decode($custom_field->regexpr != "" ? $custom_field->regexpr : null), 'show_client' => $custom_field->adminonly == "on" ? "0" : "1" ); $this->local->insert("client_fields", $vars); $this->mappings['client_fields'][$custom_field->id][$remote_group_id] = $this->local->lastInsertId(); } // Insert custom client values for this field $custom_values = $this->fetchall ? $this->WhmcsClients->getCustomFieldValues($custom_field->id)->fetchAll() : $this->WhmcsClients->getCustomFieldValues($custom_field->id); foreach ($custom_values as $custom_value) { if (!isset($this->mappings['clients'][$custom_value->relid])) continue; $vars = array( 'client_field_id' => $this->mappings['client_fields'][$custom_field->id][$custom_value->groupid], 'client_id' => $this->mappings['clients'][$custom_value->relid], 'value' => $this->decode($custom_value->value) ); $this->local->duplicate("value", "=", $vars['value'])->insert("client_values", $vars); } unset($custom_values); } $this->local->commit(); // Import client notes $notes = $this->fetchall ? $this->WhmcsClients->getNotes()->fetchAll() : $this->WhmcsClients->getNotes(); $this->local->begin(); foreach ($notes as $note) { if (!isset($this->mappings['clients'][$note->userid])) continue; $note->note = $this->decode($note->note); $title = wordwrap($note->note, 32, "\n", true); if (strpos($title, "\n") > 0) $title = substr($title, 0, strpos($title, "\n")); $vars = array( 'client_id' => $this->mappings['clients'][$note->userid], 'staff_id' => isset($this->mappings['staff'][$note->adminid]) ? $this->mappings['staff'][$note->adminid] : 0, 'title' => $title, 'description' => trim($title) == trim($note->note) ? null : $note->note, 'stickied' => $note->sticky ? 1 : 0, 'date_added' => $this->Companies->dateToUtc($note->created), 'date_updated' => $this->Companies->dateToUtc($note->modified) ); $this->local->insert("client_notes", $vars); } $this->local->commit(); unset($notes); } /** * Import contacts */ protected function importContacts() { $this->loadModel("WhmcsContacts"); $contacts = $this->fetchall ? $this->WhmcsContacts->get()->fetchAll() : $this->WhmcsContacts->get(); $this->local->begin(); foreach ($contacts as $contact) { $vars = array( 'client_id' => $this->mappings['clients'][$contact->userid], 'contact_type' => "billing", 'first_name' => $this->decode($contact->firstname), 'last_name' => $this->decode($contact->lastname), 'company' => $this->decode($contact->companyname != "" ? $contact->companyname : null), 'email' => $this->decode($contact->email), 'address1' => $this->decode($contact->address1 != "" ? $contact->address1 : null), 'address2' => $this->decode($contact->address2 != "" ? $contact->address2 : null), 'city' => $this->decode($contact->city != "" ? $contact->city : null), 'state' => $this->decode($contact->state != "" ? substr($contact->state, 0, 3) : null), 'zip' => $this->decode($contact->postcode != "" ? $contact->postcode : null), 'country' => $contact->country != "" ? $contact->country : $this->default_country, 'date_added' => $this->Companies->dateToUtc(date("c")) ); $this->local->insert("contacts", $vars); $contact_id = $this->local->lastInsertId(); $this->mappings['contacts'][$contact->id] = $contact_id; // Add contact phone number if ($contact->phonenumber != "") { $vars = array( 'contact_id' => $contact_id, 'number' => $this->decode($contact->phonenumber), 'type' => "phone", 'location' => "home" ); $this->local->insert("contact_numbers", $vars); } } $this->local->commit(); unset($contacts); } /** * Import taxes */ protected function importTaxes() { $this->loadModel("WhmcsTaxes"); $taxes = $this->fetchall ? $this->WhmcsTaxes->get()->fetchAll() : $this->WhmcsTaxes->get(); $this->local->begin(); foreach ($taxes as $tax) { $state = $this->local->select()->from("states")-> where("country_alpha2", "=", $tax->country)-> where("name", "=", trim($tax->state))->fetch(); $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'level' => $tax->level, 'name' => $this->decode($tax->name), 'state' => $state ? $state->code : null, 'country' => $tax->country != "" ? $tax->country : null, 'amount' => $tax->taxrate ); $this->local->insert("taxes", $vars); $tax_id = $this->local->lastInsertId(); $this->mappings['taxes'][$tax->id] = $tax_id; } $this->local->commit(); unset($taxes); } /** * Import currencies */ protected function importCurrencies() { $this->loadModel("WhmcsCurrencies"); $currencies = $this->fetchall ? $this->WhmcsCurrencies->get()->fetchAll() : $this->WhmcsCurrencies->get(); foreach ($currencies as $currency) { $vars = array( 'code' => $currency->code, 'company_id' => Configure::get("Blesta.company_id"), 'format' => $this->getCurrencyFormat((int)$currency->format), 'prefix' => $this->decode($currency->prefix != "" ? $currency->prefix : null), 'suffix' => $this->decode($currency->suffix != "" ? $currency->suffix : null), 'exchange_rate' => $currency->rate, 'exchange_updated' => null ); $this->local-> duplicate("format", "=", $vars['format'])-> duplicate("prefix", "=", $vars['prefix'])-> duplicate("suffix", "=", $vars['suffix'])-> duplicate("exchange_rate", "=", $vars['exchange_rate'])-> insert("currencies", $vars); // Set default currency if ($currency->default == "1") { $this->Companies->setSetting(Configure::get("Blesta.company_id"), "default_currency", $currency->code); } } unset($currencies); } /** * Import invoices */ protected function importInvoices() { $this->loadModel("WhmcsConfiguration"); $this->loadModel("WhmcsInvoices"); Loader::loadModels($this, array("Invoices")); $cascade_tax = false; // Get compound tax setting $cascade = $this->WhmcsConfiguration->get("TaxL2Compound")->fetch(); if ($cascade && $cascade->value == "on") $cascade_tax = true; $invoices = $this->fetchall ? $this->WhmcsInvoices->get()->fetchAll() : $this->WhmcsInvoices->get(); $this->local->begin(); foreach ($invoices as $invoice) { // Get tax rules $level1 = $this->getTaxRule(1, $invoice->taxrate); $level2 = $this->getTaxRule(2, $invoice->taxrate2); $status = "active"; switch (strtolower($invoice->status)) { case "refunded": case "cancelled": $status = "void"; break; default: $status = "active"; break; } if (!$invoice->currency) { $invoice->currency = "AUD"; } $vars = array( 'id_format' => $this->decode($invoice->invoicenum != "" ? $invoice->invoicenum : "{num}"), 'id_value' => $invoice->invoicenum != "" ? 0 : $invoice->id, 'client_id' => $this->mappings['clients'][$invoice->userid], 'date_billed' => $this->Companies->dateToUtc($invoice->date), 'date_due' => $this->Companies->dateToUtc($invoice->duedate), 'date_closed' => strtolower($invoice->status) != "paid" || $invoice->datepaid == "0000-00-00 00:00:00" ? null : $this->Companies->dateToUtc($invoice->datepaid), 'date_autodebit' => null, 'status' => $status, 'previous_due' => 0, 'currency' => $invoice->currency, 'note_public' => $invoice->notes, 'note_private' => null, ); // Manually add the invoice so we can set the correct tax IDs and invoice ID $this->local->insert("invoices", $vars); $local_invoice_id = $this->local->lastInsertId(); $this->mappings['invoices'][$invoice->id] = $local_invoice_id; $this->mappings['invoice_tax_rules'][$invoice->id] = array( 'level1' => $level1, 'level2' => $level2 ); if (!$invoice->currency) { $invoice->currency = "AUD"; } if ($invoice->credit > 0) { $this->credits[] = array( 'invoice_id' => $local_invoice_id, 'client_id' => $this->mappings['clients'][$invoice->userid], 'amount' => $invoice->credit, 'currency' => $invoice->currency, 'transaction_id' => "invoice credit", 'transaction_type' => "other", 'transaction_type_id' => $this->getTransactionTypeId("in_house_credit"), 'status' => 'approved', 'date_added' => $this->Companies->dateToUtc($invoice->date, "c") ); } } $this->local->commit(); unset($invoices); // Import line items $lines = $this->fetchall ? $this->WhmcsInvoices->getLines()->fetchAll() : $this->WhmcsInvoices->getLines(); $this->local->begin(); foreach ($lines as $line) { if (!isset($this->mappings['invoices'][$line->invoiceid])) continue; // Import lines $vars = array( 'invoice_id' => $this->mappings['invoices'][$line->invoiceid], 'service_id' => null, 'description' => $this->decode($line->description), 'qty' => 1, 'amount' => $line->amount, 'order' => 0 ); $this->local->insert("invoice_lines", $vars); $line_id = $this->local->lastInsertId(); // Import tax lines if ($line->taxed > 0) { if ($this->mappings['invoice_tax_rules'][$line->invoiceid]['level1']) { $vars = array( 'line_id' => $line_id, 'tax_id' => $this->mappings['invoice_tax_rules'][$line->invoiceid]['level1']->id ); $this->local->insert("invoice_line_taxes", $vars); } if ($this->mappings['invoice_tax_rules'][$line->invoiceid]['level2']) { $vars = array( 'line_id' => $line_id, 'tax_id' => $this->mappings['invoice_tax_rules'][$line->invoiceid]['level2']->id, 'cascade' => $cascade_tax ? 1 : 0 ); $this->local->insert("invoice_line_taxes", $vars); } } } $this->local->commit(); unset($lines); // Update totals if (isset($this->mappings['invoices'])) { foreach ($this->mappings['invoices'] as $remote_invoice_id => $local_invoice_id) { $subtotal = $this->Invoices->getSubtotal($local_invoice_id); $total = $this->Invoices->getTotal($local_invoice_id); $this->local->where("id", "=", $local_invoice_id)-> update("invoices", array('subtotal' => $subtotal, 'total' => $total)); } } $periods = array( 'Days' => "day", 'Weeks' => "week", 'Months' => "month", 'Years' => "year" ); // Import recurring invoices $lines = $this->fetchall ? $this->WhmcsInvoices->getRecurringLines()->fetchAll() : $this->WhmcsInvoices->getRecurringLines(); $this->local->begin(); foreach ($lines as $line) { if (!$line->currency) { $line->currency = "AUD"; } if (!isset($periods[$line->recurcycle])) continue; $vars = array( 'client_id' => $this->mappings['clients'][$line->userid], 'term' => $line->recur, 'period' => $periods[$line->recurcycle], 'duration' => $line->recurfor > 0 ? $line->recurfor : null, 'date_renews' => $this->Companies->dateToUtc($line->duedate), 'currency' => $line->currency, 'lines' => array( array( 'description' => $this->decode($line->description), 'qty' => 1, 'amount' => $line->amount, 'tax' => 0 ) ), 'delivery' => array('email') ); $recurring_id = $this->Invoices->addRecurring($vars); if ($recurring_id) $this->mappings['recurring_invoices'][$line->id] = $recurring_id; } $this->local->commit(); unset($lines); if (isset($this->mappings['recurring_invoices'])) { // Record each recurring invoice instance $this->local->begin(); foreach ($this->mappings['recurring_invoices'] as $remote_id => $recurring_id) { $lines = $this->fetchall ? $this->WhmcsInvoices->getRecurInstances($remote_id)->fetchAll() : $this->WhmcsInvoices->getRecurInstances($remote_id); foreach ($lines as $line) { $vars = array( 'invoice_recur_id' => $recurring_id, 'invoice_id' => $this->mappings['invoices'][$line->invoiceid] ); $this->local->insert("invoices_recur_created", $vars); } unset($lines); } $this->local->commit(); } } /** * Import transactions */ protected function importTransactions() { $this->loadModel("WhmcsAccounts"); $this->loadModel("WhmcsCurrencies"); Loader::loadModels($this, array("Invoices")); $default_currency = $this->WhmcsCurrencies->getDefaultCode(); if (!$default_currency) { $default_currency = "AUD"; } $invoice_ids = array(); // Add invoice credits $this->local->begin(); foreach ($this->credits as $credit) { $transaction_id = $this->addTransaction($credit, null); $vars = array( 'date' => $credit['date_added'], 'amounts' => array( array( 'invoice_id' => $credit['invoice_id'], 'amount' => $credit['amount'], ) ) ); $this->Transactions->apply($transaction_id, $vars); if (!in_array($credit['invoice_id'], $invoice_ids)) $invoice_ids[] = $credit['invoice_id']; } $this->local->commit(); unset($this->credits); $transactions = $this->fetchall ? $this->WhmcsAccounts->get(true)->fetchAll() : $this->WhmcsAccounts->get(true); $this->local->begin(); foreach ($transactions as $transaction) { if (!isset($this->mappings['clients'][$transaction->userid])) continue; $currency = $default_currency; if (!$currency) { $currency = "AUD"; } if ($transaction->trans_currency != "") $currency = $transaction->trans_currency; elseif ($transaction->client_currency != "") $currency = $transaction->client_currency; // Only add income transactions if ($transaction->amountin > 0) { $status = ($transaction->refund > 0 ? "refunded" : "approved"); $vars = array( 'client_id' => $this->mappings['clients'][$transaction->userid], 'amount' => $transaction->amountin, 'currency' => $currency, 'transaction_id' => $transaction->transid, 'status' => $status, 'date_added' => $this->Companies->dateToUtc($transaction->date, "c") ); $transaction_id = $this->addTransaction($vars, $transaction->id); // If the transactions was refunded add a new transaction for the difference if ($status == "refunded" && $transaction->refund < $transaction->amountin) { $vars = array( 'client_id' => $this->mappings['clients'][$transaction->userid], 'amount' => $transaction->amountin - $transaction->refund, 'currency' => $currency, 'transaction_id' => $transaction->transid, 'status' => "approved", 'date_added' => $this->Companies->dateToUtc($transaction->date, "c") ); $transaction_id = $this->addTransaction($vars, $transaction->id); } } // Apply payment if (isset($this->mappings['invoices'][$transaction->invoiceid]) && $transaction->amountin > 0) { $vars = array( 'date' => $this->Companies->dateToUtc($transaction->date, "c"), 'amounts' => array( array( 'invoice_id' => $this->mappings['invoices'][$transaction->invoiceid], 'amount' => $transaction->amountin - ($transaction->refund > 0 ? $transaction->refund : 0), ) ) ); $this->Transactions->apply($transaction_id, $vars); if (!in_array($this->mappings['invoices'][$transaction->invoiceid], $invoice_ids)) $invoice_ids[] = $this->mappings['invoices'][$transaction->invoiceid]; } } $this->local->commit(); unset($transactions); // Add client credits $credits = $this->fetchall ? $this->WhmcsAccounts->getOpenCredits()->fetchAll() : $this->WhmcsAccounts->getOpenCredits(); $this->local->begin(); foreach ($credits as $credit) { if (!$credit->currency) { $credit->currency = "AUD"; } if (!isset($this->mappings['clients'][$credit->userid])) continue; $vars = array( 'client_id' => $this->mappings['clients'][$credit->userid], 'amount' => $credit->credit, 'currency' => $credit->currency, 'type' => 'other', 'transaction_type_id' => $this->getTransactionTypeId("in_house_credit"), 'transaction_id' => null, 'status' => 'approved', 'date_added' => $this->Companies->dateToUtc(date("c")) ); $transaction_id = $this->addTransaction($vars, $transaction->id); } $this->local->commit(); unset($credits); // Update paid totals $this->local->begin(); foreach ($invoice_ids as $invoice_id) { // Update paid total $paid = $this->Invoices->getPaid($invoice_id); $this->local->where("id", "=", $invoice_id)-> update("invoices", array('paid' => $paid)); } $this->local->commit(); $this->balanceClientCredit(); } /** * Verifies that total transaction credit for a each client matches credit * set in WHMCS */ protected function balanceClientCredit() { if ($this->settings['balance_credit'] != "true") return; $this->loadModel("WhmcsAccounts"); if (!isset($this->Transactions)) Loader::loadModels($this, array("Transactions")); if (!isset($this->Invoices)) Loader::loadModels($this, array("Invoices")); // Fetch all client credit values $credits = $this->WhmcsAccounts->getCredits(); $date = date("c"); foreach ($credits as $credit) { if (!isset($this->mappings['clients'][$credit->userid])) continue; $client_id = $this->mappings['clients'][$credit->userid]; $total_credit = $this->Transactions->getTotalCredit($client_id, $credit->currency); $credit_diff = round($total_credit-$credit->credit, 4); // We have excess credit, so consume it if ($credit_diff > 0) { // Create an invoice to balance credits $vars = array( 'client_id' => $client_id, 'currency' => $credit->currency, 'date_billed' => $date, 'date_due' => $date, 'status' => "active", 'lines' => array( array( 'description' => "Automatic credit balance adjustment.", 'qty' => 1, 'amount' => $credit_diff ) ) ); $invoice_id = $this->Invoices->add($vars); // Consume the credit $amounts = array( array( 'invoice_id' => $invoice_id, 'amount' => $credit_diff ) ); $this->Transactions->applyFromCredits($client_id, $credit->currency, $amounts); } elseif ($credit_diff < 0) { // Create transaction to hold the credit diff $vars = array( 'client_id' => $client_id, 'amount' => -1*$credit_diff, 'currency' => $credit->currency, 'type' => 'other', 'transaction_type_id' => $this->getTransactionTypeId("in_house_credit"), 'transaction_id' => null, 'status' => 'approved', 'date_added' => $this->Companies->dateToUtc($date) ); $transaction_id = $this->addTransaction($vars, $transaction->id); } } } /** * Import modules */ protected function importModules() { $this->loadModel("WhmcsProducts"); // Import generic server module required for all package assigned to no module $this->installModuleRow(array('id' => "generic_server", 'type' => "generic_server")); // Import servers $rows = $this->fetchall ? $this->WhmcsProducts->getServers()->fetchAll() : $this->WhmcsProducts->getServers(); foreach ($rows as $row) { $this->installModuleRow((array)$row); } unset($rows); // Import registrars foreach ($this->WhmcsProducts->getReigstrars() as $registrar) { $row = $this->WhmcsProducts->getRegistrarFields($registrar); foreach ($row as &$value) { $value = $this->decryptData($value); } $row['id'] = $registrar; $row['type'] = $registrar; $this->installModuleRow($row, "registrar"); } } /** * Import packages */ protected function importPackages() { $this->importModules(); $this->loadModel("WhmcsProducts"); $this->loadModel("WhmcsConfiguration"); Loader::loadModels($this, array("PackageGroups")); // Add imported package group $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'name' => "Imported", 'type' => "standard" ); $package_group_id = $this->PackageGroups->add($vars); $products = $this->WhmcsProducts->get()->fetchAll(); $i=1; $this->local->begin(); foreach ($products as $product) { if (!isset($this->mappings['modules'][$product->servertype])) $product->servertype = "generic_server"; $pricing = $this->WhmcsProducts->getPricing($product->id); $mapping = $this->getModuleMapping($product->servertype); // Add package $vars = array( 'id_format' => "{num}", 'id_value' => $product->id, 'module_id' => $this->mappings['modules'][$product->servertype], 'name' => $this->decode($product->name), 'description' => strip_tags($this->decode($product->description)), 'description_html' => $this->decode($product->description), 'qty' => $product->stockcontrol == "on" ? $product->qty : null, 'module_row' => 0, // WHMCS doesn't associate a service with a product 'module_group' => null, 'taxable' => $product->tax, 'status' => $product->retired == "1" ? "inactive" : "active", 'company_id' => Configure::get("Blesta.company_id") ); $this->local->insert("packages", $vars); $this->mappings['packages'][$product->id] = $this->local->lastInsertId(); // Assign group $this->local->insert("package_group", array('package_id' => $this->mappings['packages'][$product->id], 'package_group_id' => $package_group_id)); // Add package pricing $this->addPackagePricing($pricing, $this->mappings['packages'][$product->id]); // Import package meta $this->addPackageMeta((array)$product, $mapping); $i = max(++$i, $product->id); } $this->local->commit(); $taxable = 0; $tax_domains = $this->WhmcsConfiguration->get("TaxDomains")->fetch(); if ($tax_domains) $taxable = $tax_domains->value == "on" ? 1 : 0; $tlds = $this->WhmcsProducts->getTlds(); $this->local->begin(); foreach ($tlds as $tld) { $pricing = $this->WhmcsProducts->getTldPricing($tld->extension); $registrar = trim($tld->autoreg); if ($registrar == "") continue; $mapping = $this->getModuleMapping($registrar, "registrar"); $vars = array( 'id_format' => "{num}", 'id_value' => max($tld->id, $i++), 'module_id' => $this->mappings['modules'][$registrar], 'name' => "Domain Registration (" . $tld->extension . ")", 'description' => null, 'description_html' => null, 'qty' => null, 'module_row' => !isset($this->mappings['module_rows'][$registrar][$registrar]) ? 0 : $this->mappings['module_rows'][$registrar][$registrar], 'module_group' => null, 'taxable' => $taxable, 'status' => "active", 'company_id' => Configure::get("Blesta.company_id") ); // Add the package $this->local->insert("packages", $vars); $this->mappings['packages'][$tld->extension . $registrar] = $this->local->lastInsertId(); // Assign group $this->local->insert("package_group", array('package_id' => $this->mappings['packages'][$tld->extension . $registrar], 'package_group_id' => $package_group_id)); // Add package pricing $this->addPackagePricing($pricing, $this->mappings['packages'][$tld->extension . $registrar]); // Import package meta $product = array( 'id' => $tld->extension . $registrar, 'tlds' => array($tld->extension) ); $this->addPackageMeta($product, $mapping); } $this->local->commit(); } /** * Import package options */ protected function importPackageOptions() { $this->loadModel("WhmcsProducts"); Loader::loadModels($this, array("PackageOptionGroups", "PackageOptions")); $option_types = $this->WhmcsProducts->getConfigOptionTypes(); $option_groups = $this->WhmcsProducts->getConfigOptionGroups(); foreach ($option_groups as $option_group) { $packages = array(); // Map WHMCS packages to packages in Blesta foreach ($option_group->packages as $package_id) { if (isset($this->mappings['packages'][$package_id])) { $packages[] = $this->mappings['packages'][$package_id]; } } $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'name' => $option_group->name, 'description' => $option_group->description, 'packages' => $packages ); $option_group_id = $this->PackageOptionGroups->add($vars); // Record package group mapping $this->mappings['package_options_groups'][$option_group->id] = $option_group_id; // Import package options $options = $this->WhmcsProducts->getConfigOptions($option_group->id); foreach ($options as $option) { $values = array(); foreach ($option->values as $value) { $is_qty = isset($option_types[$option->optiontype]) && $option_types[$option->optiontype] == "quantity"; $values[] = array( 'name' => $value->optionname, 'value' => $is_qty ? null : $value->optionname, 'min' => $is_qty ? max(0, $option->qtyminimum) : null, 'max' => $is_qty && $option->qtymaximum > 0 ? max(1, $option->qtymaximum) : null, 'step' => $is_qty ? "1" : null, 'pricing' => $this->WhmcsProducts->getPricing($value->id, "configoptions") ); } // WHMCS only supports one group per option... weak! $groups = array($this->mappings['package_options_groups'][$option->gid]); $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'label' => $option->optionname, 'name' => $option->optionname, 'type' => isset($option_types[$option->optiontype]) ? $option_types[$option->optiontype] : "select", 'values' => $values, 'groups' => $groups ); $option_id = $this->PackageOptions->add($vars); // Record package option mapping $this->mappings['package_options'][$option->id] = $option_id; // Record package option value mappings $opt_values = $this->PackageOptions->getValues($option_id); foreach ($opt_values as $v => $val) { $this->mappings['option_values'][$option->values[$v]->id] = $val->id; } } } } /** * Import services */ protected function importServices() { $this->loadModel("WhmcsServices"); $this->loadModel("WhmcsProducts"); Loader::loadModels($this, array("Clients", "Packages")); $servers = array(); $rows = $this->fetchall ? $this->WhmcsProducts->getServers()->fetchAll() : $this->WhmcsProducts->getServers(); foreach ($rows as $row) { $servers[$row->id] = $row; } unset($rows); $services = $this->fetchall ? $this->WhmcsServices->get()->fetchAll() : $this->WhmcsServices->get(); $this->local->begin(); foreach ($services as $service) { // If the client doesn't exist, we can't import the service if (!isset($this->mappings['clients'][$service->userid])) continue; // If the package doesn't exist, we can't import the service if (!isset($this->mappings['packages'][$service->packageid])) continue; $package = $this->Packages->get($this->mappings['packages'][$service->packageid]); if (!isset($this->mappings['modules'])) { if (!isset($this->ModuleManager)) Loader::loadModels($this, array("ModuleManager")); $module = $this->ModuleManager->get($package->module_id, false, false); if ($module) $modules[$package->module_id] = $module->class; } else $modules = array_flip($this->mappings['modules']); $mapping = $this->getModuleMapping(isset($modules[$package->module_id]) ? $modules[$package->module_id] : "generic_server"); // Get currency this client is invoiced in $currency = $this->getCurrency($this->mappings['clients'][$service->userid]); if (!$currency) { $currency = "AUD"; } if ($package->module_row > 0) $module_row_id = $package->module_row; else { if (isset($mapping['module_row_key']) && isset($servers[$service->server]->{$mapping['module_row_key']})) $module_row_id = $this->getModuleRowId($package->module_id, $servers[$service->server]->{$mapping['module_row_key']}, null); else $module_row_id = $this->getModuleRowId($package->module_id, null, isset($modules[$package->module_id]) ? $modules[$package->module_id] : null); } if (!$module_row_id) continue; $status = $this->getServiceStatus($service->domainstatus); $pricing = $this->getPricing($this->WhmcsServices->getTerm($service->billingcycle), $package, $currency, $service->amount); $override_price = (($p = number_format($pricing->price, 2, '.', '')) == number_format($service->amount, 2, '.', '') ? $p : null); $override_currency = ($override_price === null ? null : $currency); $vars = array( 'parent_service_id' => null, 'package_group_id' => null, 'id_format' => "{num}", 'id_value' => $service->id, 'pricing_id' => $pricing->id, 'client_id' => $this->mappings['clients'][$service->userid], 'module_row_id' => $module_row_id, 'coupon_id' => null, 'qty' => 1, 'override_price' => $override_price, 'override_currency' => $override_currency, 'status' => $status, 'date_added' => $this->Companies->dateToUtc($service->regdate . " 00:00:00"), 'date_renews' => $service->nextinvoicedate == "0000-00-00" ? null : $this->Companies->dateToUtc($service->nextinvoicedate . " 00:00:00"), 'date_last_renewed' => null, 'date_suspended' => $status == "suspended" ? $this->Companies->dateToUtc(date("c")) : null, 'date_canceled' => $status == "canceled" ? $this->Companies->dateToUtc(date("c")) : null ); $this->local->insert("services", $vars); $service_id = $this->local->lastInsertId(); $this->mappings['services'][$service->id] = $service_id; $this->addServiceFields((array)$service, $mapping); } $this->local->commit(); unset($services); $option_types = $this->WhmcsProducts->getConfigOptionTypes(); // Import options for services $options = $this->WhmcsServices->getConfigOptions(); $this->local->begin(); foreach ($options as $option) { // Ensure parent service exists if (!isset($this->mappings['services'][$option->relid])) continue; $currency = $this->getCurrency($this->mappings['clients'][$option->userid]); if (!$currency) { $currency = "AUD"; } $value_id = $this->mappings['option_values'][$option->optionid]; $pricing = $this->getOptionPricing($this->WhmcsServices->getTerm($option->billingcycle), $value_id, $currency); if (!$pricing) { continue; } $vars = array( 'service_id' => $this->mappings['services'][$option->relid], 'option_pricing_id' => $pricing->id, // option isn't a quantity type, set qty to 1 'qty' => $option_types[$option->optiontype] == "quantity" ? $option->qty : 1 ); $this->local->insert("service_options", $vars); } $this->local->commit(); unset($options); $services = $this->fetchall ? $this->WhmcsServices->getDomains()->fetchAll() : $this->WhmcsServices->getDomains(); $this->local->begin(); foreach ($services as $service) { // If the client doesn't exist, we can't import the service if (!isset($this->mappings['clients'][$service->userid])) continue; if ($service->registrar == "") $service->registrar = "generic_registrar"; $tld = $this->getTld($service->domain, $service->registrar); // If package does not exist, we can't import the service if (!isset($this->mappings['packages'][$tld . $service->registrar])) continue; $package = $this->Packages->get($this->mappings['packages'][$tld . $service->registrar]); $mapping = $this->getModuleMapping($service->registrar, "registrar"); // Get currency this client is invoiced in $currency = $this->getCurrency($this->mappings['clients'][$service->userid]); if (!$currency) { $currency = "AUD"; } $module_row_id = $this->mappings['module_rows'][$service->registrar][$service->registrar]; if (!$module_row_id) continue; $status = $this->getServiceStatus($service->status); $pricing = $this->getPricing($this->WhmcsServices->getTerm($service->registrationperiod), $package, $currency, $service->recurringamount); $override_price = (($p = number_format($pricing->price, 2, '.', '')) == number_format($service->recurringamount, 2, '.', '') ? $p : null); $override_currency = ($override_price === null ? null : $currency); $vars = array( 'parent_service_id' => null, 'package_group_id' => null, 'id_format' => "{num}", 'id_value' => $service->id, 'pricing_id' => $pricing->id, 'client_id' => $this->mappings['clients'][$service->userid], 'module_row_id' => $module_row_id, 'coupon_id' => null, 'qty' => 1, 'override_price' => $override_price, 'override_currency' => $override_currency, 'status' => $status, 'date_added' => $this->Companies->dateToUtc($service->registrationdate . " 00:00:00"), 'date_renews' => $service->nextinvoicedate == "0000-00-00" ? null : $this->Companies->dateToUtc($service->nextinvoicedate . " 00:00:00"), 'date_last_renewed' => null, 'date_suspended' => $status == "suspended" ? $this->Companies->dateToUtc(date("c")) : null, 'date_canceled' => $status == "canceled" ? $this->Companies->dateToUtc(date("c")) : null ); $this->local->insert("services", $vars); $service_id = $this->local->lastInsertId(); $this->mappings['services'][$service->id] = $service_id; $this->addServiceFields((array)$service, $mapping); } $this->local->commit(); unset($services); } /** * Import support departments */ protected function importSupportDepartments() { Loader::loadModels($this, array("PluginManager")); // Install support plugin if not already installed if (!$this->PluginManager->isInstalled("support_manager", Configure::get("Blesta.company_id"))) $this->PluginManager->add(array('dir' => "support_manager", 'company_id' => Configure::get("Blesta.company_id"))); $this->loadModel("WhmcsSupportDepartments"); $departments = $this->fetchall ? $this->WhmcsSupportDepartments->get()->fetchAll() : $this->WhmcsSupportDepartments->get(); $this->local->begin(); foreach ($departments as $department) { $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'name' => $this->decode($department->name), 'description' => $this->decode($department->description), 'email' => $this->decode($department->email), 'method' => $department->piperepliesonly == "on" ? "pipe" : "pop3", 'default_priority' => "medium", 'host' => $this->decode($department->host), 'user' => $this->decode($department->login), 'pass' => $this->decryptData($department->password), 'port' => $department->port, 'security' => "none", 'box_name' => null, 'mark_messages' => "deleted", 'clients_only' => $department->clientsonly == "on" ? 1 : 0, 'status' => $department->hidden == "on" ? "hidden" : "visible" ); $this->local->insert("support_departments", $vars); $department_id = $this->local->lastInsertId(); $this->mappings['support_departments'][$department->id] = $department_id; } $this->local->commit(); unset($departments); // Assign admins to support departments $this->local->begin(); foreach ($this->mappings['admin_departs'] as $remote_admin_id => $departs) { if (!isset($this->mappings['staff'][$remote_admin_id])) continue; $departs = explode(",", $departs); foreach ($departs as $depart_id) { $depart_id = trim($depart_id); if (isset($this->mappings['support_departments'][$depart_id])) { $vars = array( 'department_id' => $this->mappings['support_departments'][$depart_id], 'staff_id' => $this->mappings['staff'][$remote_admin_id] ); $this->local-> duplicate("staff_id", "=", $this->mappings['staff'][$remote_admin_id])-> insert("support_staff_departments", $vars); } } // Add schedules $days = array("sun", "mon", "tue", "wed", "thu", "fri", "sat"); foreach ($days as $day) { $vars = array( 'staff_id' => $this->mappings['staff'][$remote_admin_id], 'company_id' => Configure::get("Blesta.company_id"), 'day' => $day, 'start_time' => "00:00:00", 'end_time' => "00:00:00" ); try { $this->local->insert("support_staff_schedules", $vars); } catch (Exception $e) { $this->local->reset(); } } // Add notices $keys = array("ticket_emails"); foreach ($keys as $key) { $vars = array( 'key' => $key, 'company_id' => Configure::get("Blesta.company_id"), 'staff_id' => $this->mappings['staff'][$remote_admin_id], 'value' => serialize(array('emergency' => "true", 'critical' => "true", 'high' => "true", 'medium' => "true", 'low' => "true")) ); try { $this->local->insert("support_staff_settings", $vars); } catch (Exception $e) { $this->local->reset(); } } } $this->local->commit(); } /** * Import support tickets */ protected function importSupportTickets() { $this->loadModel("WhmcsSupportTickets"); $priorities = array( 'High' => 'high', 'Medium' => 'medium', 'Low' => 'low' ); $statuses = array( 'Open' => 'open', 'Answered' => 'closed', 'Customer-Reply' => 'awaiting_reply', 'Closed' => 'closed', 'In Progress' => 'in_progress' ); $tickets = $this->fetchall ? $this->WhmcsSupportTickets->get()->fetchAll() : $this->WhmcsSupportTickets->get(); $this->local->begin(); foreach ($tickets as $ticket) { $vars = array( 'code' => is_numeric($ticket->tid) ? (int)$ticket->tid : preg_replace("/[^0-9]+/", "", $ticket->tid), 'department_id' => isset($this->mappings['support_departments'][$ticket->did]) ? $this->mappings['support_departments'][$ticket->did] : 0, 'staff_id' => null, 'service_id' => null, 'client_id' => $ticket->userid > 0 && isset($this->mappings['clients'][$ticket->userid]) ? $this->mappings['clients'][$ticket->userid] : null, 'email' => $this->decode($ticket->email != "" ? $ticket->email : null), 'summary' => $this->decode($ticket->title), 'priority' => isset($priorities[$ticket->urgency]) ? $priorities[$ticket->urgency] : 'medium', 'status' => isset($statuses[$ticket->status]) ? $statuses[$ticket->status] : 'open', 'date_added' => $this->Companies->dateToUtc($ticket->date), 'date_closed' => isset($statuses[$ticket->status]) && $statuses[$ticket->status] == "closed" ? $this->Companies->dateToUtc($ticket->lastreply) : null, ); $this->local->insert("support_tickets", $vars); $this->mappings['support_tickets'][$ticket->id] = $this->local->lastInsertId(); // Add ticket body $vars = array( 'ticket_id' => $this->mappings['support_tickets'][$ticket->id], 'staff_id' => $ticket->admin_id && isset($this->mappings['staff'][$ticket->admin_id]) ? $this->mappings['staff'][$ticket->admin_id] : null, 'type' => "reply", 'details' => $this->decode($ticket->message), 'date_added' => $this->Companies->dateToUtc($ticket->date), ); $this->local->insert("support_replies", $vars); } $this->local->commit(); unset($tickets); // Import ticket replies $replies = $this->fetchall ? $this->WhmcsSupportTickets->getReplies()->fetchAll() : $this->WhmcsSupportTickets->getReplies(); $this->local->begin(); foreach ($replies as $reply) { if (!isset($this->mappings['support_tickets'][$reply->tid])) continue; $vars = array( 'ticket_id' => $this->mappings['support_tickets'][$reply->tid], 'staff_id' => $reply->admin_id && isset($this->mappings['staff'][$reply->admin_id]) ? $this->mappings['staff'][$reply->admin_id] : null, 'type' => "reply", 'details' => $this->decode($reply->message), 'date_added' => $this->Companies->dateToUtc($reply->date), ); $this->local->insert("support_replies", $vars); } $this->local->commit(); unset($replies); // Import ticket notes $notes = $this->fetchall ? $this->WhmcsSupportTickets->getNotes()->fetchAll() : $this->WhmcsSupportTickets->getNotes(); $this->local->begin(); foreach ($notes as $note) { if (!isset($this->mappings['support_tickets'][$note->ticketid])) continue; $vars = array( 'ticket_id' => $this->mappings['support_tickets'][$note->ticketid], 'staff_id' => $note->admin_id && isset($this->mappings['staff'][$note->admin_id]) ? $this->mappings['staff'][$note->admin_id] : null, 'type' => "note", 'details' => $this->decode($note->message), 'date_added' => $this->Companies->dateToUtc($note->date), ); $this->local->insert("support_replies", $vars); } $this->local->commit(); unset($notes); // Import predefined categories $categories = $this->fetchall ? $this->WhmcsSupportTickets->getResponseCategories()->fetchAll() : $this->WhmcsSupportTickets->getResponseCategories(); $this->local->begin(); foreach ($categories as $category) { $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'parent_id' => isset($this->mappings['support_response_categories'][$category->parentid]) ? $this->mappings['support_response_categories'][$category->parentid] : null, 'name' => $this->decode($category->name) ); $this->local->insert("support_response_categories", $vars); $this->mappings['support_response_categories'][$category->id] = $this->local->lastInsertId(); } $this->local->commit(); unset($categories); // Import predefined replies $responses = $this->fetchall ? $this->WhmcsSupportTickets->getResponses()->fetchAll() : $this->WhmcsSupportTickets->getResponses(); $this->local->begin(); foreach ($responses as $response) { if (!isset($this->mappings['support_response_categories'][$response->catid])) continue; $vars = array( 'category_id' => $this->mappings['support_response_categories'][$response->catid], 'name' => $this->decode($response->name), 'details' => $this->decode($response->reply) ); $this->local->insert("support_responses", $vars); } $this->local->commit(); unset($responses); } /** * Import miscellaneous */ protected function importMisc() { $this->loadModel("WhmcsEmails"); $this->loadModel("WhmcsConfiguration"); $this->loadModel("WhmcsCalendar"); $from_name = $this->WhmcsConfiguration->get("SystemEmailsFromName")->fetch(); $from_email = $this->WhmcsConfiguration->get("SystemEmailsFromEmail")->fetch(); // Mail log $this->startTimer("mail log"); $this->local->begin(); foreach ($this->WhmcsEmails->get() as $message) { if ($message->to == "") continue; $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'to_client_id' => $message->userid > 0 && isset($this->mappings['clients'][$message->userid]) ? $this->mappings['clients'][$message->userid] : null, 'from_staff_id' => null, 'to_address' => $this->decode($message->to), 'from_address' => $this->decode($from_email->value), 'from_name' => $this->decode($from_name->value), 'cc_address' => $this->decode($message->cc != "" ? $message->cc : null), 'subject' => $this->decode($message->subject != "" ? $message->subject : " "), 'body_text' => strip_tags($this->decode($message->message)), 'body_html' => $this->decode($message->message), 'sent' => 1, 'error' => null, 'date_sent' => $this->Companies->dateToUtc($message->date) ); $this->local->insert("log_emails", $vars); } $this->local->commit(); $this->endTimer("mail log"); // Configurations $this->startTimer("settings"); $settings = $this->fetchall ? $this->WhmcsConfiguration->get()->fetchAll() : $this->WhmcsConfiguration->get(); $this->local->begin(); foreach ($settings as $setting) { $setting->value = $this->decode($setting->value); switch ($setting->setting) { case "MailType": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "mail_delivery", $setting->value == "mail" ? "php" : $setting->value); break; case "SMTPHost": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "smtp_host", $setting->value); break; case "SMTPUsername": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "smtp_user", $setting->value); break; case "SMTPPassword": if ($setting->value != "") $this->Companies->setSetting(Configure::get("Blesta.company_id"), "smtp_user", $this->decryptData($setting->value)); break; case "SMTPPort": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "smtp_port", $setting->value); break; case "SMTPSSL": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "smtp_security", $setting->value); break; case "CreateInvoiceDaysBefore": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "inv_days_before_renewal", $setting->value); break; case "SendInvoiceReminderDays": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "notice1", $setting->value != 0 ? -1 * $setting->value : "disabled"); break; case "SendFirstOverdueInvoiceReminder": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "notice2", $setting->value != 0 ? $setting->value : "disabled"); break; case "SendSecondOverdueInvoiceReminder": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "notice3", $setting->value != 0 ? $setting->value : "disabled"); break; case "CCProcessDaysBefore": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "autodebit_days_before_due", $setting->value); break; case "AutoSuspensionDays": $this->Companies->setSetting(Configure::get("Blesta.company_id"), "suspend_services_days_after_due", $setting->value); break; } } $this->local->commit(); $this->endTimer("settings"); unset($settings); // Import calendar events $this->startTimer("calendar events"); $events = $this->fetchall ? $this->WhmcsCalendar->get()->fetchAll() : $this->WhmcsCalendar->get(); $this->local->begin(); foreach ($events as $event) { $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'staff_id' => isset($this->mappings['staff'][$event->adminid]) ? $this->mappings['staff'][$event->adminid] : 0, 'shared' => 0, 'title' => $this->decode($event->title . " " . $event->desc), 'url' => null, 'start_date' => $this->Companies->dateToUtc($event->start), 'end_date' => $event->end != 0 ? $this->Companies->dateToUtc($event->end) : $this->Companies->dateToUtc($event->start), 'all_day' => $event->allday ); $this->local->insert("calendar_events", $vars); } $this->local->commit(); $this->endTimer("calendar events"); unset($events); // Import todo events $this->startTimer("todo events"); $events = $this->fetchall ? $this->WhmcsCalendar->getTodos()->fetchAll() : $this->WhmcsCalendar->getTodos(); $this->local->begin(); foreach ($events as $event) { $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'staff_id' => isset($this->mappings['staff'][$event->admin]) ? $this->mappings['staff'][$event->admin] : 0, 'shared' => 0, 'title' => $this->decode($event->title . " " . $event->description), 'url' => null, 'start_date' => $this->Companies->dateToUtc($event->date), 'end_date' => $this->Companies->dateToUtc($event->duedate), 'all_day' => 1 ); $this->local->insert("calendar_events", $vars); } $this->local->commit(); $this->startTimer("todo events"); unset($events); } /** * Load the given local model * * @param string $name The name of the model to load */ protected function loadModel($name) { $name = Loader::toCamelCase($name); $file = Loader::fromCamelCase($name); Loader::load($this->path . DS . "models" . DS . $file . ".php"); $this->{$name} = new $name($this->remote); } /** * Creates a user * * @param array $user An array of key/value pairs including: * - username * - password * - date_added */ private function createUser(array $user) { $this->local->insert("users", $user); return $this->local->lastInsertId(); } /** * Returns the field type * * @param string WHMCS field type * @return string Blesta field type */ private function getFieldType($type) { switch ($type) { case "text": case "textarea": return $type; break; case "dropdown": return "select"; case "tickbox": return "checkbox"; default: return "text"; } } /** * Returns the serialized selection of field values * * @param string WHMCS serialized values * @return string Blesta serialized values */ private function getFieldValues($values) { if ($values == "") return null; $values = explode(",", $values); return serialize(array_combine($values, $values)); } /** * Returns the currency format * * @param int WHMCS currency format value * @return string Blesta currency format value */ private function getCurrencyFormat($format) { switch ($format) { default: case 1: case 2: return "#,###.##"; case 3: return "#.###,##"; case 4: return "#,###"; } } /** * Returns the local tax rule for the given level and rate * * @param int $level * @param float $rate * @return mixed A stdClass object representing the local tax rule, false if no rule exists */ private function getTaxRule($level, $rate) { return $this->local->select()->from("taxes")-> where("company_id", "=", Configure::get("Blesta.company_id"))-> where("level", "=", $level)->where("amount", "=", $rate)->fetch(); } /** * Returns the transaction type ID * * @param string $type The version 2 transaction type * @return string The transaction type ID */ private function getTransactionTypeId($type) { static $trans_types = null; if (!isset($this->Transactions)) Loader::loadModels($this, array("Transactions")); if ($trans_types == null) $trans_types = $this->Transactions->getTypes(); switch ($type) { default: case "other": case "credit": return null; case "cash": case "check": foreach ($trans_types as $trans_type) { if ($trans_type->name == $type) return $trans_type->id; } case "in_house_credit": foreach ($trans_types as $trans_type) { if ($trans_type->name == "in_house_credit") return $trans_type->id; } case "money_order": foreach ($trans_types as $trans_type) { if ($trans_type->name == "money_order") return $trans_type->id; } } return null; } /** * Convert WHMCS service status into Blesta service status * * @param string $status * @return string The service status */ private function getServiceStatus($status) { $status = strtolower($status); switch ($status) { case "active": case "pending": case "suspended": return $status; case "fraud": case "terminated": case "cancelled": return "canceled"; } return "in_review"; } /** * Decrypts data from WHMCS * * @param string $data The data to decrypt * @return string The decrypted data */ private function decryptData($str) { $this->decrypt_count++; $this->unpauseTimer("decrypt"); $key = $this->settings['key']; $y = base64_decode($str); $x = null; // Key derivation $key = sha1(md5(md5($key)) . md5($key)); $temp_key = null; for ($i=0; $i<strlen($key); $i+=2) { $temp_key .= chr(hexdec($key[$i] . $key[$i + 1])); } $key = $temp_key; $key_length = strlen($key); // Extract key seed from input $key_seed = substr($y, 0, $key_length); $y = substr($y, $key_length, strlen($y) - $key_length); // Calculate final key $z = null; for ($i=0; $i<$key_length; $i++) { $z .= chr(ord($key_seed[$i]) ^ ord($key[$i])); } // Decrypt for ($i=0; $i<strlen($y); $i++) { // Generate new key schedule for each block if ($i != 0 && $i % $key_length == 0) { $temp = sha1($z . substr($x, $i - $key_length, $key_length)); $z = null; for ($j=0; $j<strlen($temp); $j+=2) { $z .= chr(hexdec($temp[$j] . $temp[$j+1])); } } $x .= chr(ord($z[$i % $key_length]) ^ ord($y[$i])); } $this->pauseTimer("decrypt"); return $x; } /** * Formats the given key into a mysql AES key * * @param string $key The AES key to format * @return string The mysql formatted AES key */ private function mysqlAesKey($key) { $new_key = str_repeat(chr(0), 16); for($i=0,$len=strlen($key);$i<$len;$i++) { $new_key[$i%16] = $new_key[$i%16] ^ $key[$i]; } return $new_key; } /** * Installs the module row * * @param array $row An array of key/value pairs, including but not limited to: * - type The module name in WHMCS * - id The row ID in WHMCS * @param string $module_type The type of module ('server' or 'registrar') * @return int The module row ID installed (also saved in mappings['modules'] property) */ private function installModuleRow($row, $module_type = "server") { if (!isset($this->ModuleManager)) Loader::loadModels($this, array("ModuleManager")); $mapping = $this->getModuleMapping($row['type'], $module_type); $module_id = $this->installModule($row['type'], $mapping); if (!$module_id) return null; // Install the module row $this->local->insert("module_rows", array('module_id' => $module_id)); $module_row_id = $this->local->lastInsertId(); $this->mappings['module_rows'][$row['type']][$row['id']] = $module_row_id; // Install the module row meta fields if (isset($mapping['module_row_meta'])) { foreach ($mapping['module_row_meta'] as $meta_row) { $vars = (array)$meta_row; $vars['value'] = null; $vars['module_row_id'] = $module_row_id; if (is_object($meta_row->value)) { $row_key = strtolower($meta_row->value->module); if (isset($meta_row->value->module) && array_key_exists($row_key, $row)) $vars['value'] = $row[$row_key]; } else $vars['value'] = $meta_row->value; if (isset($meta_row->callback)) $vars['value'] = call_user_func_array($meta_row->callback, array($vars['value'])); if ($vars['serialized'] == 1) $vars['value'] = serialize($vars['value']); if ($vars['encrypted'] == 1) $vars['value'] = $this->ModuleManager->systemEncrypt($vars['value']); $this->local->insert("module_row_meta", $vars, array("module_row_id", "key", "value", "serialized", "encrypted")); } } return $module_row_id; } /** * Installs the given module and returns the module ID, if already installed simply returns the module ID * * @param string $module The WHMCS module name * @param array An array of mapping fields for this particular module (optional, will automatically load if not given) * @return int The ID of the module in Blesta */ private function installModule($module, $mapping = null) { if (!isset($this->ModuleManager)) Loader::loadModels($this, array("ModuleManager")); if ($mapping == null) $mapping = $this->getModuleMapping($module); // Return module if already mapped if (isset($this->mappings['modules'][$module])) return $this->mappings['modules'][$module]; // Check if module is already installed $mod = $this->local->select(array("id"))->from("modules")-> where("company_id", "=", Configure::get("Blesta.company_id"))-> where("class", "=", $mapping['module'])->fetch(); if ($mod) { $this->mappings['modules'][$module] = $mod->id; return $mod->id; } // Install the module since it does not already exist $module_id = null; try { $vars = array( 'company_id' => Configure::get("Blesta.company_id"), 'class' => $mapping['module'] ); $module_id = $this->ModuleManager->add($vars); } catch (Exception $e) { // Module couldn't be added } $this->mappings['modules'][$module] = (int)$module_id; return $module_id; } /** * Adds package pricing * * @param array $pricing A numerically indexed array of pricing info including: * - term * - period * - price * - setup_fee * - cancel_fee * - currency * @param string $package_id The Blesta package ID to add pricing to */ private function addPackagePricing($pricing, $package_id) { // Add package pricing $pricing_id = null; foreach ($pricing as $price) { if (version_compare(BLESTA_VERSION, "3.1.0-b1", ">=")) { $vars = $price; $vars['company_id'] = Configure::get("Blesta.company_id"); $this->local->insert("pricings", $vars); $pricing_id = $this->local->lastInsertId(); $this->local->insert("package_pricing", array( 'package_id' => $package_id, 'pricing_id' => $pricing_id ) ); $pricing_id = $this->local->lastInsertId(); } else { $vars = $price; $vars['package_id'] = $package_id; $this->local->insert("package_pricing", $vars); $pricing_id = $this->local->lastInsertId(); } } return $pricing_id; } /** * Adds package meta for the given package * * @param array $package An array of package info including: * - id The ID of the package in WHMCS * - * misc package fields * @param array $mapping An array of module mapping config settings */ private function addPackageMeta($package, $mapping) { // Add package meta if (isset($mapping['package_meta'])) { foreach ($mapping['package_meta'] as $meta) { $vars = (array)$meta; $vars['package_id'] = $this->mappings['packages'][$package['id']]; $vars['value'] = null; if (is_object($meta->value)) { if (isset($meta->value->package)) { $meta_key = strtolower($meta->value->package); if (array_key_exists($meta_key, $package)) { $vars['value'] = $package[$meta_key]; if ($meta_key == "password") $vars['value'] = $this->decryptData($package[$meta_key]); } } } else $vars['value'] = $meta->value; if (isset($meta->callback)) $vars['value'] = call_user_func_array($meta->callback, array($vars['value'])); if ($vars['serialized'] == 1) $vars['value'] = serialize($vars['value']); if ($vars['encrypted'] == 1) $vars['value'] = $this->ModuleManager->systemEncrypt($vars['value']); $this->local->insert("package_meta", $vars, array("package_id", "key", "value", "serialized", "encrypted")); } } } /** * Adds service fields * * @param array $service An array of key/value pairs for the remote service including: * - id The ID of the service on the remote server * - * other fields * @param array $mapping An array of module mapping config settings */ private function addServiceFields($service, $mapping) { if (!isset($this->Services)) Loader::loadModels($this, array("Services")); foreach ($mapping['service_fields'] as $key => $field) { $value = array_key_exists($key, $service) ? $service[$key] : null; if ($key == "password" && $value != "") $value = $this->decryptData($value); if (!is_object($field)) continue; if (isset($field->callback)) $value = call_user_func_array($field->callback, array($value)); if ($field->serialized > 0) $value = serialize($value); if ($field->encrypted > 0) $value = $this->Services->systemEncrypt($value); $vars = array( 'service_id' => $this->mappings['services'][$service['id']], 'key' => $field->key, 'value' => $value != null ? $this->decode($value) : "", 'serialized' => $field->serialized, 'encrypted' => $field->encrypted ); $this->local->insert("service_fields", $vars); } } /** * Get the pricing for the given term, package, and currency * * @param array $term An array of term info including: * - term * - period * @param stdClass $package The package in Blesta * @param string $currency The currency to fetch the pricing ID in, will fallback to any currency for the matching term and period * @param string $amount The service amount * @return stdClass An object containing the pricing */ private function getPricing($term, $package, $currency = null, $amount = null) { if (!is_array($term)) return null; $pricing_id = null; if ($package) { foreach ($package->pricing as $price) { if ($price->term == $term['term'] && $price->period == $term['period']) { $pricing_id = $price->id; if ($price->currency == $currency) { return $price; } } } } // If no pricing found, add default pricing $pricing = array( array( 'term' => $term['term'], 'period' => $term['period'], 'currency' => $currency ? $currency : "USD", 'price' => $amount !== null ? $amount : 0, ) ); $pricing_id = $this->addPackagePricing($pricing, $package->id); $fields = array("package_pricing.id", "package_pricing.pricing_id", "package_pricing.package_id", "pricings.term", "pricings.period", "pricings.price", "pricings.setup_fee", "pricings.cancel_fee", "pricings.currency", "packages.taxable"); return $this->local->select($fields)->from("package_pricing")-> innerJoin("pricings", "pricings.id", "=", "package_pricing.pricing_id", false)-> innerJoin("packages", "packages.id", "=", "package_pricing.package_id", false)-> where("package_pricing.id", "=", $pricing_id)->fetch(); } /** * Get the pricing for the given term, option value ID, and currency * * @param array $term An array of term info including: * - term * - period * @param int $value_id The option value ID in Blesta * @param string $currency The currency to fetch the pricing ID in * @return stdClass An object containing the pricing */ private function getOptionPricing($term, $value_id, $currency) { if (!is_array($term)) return null; $fields = array("package_option_pricing.id", "package_option_pricing.pricing_id", "package_option_pricing.option_value_id", "pricings.term", "pricings.period", "pricings.price", "pricings.setup_fee", "pricings.cancel_fee", "pricings.currency"); return $this->local->select($fields)->from("package_option_pricing")-> innerJoin("pricings", "pricings.id", "=", "package_option_pricing.pricing_id", false)-> where("pricings.currency", "=", $currency)-> where("pricings.period", "=", $term['period'])-> where("pricings.term", "=", $term['term'])-> where("package_option_pricing.option_value_id", "=", $value_id)->fetch(); } /** * Returns the local module row ID used for the remote service * * @param int $local_module_id The local ID of the module * @param string $row_value The module row field value for the remote service that uniquely identifies the module row * @param string $remote_module The name of the module on the remote server * @return int The local module row ID for the service */ private function getModuleRowId($local_module_id, $row_value = null, $remote_module = null) { $module_row = false; if ($row_value) { $module_row = $this->local->select(array("module_rows.*"))->from("module_rows")-> innerJoin("module_row_meta", "module_row_meta.module_row_id", "=", "module_rows.id", false)-> where("module_row_meta.value", "=", $row_value)-> where("module_rows.module_id", "=", $local_module_id)->fetch(); } // If no field, attempt to look up module row based on module name, since // the universal module uses the module name to create module rows else { $module_row = $this->local->select(array("module_rows.*"))->from("module_rows")-> innerJoin("modules", "modules.id", "=", "module_rows.module_id", false)-> on("module_row_meta.module_row_id", "=", "module_rows.id", false)-> innerJoin("module_row_meta", "module_row_meta.key", "=", "name")-> where("modules.class", "=", "universal_module")-> where("module_row_meta.value", "=", $remote_module)-> where("module_rows.module_id", "=", $local_module_id)->fetch(); } if ($module_row) { return $module_row->id; } else { $module_row = $this->local->select(array("module_rows.*"))->from("module_rows")-> where("module_rows.module_id", "=", $local_module_id)->fetch(); return $module_row->id; } } /** * Fetch the currency in used by the given client * * @param int $client_id * @return string The currency code for the client */ private function getCurrency($client_id) { if (!isset($this->Clients)) Loader::loadModels($this, array("Clients")); static $currencies = array(); if (!isset($currencies[$client_id])) { $default_currency = $this->Clients->getSetting($client_id, "default_currency"); if ($default_currency) $currencies[$client_id] = $default_currency->value; } // Get currency this client is invoiced in return isset($currencies[$client_id]) ? $currencies[$client_id] : "USD"; } /** * Looks for the TLD of the given domain based on the packages created for the given registrar * * @param string $domain * @param string $registrar The registrar * @return string The TLD */ private function getTld($domain, $registrar) { $tld = $domain; do { $tld = strstr(ltrim($tld, "."), "."); } while (!isset($this->mappings['packages'][$tld . $registrar]) && $tld != ""); return $tld; } /** * Decodes the HTML entities of the given string * * @param string $str The string to decode * @return string The decoded string */ protected function decode($str) { if ($str === null) return $str; return html_entity_decode($str, ENT_QUOTES, "UTF-8"); } /** * Set debug data * * @param string $str The debug data */ protected function debug($str) { static $set_buffering = false; if ($this->enable_debug) { if (!$set_buffering) { ini_set('output_buffering', 'off'); ini_set('zlib.output_compression', false); @ob_end_flush(); ini_set('implicit_flush', true); ob_implicit_flush(true); header("Content-type: text/plain"); header('Cache-Control: no-cache'); $set_buffering = true; } echo $str . "\n"; @ob_flush(); flush(); } } /** * Start a timer for the given task * * @param string $task */ protected function startTimer($task) { $this->task[$task] = array('start' => microtime(true), 'end' => 0, 'total' => 0); } /** * Pause a timer for the given task * * @param string $task */ protected function pauseTimer($task) { $this->task[$task]['end'] = microtime(true); $this->task[$task]['total'] += ($this->task[$task]['end'] - $this->task[$task]['start']); } /** * Unpause a timer for the given task * * @param string $task */ protected function unpauseTimer($task) { $this->task[$task]['start'] = microtime(true); } /** * End a timer for the given task, output to debug * * @param string $task */ protected function endTimer($task) { if ($this->task[$task]['start'] > $this->task[$task]['end']) $this->pauseTimer($task); if ($this->enable_debug) { $this->debug($task . " took: " . round($this->task[$task]['total'], 4) . " seconds"); } } } ?>
×
×
  • Create New...