<?php

require_once 'modules/admin/views/public/SignupView.php';
require_once 'newedge/classes/NE_PluginCollection.php';
require_once 'modules/billing/models/InvoiceEntry.php';
require_once "modules/billing/models/RecurringWork.php";
require_once "modules/billing/models/BillingType.php";
require_once "modules/clients/models/UserPackage.php";
require_once "modules/clients/models/DomainNameGateway.php";
require_once 'modules/billing/models/Coupon.php';
require_once 'modules/support/models/AutoresponderTemplateGateway.php';
require_once 'newedge/classes/NE_MailGateway.php';
require_once 'modules/clients/models/Client_EventLog.php';
require_once 'modules/clients/models/Package_EventLog.php';
include_once "newedge/encrypted/Clientexec.php";
require_once 'modules/clients/models/UserGateway.php';
require_once 'modules/admin/models/ServerGateway.php';
include_once 'modules/admin/models/PluginGateway.php';
/**
 * @package Admin
 *
 * This file has no template. It is merely used to process the signup request
 * and to handle things like Fraud, Payment Processor sendoff etc.
*/
class ViewSignup_CreateAccounts extends SignupView
{
    var $permission     = '';
    var $customerId     = null;
    var $existingMember = false;
    var $firstCycle = null;
    var $signupLogLevel = 3;
    var $signupEmail = array('HTML' => '', 'plainText' => '');


    function dispatch($passedUserId = null)
    {

        $dng = new DomainNameGateway();
        $this->initialize();

        if(@!$_REQUEST['signupChecksPassed']) {
            die("Can't call this directly & not passed checks");
        }

        $this->log($this->signupLogLevel, "Signup: STARTING CREATE ACCOUNTS");
        ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");
        ViewSignup_CreateAccounts::addStaffNotificationEvent("Customer Information");
        ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");
        ViewSignup_CreateAccounts::addStaffNotificationEvent("");

		//we need to not process this order if stock is used up
		//don't create the user yet.


        // Handle the customer registration
        if($this->user->getId() || $passedUserId) {
            
            if($passedUserId) {
                $this->customerId = $passedUserId;
            } else {
                $this->customerId = $this->user->getId();
            }

            // existing user
            $this->existingMember = true;
            $newUser = new User($this->customerId);

            $this->log($this->signupLogLevel, "Signup: Existing Customer Information: E-mail: '".$newUser->getEmail()."'. User ID: '".$newUser->getId()."'");
            ViewSignup_CreateAccounts::addStaffNotificationEvent("Existing Customer: " . $newUser->getFullName());
            ViewSignup_CreateAccounts::addStaffNotificationEvent("E-mail: ".$newUser->getEmail());
            ViewSignup_CreateAccounts::addStaffNotificationEvent("User ID: ".$newUser->getId());
        } else {

            $this->existingMember = false;

            $this->log($this->signupLogLevel, "Signup: NEW Customer, signup information to follow....");
            
            // New user
            $newUser = new User();
            $newUser->setCurrent(false);
            $newUser->setGroupId(1);

            // User Event Log
            $uEventLog = array();

            // Organization
            if(isset($_REQUEST['isOrganization'])){
                $newUser->setIsOrganization(true);
                $uEventLog['Organization'] = 'Yes';
                $this->log($this->signupLogLevel, "Signup: Customer: Is Organization");
                ViewSignup_CreateAccounts::addStaffNotificationEvent("Customer is an Organization");
            }else{
                $newUser->setIsOrganization(false);
                $uEventLog['Organization'] = 'No';
            }

            // Currency
            if(isset($_REQUEST['selectedcurrency'])){
                $newUser->setCurrency($_REQUEST['selectedcurrency']);
                $uEventLog['Currency'] = $_REQUEST['selectedcurrency'];
                $this->log($this->signupLogLevel, "Signup: Customer: Currency - ".$_REQUEST['selectedcurrency']);
            }else{
                $newUser->setCurrency($_REQUEST['currency']);
                $uEventLog['Currency'] = $_REQUEST['currency'];
                $this->log($this->signupLogLevel, "Signup: Customer: Currency - ".$_REQUEST['currency']);
            }

            // Handle some user based payment items
            $newUser->setPaymentType(@$_REQUEST['paymentMethod']);
            $uEventLog['Payment type'] = @$_REQUEST['paymentMethod'];
            $this->log($this->signupLogLevel, "Signup: Customer: PaymentType - ".$_REQUEST['paymentMethod']);

            if(@$_REQUEST[@$_REQUEST['paymentMethod'].'_ccMonth']) {
                $newUser->setCCMonth(@$_REQUEST[@$_REQUEST['paymentMethod'].'_ccMonth']);
                $this->log($this->signupLogLevel, "Signup: Customer: ccMonth - ".@$_REQUEST[@$_REQUEST['paymentMethod'].'_ccMonth']);
            }
            if(@$_REQUEST[@$_REQUEST['paymentMethod'].'_ccYear']) {
                $newUser->setCCYear(@$_REQUEST[@$_REQUEST['paymentMethod'].'_ccYear']);
                $this->log($this->signupLogLevel, "Signup: Customer: ccYear - ".@$_REQUEST[@$_REQUEST['paymentMethod'].'_ccYear']);

            }

            $newUser->setAutopayment(@$_REQUEST[@$_REQUEST['paymentMethod'].'_autopayment']);
            $this->log($this->signupLogLevel, "Signup: Customer: AutoPayment - ".@$_REQUEST[@$_REQUEST['paymentMethod'].'_autopayment']);
            ViewSignup_CreateAccounts::addStaffNotificationEvent("Payment Method: ".@$_REQUEST['paymentMethod']);
            ViewSignup_CreateAccounts::addStaffNotificationEvent(" ".(@$_REQUEST[@$_REQUEST['paymentMethod'].'_autopayment'])?"Auto payment?: Yes":"Auto payment?: No");

            // Extra attributes
            $newUser->setDateCreated(date("Y-m-d"));
            $newUser->setStatus(0);
            $newUser->setEmail(htmlspecialchars(strip_tags(
                $_REQUEST['CT_' . $newUser->getCustomFieldsObj()->_getCustomFieldIdByType(typeEMAIL)],
                ENT_QUOTES)));
            if (!$newUser->add()) {

                $this->log($this->signupLogLevel, "Signup: FATAL ERROR. SIGNUP LIMIT REACHED.");

                // Installation limit reatched, fail This.
                die("Installation limit reached. Unable to continue");
                
            }

            // MOVED THIS CODE DOWN HERE, SINCE THE USER ID IS REQUIRED FOR PROPERLY STORING THE CC NUMBER
            if (!$this->existingMember && @$_REQUEST[@$_REQUEST['paymentMethod'].'_ccNumber'] != '') {
                $uEventLog[/*T*/'CC number (last 4)'/*/T*/] = mb_substr($_REQUEST[@$_REQUEST['paymentMethod'].'_ccNumber'], -4);
                $uEventLog[/*T*/'CC expiration month'/*/T*/] = @$_REQUEST[@$_REQUEST['paymentMethod'].'_ccMonth'];
                $uEventLog[/*T*/'CC expiration year'/*/T*/] = @$_REQUEST[@$_REQUEST['paymentMethod'].'_ccYear'];
                $newUser->StoreCreditCardInfo($_REQUEST[@$_REQUEST['paymentMethod'].'_ccNumber'], $this->settings);
                $newUser->save();

                $this->log($this->signupLogLevel, "Signup: Customer: ccNumber - ".mb_substr($_REQUEST[@$_REQUEST['paymentMethod'].'_ccNumber'], -4));
            }

            // Move guest tickets to this user
            ViewSignup_CreateAccounts::_importGuestTickets($newUser);
            
            if (!is_null($this->settings->get('plugin_paypal_Paypal Subscriptions Option In Signup')) && $this->settings->get('plugin_paypal_Paypal Subscriptions Option In Signup') == 1)
            {
                $_REQUEST['paypalSubscription'] = 1;
            }
            // set paypal subscriptions preference
            if (isset($_REQUEST['paypalSubscription']) && $_REQUEST['paypalSubscription'] == '1' && $_REQUEST['paymentMethod'] == 'paypal') {
                $query = "SELECT id FROM customuserfields WHERE name='Use Paypal Subscriptions' AND company_id=?;";
                $result = $this->db->query($query, NE_Registry::getCompany()->getId());
                list($customId) = $result->fetch();
                $newUser->UpdateCustomTag($customId, 1);

                $this->log($this->signupLogLevel, "Signup: Customer: Using Paypal Subscriptions!");
                ViewSignup_CreateAccounts::addStaffNotificationEvent("Customer is using PayPal subscription");
            }

            // Process Custom Fields for Profile
            foreach ($_REQUEST as $customTag => $value) {

                // Explode the item and see if it's a CT
                $CT = explode("_", $customTag);
                if($CT[0] == 'CT') {

                    // Sanitize $value
                    $value = htmlspecialchars(strip_tags($value),ENT_QUOTES);

                    // Don't bother adding a blank value
                    if (trim($value) != '') {

                        if (isset($_REQUEST["CTT_{$CT[1]}"]) && $_REQUEST["CTT_{$CT[1]}"] == TYPEDATE) {
                            if ($value != '') {
                                $value = NE_Lib::form_to_db($value, $this->settings->get('Date Format'), "/");
                            }
                        }

                        $newUser->UpdateCustomTag($CT[1],$value);

                        // Get the name of the custom field
                        $customFieldName = $newUser->getCustomFieldName($CT[1]);
                        $uEventLog[$customFieldName] = $value;
                        ViewSignup_CreateAccounts::addStaffNotificationEvent($customFieldName.": ".$value);
                        $this->log($this->signupLogLevel, "Signup: Customer: ".$customFieldName." - ".$value);
                    }
                }
            }

            //Set default HTML Email format to yes
            $getHTMLEmailQuery = "SELECT id FROM customuserfields WHERE name='HTML Email Format' AND company_id=?;";
            $getHTMLEmailResult = $this->db->query($getHTMLEmailQuery, NE_Registry::getCompany()->getId());
            list($tCustomTag) = $getHTMLEmailResult->fetch();
            $newUser->UpdateCustomTag($tCustomTag,"1");


            $newUser->setPassword($_REQUEST['password']);
            //ViewSignup_CreateAccounts::addStaffNotificationEvent("Account Password: ".$_REQUEST['password']);

            // update user's tax flag
            /*
            if($newUser->getTaxRate(1) || $newUser->getTaxRate(2)) {
                $newUser->setTaxable(1);
                $this->log($this->signupLogLevel, "Signup: Customer: Customer is Taxable!");
                ViewSignup_CreateAccounts::addStaffNotificationEvent("Customer matches a tax rule");
            }
            */
            // All customers will be taxable by default.
            $newUser->setTaxable(1);
            $uEventLog['Taxable'] = 'Yes';

            $newUser->save();

            $clientLog = Client_EventLog::newInstance($newUser->getId(), $newUser->getId(), CLIENT_EVENTLOG_CREATED, $newUser->getId(), serialize($uEventLog));
            $this->logger->addEventLog($clientLog);

            // Set the user ID
            $this->customerId = $newUser->getId();

            $this->log($this->signupLogLevel, "Signup: Customer: Saved Customer. ID '".$this->customerId."'");
        }

        $invoiceEntries = "";

        // Get the session
        if(NE_Lib::generateSignupCartHash() == @$_SESSION['cartHash'] && @$_SESSION['cartHash'] != null) {

            // Get the cart items
            $cartItems = unserialize(base64_decode(@$_SESSION['cartContents']));
            $productsToBundle = array();

            $this->log($this->signupLogLevel, "Signup: STARTING PROCESSING CART CONTENTS");

            // Loop the cart
            foreach($cartItems AS $value => $key) {
                // Skip coupons
                if($value == 'couponCodes') {
                    continue;
                }

                // Get the information of the package
                $package = new Package($key['productId']);
                $package->getProductPricing();

                // Get the product group information
                if(!@$productGroupInfo[$package->planid]) {
                    $productGroup = PackageTypeGateway::getPackageTypes($package->planid);
                    $productGroupInfo[$package->planid] = $productGroup->fetch();
                }
                
                
                // Generate a full name for the product
                $productFullName = $productGroupInfo[$package->planid]->fields['name']." / ".$package->planname;

                // Package Event Log
                $pEventLog = array();
                
                $pEventLog[/*T*/'Package Type'/*/T*/] = $productGroupInfo[$package->planid]->fields['name'];
                $pEventLog[/*T*/'Package'/*/T*/] = $package->planname;

                // Add the product record manually
                $sql = "INSERT into domains(CustomerId, Plan, dateActivated) values(?,?,NOW())";
                $result = $this->db->query($sql,$this->customerId,$key['productId']);
                $userPackageId = $result->getInsertId();

                $this->log($this->signupLogLevel, "Signup: Cart: Created OrderID: '".$userPackageId."' with CustomerID '".$this->customerId."'. From ProductID: '".$key['productId']."'");

                ViewSignup_CreateAccounts::addStaffNotificationEvent("");
                ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");
                ViewSignup_CreateAccounts::addStaffNotificationEvent("Order Item #$userPackageId");
                ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");
                ViewSignup_CreateAccounts::addStaffNotificationEvent("Product Ordered: ".$productFullName);

                // Push the product ID back into the session so we can use it for bundling at any point
                $cartItems[$value]['savedProductId'] = $userPackageId;
                
                // Create the userpackage
                $userPackage = new UserPackage($userPackageId);
                $userPackage->signup = 1;
                $userPackage->loadCustomFields();

                // Work out what type of product we are handling in order to support the custom fields
                if($productGroupInfo[$package->planid]->fields['type'] == 1) {

                    $this->log($this->signupLogLevel, "Signup: Cart: Product is of type Hosting.");
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("Type: Hosting");

                    // We first need to FIND the ID of the username and password
                    $cfUserName = $userPackage->getCustomFieldObject('User Name');
                    $cfPassword = $userPackage->getCustomFieldObject('Password');
                    $cfDomainName = $userPackage->getCustomFieldObject('Domain Name');
                    
                    $advancedSettings = @unserialize($package->advanced);
                    // Do not try to use username/password if we are hidding hosting custom fields
                    if ( @$advancedSettings['hostingcustomfields'] != 1 ) {
                        // Handle the default hosting fields
                        if(@$key['bundledDomain'] && isset($cartItems[$key['bundledDomain']])) {
                            $packageDomainName = $cartItems[$key['bundledDomain']]['params']['sld'].".".$cartItems[$key['bundledDomain']]['params']['tld'];
                        } elseif(isset($key['bundledDomain']) && !@is_numeric($key['bundledDomain'])) {
                             $packageDomainName =  $key['bundledDomain'];
                        } else {
                            $packageDomainName = $key['params']['customFields'][$cfDomainName['id']];
                        }

                        $userPackage->setCustomField('Domain Name', $packageDomainName);
                        $pEventLog[/*T*/'Domain Name'/*/T*/] = $packageDomainName;
                        $this->log($this->signupLogLevel, "Signup: Cart: Domain Name - ".$packageDomainName);
                        ViewSignup_CreateAccounts::addStaffNotificationEvent("Domain Name: ".$packageDomainName);

                        /*
                         * We need to generate the possible username & password first before saving it so that we can
                         * call validateCredentials on the server plugin to check we have a valid u/p
                         */

                        // Check if we have submitted a username
                        if(isset($key['params']['customFields'][$cfUserName['id']])) {
                            $packageUsername = $key['params']['customFields'][$cfUserName['id']];
                        } else {
                            $packageUsername = NE_Lib::generateUsername(8,$packageDomainName);
                        }

                        // Check if we have submitted a password
                        if(isset($key['params']['customFields'][$cfPassword['id']])) {
                            $packagePassword = $key['params']['customFields'][$cfPassword['id']];
                        } else {
                            $packagePassword = NE_Lib::generatePassword();
                        }
                    }

                    // Get the servers
                    $servers = new ServerGateway();
                    $serversList = $servers->getServersGridList();
                    $serversList = $serversList['data'];
                    $packageServers = $package->getProductServerIds();

                    // Check we have some servers, now find one we can use
                    if(is_array($serversList)) {
                        foreach($serversList as $server) {
                            // Check this server is assigned
                            if(isset($packageServers[$server['id']])) {
                                //check if serverid is not over quota
                                if($server['rawQuota'] == 0 || $server['rawQuota'] > $server['rawAmount']) {
                                    $userPackage->setCustomField("Server Id", $server['id']);
                                    if ($server['id']!= 0 ) {
                                        $query_server_name = "SELECT name "
                                            ."FROM server "
                                            ."WHERE id = ? ";
                                        $result_server_name = $this->db->query($query_server_name, $server['id']);
                                        list($server_name) = $result_server_name->fetch();
                                        $pEventLog[/*T*/'Server'/*/T*/] = $server_name;
                                    }
                                    
                                    $serverips = $servers->getAvailableIPs($server['id'], true);
                                    
                                    $userPackage->setCustomField("Shared", 1);
                                    $pEventLog[/*T*/'Use Shared IP'/*/T*/] = $this->lang('Yes');
                                    
                                    $userPackage->setCustomField("IP Address", $serverips['sharedip']);
                                    $pEventLog[/*T*/'IP Address'/*/T*/] = $serverips['sharedip'];
                                    
                                    $this->log($this->signupLogLevel, "Signup: Cart: ServerID - ".$server['id']);
                                    ViewSignup_CreateAccounts::addStaffNotificationEvent("Allocated Account to Server : ".$server['name']);

                                    // If we are not hiding custom hosting fields, we now validate the credentials with this plugin
                                    if ( @$advancedSettings['hostingcustomfields'] != 1 ) {
                                        $pluginGateway = new PluginGateway();
                                        $plugin = $pluginGateway->getPluginByName('server', $server['rawPlugin']);
                                        if(method_exists($plugin, 'validateCredentials')) {
                                            $validCredentials = $plugin->validateCredentials(array('package' => array('username' => $packageUsername, 'password' => $packagePassword), 'noError' => true));
                                            if($validCredentials) {
                                                $packageUsername = $validCredentials;
                                            }
                                            break;
                                        }
                                    }
                                    break;
                                } else {
                                    $this->log($this->signupLogLevel, "Signup: Cart: ServerID ".$server['id']." is over it's Quota. Moving to another server.");
                                }
                            }
                        }
                    } else {
                        $this->log($this->signupLogLevel, "Signup: Cart: WARNING - NO SERVERS FOUND.");
                        ViewSignup_CreateAccounts::addStaffNotificationEvent("Unable to find a server to allocate account");
                    }

                    // Do not try to set username/password if we are hidding hosting custom fields
                    if ( @$advancedSettings['hostingcustomfields'] != 1 ) {
                        // Save the username now thats its validated
                        $userPackage->setCustomField('User Name', $packageUsername);
                        $pEventLog[/*T*/'User Name'/*/T*/] = $packageUsername;
                        $this->log($this->signupLogLevel, "Signup: Cart: User Name - ".$packageUsername);
                        ViewSignup_CreateAccounts::addStaffNotificationEvent("User Name: ".$packageUsername);

                        // Save the password
                        if ( $this->settings->get('Domain Passwords are Encrypted') == 1 ) {
                            $userPackage->setCustomField('Password', Clientexec::encryptString($packagePassword));
                        } else {
                            $userPackage->setCustomField('Password', $packagePassword);
                        }
                        ViewSignup_CreateAccounts::addStaffNotificationEvent("Password: ".$packagePassword);
                    }

                    // Add the product to bundle
                    if(@$key['bundledDomain']) {
                        $productsToBundle[$userPackageId] = $key['bundledDomain'];
                        ViewSignup_CreateAccounts::addStaffNotificationEvent("Product is bundled with a domain name");
                    }

                } elseif($productGroupInfo[$package->planid]->fields['type'] == 3) {

                    $this->log($this->signupLogLevel, "Signup: Cart: Product is of type Domain");
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("Type: Domain Name");

                    // Handle the custom field information for domains
                    $userPackage->setCustomField('Domain Name', $key['params']['sld'].".".$key['params']['tld']);
                    $pEventLog[/*T*/'Domain Name'/*/T*/] = $key['params']['sld'].".".$key['params']['tld'];
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("Domain Name: ".$key['params']['sld'].".".$key['params']['tld']);

                    $userPackage->setCustomField('Registration Option', $key['params']['domainType']);

                    // Extract the registrar from the pricing information
                    $package->getProductPricing();
                    $userPackage->setCustomField('Registrar', $package->pricingInformation['pricedata'][$key['params']['tld']]['registrar']);
                    $pEventLog[/*T*/'Registrar'/*/T*/] = $package->pricingInformation['pricedata'][$key['params']['tld']]['registrar'];
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("Registrar: ".$package->pricingInformation['pricedata'][$key['params']['tld']]['registrar']);

                    // Generate a domain username and password
                    $packageUsername = NE_Lib::generateUsername(8,$key['params']['sld'].".".$key['params']['tld']);
                    $packagePassword = NE_Lib::generatePassword();
                    $key['params']['extraAttributes']['domainUsername'] = NE_Lib::generateUsername(8,$key['params']['sld'].".".$key['params']['tld']);
                    $domainPassword = NE_Lib::generatePassword();
                    
                    if ( $this->settings->get('Domain Passwords are Encrypted') == 1 ) {
                        $key['params']['extraAttributes']['domainPassword'] = Clientexec::encryptString($domainPassword);
                    } else {
                        $key['params']['extraAttributes']['domainPassword'] = $domainPassword;
                    }

                    ViewSignup_CreateAccounts::addStaffNotificationEvent("Domain Username: ".$key['params']['extraAttributes']['domainUsername']);
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("Domain Password: ".$domainPassword);

                    // Show what the customer wants the host to do with the domain they are requesting
                    switch ( $key['params']['domainType'] ) {
                        case 0:
                            $strMessageOutput = "Registrar Service Requested: Customer wants host to register domain";
                            $pEventLog[/*T*/'Registrar Service Requested'/*/T*/] = 'Customer wants host to register domain';
                            break;
                        case 1:
                            $strMessageOutput = "Registrar Service Requested: Customer wants host to transfer domain";
                            $pEventLog[/*T*/'Registrar Service Requested'/*/T*/] = 'Customer wants host to transfer domain';
                            break;
                        case 2:
                            $strMessageOutput = "Registrar Service Requested: Customer will manage their own domain";
                            $pEventLog[/*T*/'Registrar Service Requested'/*/T*/] = 'Customer will manage their own domain';
                            break;
                    }
                    ViewSignup_CreateAccounts::addStaffNotificationEvent($strMessageOutput);

                    // Capture the domain extra attributes
                    if(@is_array($key['params']['extraAttributes'])) {
                        $userPackage->setCustomField('Domain Extra Attr', serialize($key['params']['extraAttributes']));

                        foreach ($key['params']['extraAttributes'] as $extattrname => $extattrvalue) {
                            if(!in_array($extattrname, array('domainPassword'))){
                                $pEventLog[/*T*/'Extra attribute'/*/T*/ .' "'.$extattrname.'"'] = $extattrvalue;
                            }
                        }

                        // Show EPP code in e-mail if there is one.
                        if ( array_key_exists('eppCode', $key['params']['extraAttributes']) ) {
                            ViewSignup_CreateAccounts::addStaffNotificationEvent('EPP Code: ' . $key['params']['extraAttributes']['eppCode']);
                        }
                    }
                } else if ( $productGroupInfo[$package->planid]->fields['type'] == 2 ) {
                    
                    $this->log($this->signupLogLevel, "Signup: Cart: Product is of type SSL");
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("Type: SSL Certificate");

                    $advanced = unserialize($package->advanced);
                    $registrar = $advanced['registrar'];
                    $userPackage->setCustomField('Registrar', $registrar);
                    $pEventLog[/*T*/'Registrar'/*/T*/] = $registrar;
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("Registrar: ". $registrar);

                   
                } else {
                    $this->log($this->signupLogLevel, "Signup: Cart: Product is of type General");
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("Type: General");
                    
                    // No Specific work to do for general products.
                }

                // Handle any user generated custom fields
                if(@is_array($key['params']['customFields'])) {
                    $firstTime = true;
                    foreach ($key['params']['customFields'] as $customTag => $value) {
                        
                        // Skip domain name, username & password as they have been saved above
                        if((isset($cfDomainName['id']) && $cfDomainName['id'] == $customTag)
                          || (isset($cfUserName['id']) && $cfUserName['id'] == $customTag)
                          || (isset($cfPassword['id']) && $cfPassword['id'] == $customTag)) {
                            continue;
                        }

                        if ( $firstTime == true ) {
                            $firstTime = false;
                            // Only show Custom Fields header if we have custom fields to show.
                            ViewSignup_CreateAccounts::addStaffNotificationEvent("");
                            ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");
                            ViewSignup_CreateAccounts::addStaffNotificationEvent("Custom Fields:");
                            ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");
                        }

                        // Sanitize $value
                        $value = htmlspecialchars(strip_tags($value),ENT_QUOTES);

                        // Don't bother adding a blank value
                        if (trim($value) != '') {
                            $cfObject = $userPackage->getCustomFieldObject($customTag, CUSTOM_FIELDS_FOR_PACKAGE);
                            if(is_array($cfObject)) {
                                if ( $cfObject['fieldtype'] == TYPEDATE ) {
                                    $value = NE_Lib::form_to_db($value, $this->settings->get('Date Format'), "/");
                                }
                                // Get the name of the custom field so we can log it
                                $this->log($this->signupLogLevel, "Signup: Cart: CustomFieldID ".@$cfObject['name']." - ".$value);
                                ViewSignup_CreateAccounts::addStaffNotificationEvent($cfObject['name'].": ".$value);
                            }

                            // save the value
                            $userPackage->setCustomField($customTag, $value);
                            if(isset($cfObject['name'])){
                                $pEventLog[@$cfObject['name']] = $value;
                            }else{
                                $pEventLog["Custom Field ".$customTag] = $value;
                            }
                        }
                    }
                }
                
                // Handle saving of addons
                $userPackage->saveAddons(@$key['params']['addons'], $pEventLog, $this);

                $packageLog = Package_EventLog::newInstance($newUser->getId(), $userPackage->getID(), PACKAGE_EVENTLOG_CREATED, $newUser->getId(), serialize($pEventLog));
                $this->logger->addEventLog($packageLog);

                /*
                 * HANDLE THE BILLING
                 * Seems that we create invoice items for single things like setup fees
                 * and recurring work entries for things like monthly billing
                 * domains have to have an invoice item AND recurring work for X in the future as
                 * we can only make one paypal subscription
                 */

                // Calculate the disableGenerate value
                if($productGroupInfo[$package->planid]->fields['type'] == 1 || $productGroupInfo[$package->planid]->fields['type'] == 0 || $productGroupInfo[$package->planid]->fields['type'] == 2) {
                    $trueTerm = @$key['params']['term'];
                } else {
                    $trueTerm = @$key['params']['term'] * 12;
                }

                $this->log($this->signupLogLevel, "Signup: Cart: Product has billing term of ".$trueTerm);
                
                if(!isset($this->firstCycle)) { $this->firstCycle = $trueTerm; }

                if($newUser->getUsePaypalSubscriptions() && $this->firstCycle != $trueTerm) {
                    // Cycle mismatch (e.g. a domain) so postponing generating the invoice
                    $disableGenerate = -1;
                } elseif ($newUser->getUsePaypalSubscriptions()) {
                    // Subscription so don't ever create an invoice
                    $disableGenerate = 1;
                } else {
                    // Create an invoice as usual
                    $disableGenerate = 0;
                }

                $this->log($this->signupLogLevel, "Signup: Cart: DisableGenerate Value: ".$disableGenerate);

                if($productGroupInfo[$package->planid]->fields['type'] == 1 || $productGroupInfo[$package->planid]->fields['type'] == 0 || $productGroupInfo[$package->planid]->fields['type'] == 2) {

                    // Process prorating
                    $linePrice = $package->getPrice(@$key['params']['term']);
                    $nextBillDate = ViewSignup_CreateAccounts::generateNextBillDate(@$key['params']['term'], $productGroupInfo[$package->planid]->fields['type']);
                    if($this->settings->get('Prorate To Day') != 0) {

                        list($itemPrice, $proRatedPrice, $proratedDays, $proIncFollowing, $tmpnextBill, $proNextBill) = $this->processProrating($this->settings->get('Prorate To Day'), $this->settings->get('Include Following Payment'), $key['params']['term'], $linePrice);

                        if($itemPrice != 0) {
                            $linePrice = $itemPrice + $proRatedPrice;
                        } else {
                            $linePrice = $proRatedPrice;
                        }
                        $nextBillDate['nextBilling'] = date("Y-m-d", $proNextBill);
                    }
                    
                    // Add the domain to the title if required
                    if(isset($packageDomainName)) {
                        $extraText = " (".$packageDomainName.")";
                    } else {
                        $extraText = '';
                    }

                    // Hosting and General share the same term types
                    // If we have 0 then it's one time so no need to create a recurring term
                    if($key['params']['term'] == 0) {

                        // Create an invoice entry for a one time fee
                        $params = array(
                            'm_CustomerID'        => $this->customerId,
                            'm_Description'       => $productFullName." - ".$this->lang("One time").$extraText,
                            'm_Detail'            => "One time product fee",
                            'm_invoiceid'         => 0,
                            'm_Date'              => date("Y-m-d"),
                            'm_BillingTypeID'     => BILLINGTYPE_PACKAGE,
                            'm_IsProrating'       => 0,
                            'm_Price'             => $package->getPrice(@$key['params']['term']),
                            'm_Recurring'         => 0,
                            'm_IncludeNextPayment'=> 1,
                            'm_AppliesToID'       => $userPackageId,
                            'm_Setup'             => 0,
                            'm_Taxable'           => ($package->isTaxable())? 1 : 0,
                        );
                        $invoiceEntry = new InvoiceEntry($params);
                        $invoiceEntry->updateRecord();

                        $invoiceEntries .= $invoiceEntry->m_EntryID." ";

                        $this->log($this->signupLogLevel, "Signup: Cart: Created Invoice Entry '".$invoiceEntry->m_EntryID."'. For: ".$params['m_Description']);


                    } else {

                        // We still need to handle setup fee's as invoice items
                        $itemSetupFee = $package->getSetupFee(@$key['params']['term']);
                        if(!($itemSetupFee == '0' || $itemSetupFee == '0.00')) {
                            
                            // Create setup fee
                            $params = array(
                                'm_CustomerID'        => $this->customerId,
                                'm_Description'       => $productFullName." - ".$this->lang("Setup Fee"),
                                'm_Detail'            => 'Initial setup charges',
                                'm_invoiceid'         => 0,
                                'm_Date'              => date("Y-m-d"),
                                'm_BillingTypeID'     => BILLINGTYPE_PACKAGE,
                                'm_IsProrating'       => 0,
                                'm_Price'             => $package->getSetupFee(@$key['params']['term']),
                                'm_Recurring'         => 0,
                                'm_IncludeNextPayment'=> 1,
                                'm_AppliesToID'       => $userPackageId,
                                'm_Setup'             => 1,
                                'm_Taxable'           => ($package->isTaxable())? 1 : 0,
                            );
                            $invoiceEntry = new InvoiceEntry($params);
                            $invoiceEntry->updateRecord();

                            $invoiceEntries .= $invoiceEntry->m_EntryID." ";
                            $this->log($this->signupLogLevel, "Signup: Cart: Created Invoice Entry '".$invoiceEntry->m_EntryID."'. For: ".$params['m_Description']);

                        }

                        // Create some recurring work
                        $tParams = array(
                            'customerid'      => $this->customerId,
                            'paymentterm'     => @$key['params']['term'],
                            'description'     => $productFullName." - ".$package->getTermText(@$key['params']['term']).$extraText,
                            'detail'          => $productFullName." - ".$package->getTermText(@$key['params']['term']).$extraText,
                            'billingtypeid'   => BILLINGTYPE_PACKAGE,
                            'nextbilldate'    => $nextBillDate['nextBilling'],
                            'appliestoid'     => $userPackageId,
                            'amount'          => $package->getPrice(@$key['params']['term']),
                            'disablegenerate' => $disableGenerate,
                            'taxable'         => ($package->isTaxable())? 1 : 0,
                            'recurring'       => 1
                        );
                        $domainRegRecurringEntry = new RecurringWork($tParams);
                        $domainRegRecurringEntry->update();

                        $this->log($this->signupLogLevel, "Signup: Cart: Created Recurring work. Paymentterm: '".$key['params']['term']."'. For: ".$tParams['description']);

                        $todaybillingNice = date($this->settings->get('Date Format'), mktime(0, 0, 0, date("m"), date("d"),  date("Y")));
                        $secondsInADay = 60*60*24;
                        $nextbillingNice = date($this->settings->get('Date Format'), mktime(0, 0, 0, date("m", strtotime($nextBillDate['nextBilling'])), date("d", strtotime($nextBillDate['nextBilling'])),  date("Y", strtotime($nextBillDate['nextBilling']))) - $secondsInADay);

                        // Create invice entry
                        $params = array(
                                'm_CustomerID'        => $this->customerId,
                                'm_Description'       => $productFullName." - ".$package->getTermText(@$key['params']['term']).$extraText.', '.$todaybillingNice.' '.$this->lang("thru").' '.$nextbillingNice,
                                'm_Detail'            => 'Recurring Fee',
                                'm_invoiceid'         => 0,
                                'm_Date'              => date("Y-m-d"),
                                'm_BillingTypeID'     => BILLINGTYPE_PACKAGE,
                                'm_IsProrating'       => 0,
                                'm_Price'             => $linePrice,
                                'm_Recurring'         => 1,
                                'm_IncludeNextPayment'=> 1,
                                'm_AppliesToID'       => $userPackageId,
                                'm_Setup'             => 0,
                                'm_Taxable'           => ($package->isTaxable())? 1 : 0,
                                'm_RecurringAppliesTo' => @$domainRegRecurringEntry->vars['id']['data'],
                                'm_BillingCycle'      => @$key['params']['term']
                            );
                        $invoiceEntry = new InvoiceEntry($params);
                        $invoiceEntry->updateRecord();

                        $invoiceEntries .= $invoiceEntry->m_EntryID." ";
                        $this->log($this->signupLogLevel, "Signup: Cart: Created Invoice Entry '".$invoiceEntry->m_EntryID."'. For: ".$params['m_Description']);
                        
                    }
                    
                } elseif($productGroupInfo[$package->planid]->fields['type'] == 3) {

                    $domainPricing = $package->isTermValid(@$key['params']['term'], @$key['params']['tld']);

                    // Handle the type of domain, transfer or registration
                    if($key['params']['domainType'] == 0) {

                        // future recurring work for Registration
                        $nextBillDate = ViewSignup_CreateAccounts::generateNextBillDate(@$key['params']['term'], $productGroupInfo[$package->planid]->fields['type']);
                        $params = array(
                            'customerid'      => $this->customerId,
                            'paymentterm'     => @$key['params']['term'] * 12,
                            'description'     => $this->lang("Domain Renewal")." - ".@$key['params']['sld'].".".@$key['params']['tld'],
                            'detail'          => $this->lang("Domain Renewal")." - ".@$key['params']['sld'].".".@$key['params']['tld'],
                            'billingtypeid'   => BILLINGTYPE_PACKAGE,
                            'nextbilldate'    => $nextBillDate['nextBilling'],
                            'appliestoid'     => $userPackageId,
                            'amount'          => $domainPricing['renew'],
                            'disablegenerate' => $disableGenerate,
                            'taxable'         => ($package->isTaxable())? 1 : 0,
                            'recurring'       => (@$key['params']['term'])? 1 : 0
                        );
                        $recurringWork = new RecurringWork($params);
                        $recurringWork->update();
                        $this->log($this->signupLogLevel, "Signup: Cart: Created Recurring work. Paymentterm: '".$key['params']['term']."' Year(s). For: ".$params['description']);

                        $todaybillingNice = date($this->settings->get('Date Format'), mktime(0, 0, 0, date("m"), date("d"),  date("Y")));
                        $secondsInADay = 60*60*24;
                        $nextbillingNice = date($this->settings->get('Date Format'), mktime(0, 0, 0, date("m", strtotime($nextBillDate['nextBilling'])), date("d", strtotime($nextBillDate['nextBilling'])),  date("Y", strtotime($nextBillDate['nextBilling']))) - $secondsInADay);

                        // Create invoice item for this here and now
                        $tParams = array(
                            'm_CustomerID'        => $this->customerId,
                            'm_Description'       => $this->lang("Domain Registration")." - ".@$key['params']['sld'].".".@$key['params']['tld'].', '.$todaybillingNice.' '.$this->lang("thru").' '.$nextbillingNice,
                            'm_Detail'            => $this->lang("Domain Registration")." ".$this->lang('for Domain')." : ".@$key['params']['sld'].".".@$key['params']['tld']." x ".@$key['params']['term']." ".$this->lang("Years"),
                            'm_invoiceid'         => 0,
                            'm_Date'              => date("Y-m-d"),
                            'm_BillingTypeID'     => BILLINGTYPE_DOMAIN_NAME,
                            'm_IsProrating'       => 0,
                            'm_Price'             => $domainPricing['price'],
                            'm_Recurring'         => (@$key['params']['term'])? 1 : 0,
                            'm_IncludeNextPayment'=> 1,
                            'm_AppliesToID'       => $userPackageId,
                            'm_Setup'             => 0,
                            'm_Taxable'           => ($package->isTaxable())? 1 : 0,
                            'm_RecurringAppliesTo' => @$recurringWork->vars['id']['data'],
                            'm_BillingCycle'      => @$key['params']['term'] * 12
                        );
                        $invoiceEntry = new InvoiceEntry($tParams);
                        $invoiceEntry->updateRecord();

                        $invoiceEntries .= $invoiceEntry->m_EntryID." ";
                        $this->log($this->signupLogLevel, "Signup: Cart: Created Invoice Entry '".$invoiceEntry->m_EntryID."'. For: ".$tParams['m_Description']);


                    } elseif($key['params']['domainType'] == 1) {

                        // Future recurring work entry for a domain transfer
                        $nextBillDate = ViewSignup_CreateAccounts::generateNextBillDate(@$key['params']['term'], $productGroupInfo[$package->planid]->fields['type']);
                        $params = array(
                            'customerid'      => $this->customerId,
                            'paymentterm'     => @$key['params']['term'] * 12,
                            'description'     => $this->lang("Domain Renewal")." - ".@$key['params']['sld'].".".@$key['params']['tld'],
                            'detail'          => $this->lang("Domain Renewal")." ".$this->lang('for Domain')." : ".@$key['params']['sld'].".".@$key['params']['tld']." x 1 ".$this->lang("Years"),
                            'billingtypeid'   => BILLINGTYPE_PACKAGE, // required for the duration to work correctly elsewhere
                            'nextbilldate'    => $nextBillDate['nextBilling'],
                            'appliestoid'     => $userPackageId,
                            'amount'          => $domainPricing['renew'],
                            'disablegenerate' => -1,
                            'taxable'         => ($package->isTaxable())? 1 : 0,
                            'recurring'       => (@$key['params']['term'])? 1 : 0
                        );
                        $recurringWork = new RecurringWork($params);
                        $recurringWork->update();
                        $this->log($this->signupLogLevel, "Signup: Cart: Created Recurring work. Paymentterm: '".$key['params']['term']."' year(s). For: ".$params['description']);

                        $todaybillingNice = date($this->settings->get('Date Format'), mktime(0, 0, 0, date("m"), date("d"),  date("Y")));
                        $secondsInADay = 60*60*24;
                        $nextbillingNice = date($this->settings->get('Date Format'), mktime(0, 0, 0, date("m", strtotime($nextBillDate['nextBilling'])), date("d", strtotime($nextBillDate['nextBilling'])),  date("Y", strtotime($nextBillDate['nextBilling']))) - $secondsInADay);

                        // Single invoice entry for a domain transfer.
                        $tParams = array(
                            'm_CustomerID'        => $this->customerId,
                            'm_Description'       => $this->lang("Domain Transfer")." - ".@$key['params']['sld'].".".@$key['params']['tld'].', '.$todaybillingNice.' '.$this->lang("thru").' '.$nextbillingNice,
                            'm_Detail'            => $this->lang("Domain Transfer")." ".$this->lang('for Domain')." : ".@$key['params']['sld'].".".@$key['params']['tld']." x ".@$key['params']['term']." ".$this->lang("Years"),
                            'm_invoiceid'         => 0,
                            'm_Date'              => date("Y-m-d"),
                            'm_BillingTypeID'     => BILLINGTYPE_DOMAIN_NAME,
                            'm_IsProrating'       => 0,
                            'm_Price'             => $domainPricing['transfer'],
                            'm_Recurring'         => (@$key['params']['term'])? 1 : 0,
                            'm_IncludeNextPayment'=> 1,
                            'm_AppliesToID'       => $userPackageId,
                            'm_Setup'             => 0,
                            'm_Taxable'           => ($package->isTaxable())? 1 : 0,
                            'm_RecurringAppliesTo' => @$recurringWork->vars['id']['data'],
                            'm_BillingCycle'      => @$key['params']['term'] * 12
                        );
                        $invoiceEntry = new InvoiceEntry($tParams);
                        $invoiceEntry->updateRecord();

                        $invoiceEntries .= $invoiceEntry->m_EntryID." ";
                        $this->log($this->signupLogLevel, "Signup: Cart: Created Invoice Entry '".$invoiceEntry->m_EntryID."'. For :".$tParams['m_Description']);

                    }

                    
                } else {

                    // Handle SSL Certs
                }
                
                // Handle addon invoice Entries
                if(@$key['params']['addons']) {

                    ViewSignup_CreateAccounts::addStaffNotificationEvent("");
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("Package Addons:");
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");

                    $packageAddons = SignupView::getAddons($key['productId'], $key['params']['term']);

                    // Loop the addons in the array
                    foreach($key['params']['addons'] AS $addonId => $addonValue) {

                        // Explode the addon value
                        $addonExplode = explode("_", $addonValue);

                        // Check we have enough info from the post
                        if(count($addonExplode) == 4) {

                            // Set addons up
                            $workingItem['hasAddons'] = true;

                            // Get the addon
                            foreach($packageAddons as $addon) {

                                // Do we have the right addon?
                                if($addon['id'] == $addonId) {

                                    // Get the price
                                    foreach($addon['prices'] AS $price) {
                                        if($price['price_id'] == $addonExplode[2] && $price['recurringprice_cyle'] == $addonExplode[3]) {
                                            
                                            $addonDescription = $addon['name'] . ': ' . @$price['item_name'];

                                            // Check for something above 0
                                            if(@$price['item_price'] > 0) {

                                                if($newUser->getUsePaypalSubscriptions() && $this->firstCycle != @$price['recurringprice_cyle']) {
                                                    $disableGenerate = -1;
                                                } elseif ($newUser->getUsePaypalSubscriptions()) {
                                                    $disableGenerate = 1;
                                                } else {
                                                    $disableGenerate = 0;
                                                }


                                                // Process prorating
                                                $linePrice = $price['item_price'];
                                                $nextBillDate = ViewSignup_CreateAccounts::generateNextBillDate(@$price['recurringprice_cyle'],1);
                                                if($this->settings->get('Prorate To Day') != 0) {

                                                    list($itemPrice, $proRatedPrice, $proratedDays, $proIncFollowing, $tmpnextBill, $proNextBill) = $this->processProrating($this->settings->get('Prorate To Day'), $this->settings->get('Include Following Payment'), @$price['recurringprice_cyle'], $linePrice);

                                                    if($itemPrice != 0) {
                                                        $linePrice = $itemPrice + $proRatedPrice;
                                                    } else {
                                                        $linePrice = $proRatedPrice;
                                                    }
                                                    $nextBillDate['nextBilling'] = date("Y-m-d", $proNextBill);
                                                }

                                                
                                                $recurringEntry = new RecurringWork(array(
                                                   'description'           => $addonDescription,
                                                   'detail'                => '',
                                                   'billingtypeid'         => BILLINGTYPE_PACKAGE_ADDON,
                                                   'packageAddonPricesId'  => $price['price_id'],
                                                   'amount'                => $price['item_price'],
                                                   'disablegenerate'       => $disableGenerate,
                                                   'customerid'            => $this->customerId,
                                                   'paymentterm'           => @$price['recurringprice_cyle'],
                                                   'nextbilldate'          => $nextBillDate['nextBilling'],
                                                   'appliestoid'           => $userPackageId,
                                                   'taxable'               => (@$addon['taxable'])? 1 : 0));
                                                $recurringEntry->update();
                                                $this->log($this->signupLogLevel, "Signup: Cart: Created Recurring work. Paymentterm: '".$price['recurringprice_cyle']."'. For: ".$addonDescription);

                                                $todaybillingNice = date($this->settings->get('Date Format'), mktime(0, 0, 0, date("m"), date("d"),  date("Y")));
                                                $secondsInADay = 60*60*24;
                                                $nextbillingNice = date($this->settings->get('Date Format'), mktime(0, 0, 0, date("m", strtotime($nextBillDate['nextBilling'])), date("d", strtotime($nextBillDate['nextBilling'])),  date("Y", strtotime($nextBillDate['nextBilling']))) - $secondsInADay);

                                                $tParams = array(
                                                    'm_CustomerID'        => $this->customerId,
                                                    'm_Description'       => $addonDescription.', '.$todaybillingNice.' '.$this->lang("thru").' '.$nextbillingNice,
                                                    'm_Detail'            => '',
                                                    'm_invoiceid'         => 0,
                                                    'm_Date'              => date("Y-m-d"),
                                                    'm_BillingTypeID'     => BILLINGTYPE_PACKAGE_ADDON,
                                                    'm_IsProrating'       => 0,
                                                    'm_Price'             => $linePrice,
                                                    'm_Recurring'         => 1,
                                                    'm_IncludeNextPayment'=> 1,
                                                    'm_AppliesToID'       => $userPackageId,
                                                    'm_Setup'             => 0,
                                                    'm_Taxable'           => (@$addon['taxable'])? 1 : 0,
                                                    'm_RecurringAppliesTo' => @$recurringEntry->vars['id']['data'],
                                                    'm_BillingCycle'      => @$price['recurringprice_cyle']
                                                );
                                                $invoiceEntry = new InvoiceEntry($tParams);
                                                $invoiceEntry->updateRecord();

                                                $invoiceEntries .= $invoiceEntry->m_EntryID." ";
                                                $this->log($this->signupLogLevel, "Signup: Cart: Created Invoice Entry '".$invoiceEntry->m_EntryID."'. For :".$tParams['m_Description']);
                                                
                                            }
                                            
                                            // Handle the addon setup fee
                                            if(@$price['item_setup'] > 0) {
                                                
                                                $tParams = array(
                                                    'm_CustomerID'        => $this->customerId,
                                                    'm_Description'       => $addonDescription." (Setup)",
                                                    'm_Detail'            => '',
                                                    'm_invoiceid'         => 0,
                                                    'm_Date'              => date("Y-m-d"),
                                                    'm_BillingTypeID'     => BILLINGTYPE_PACKAGE_ADDON,
                                                    'm_IsProrating'       => 0,
                                                    'm_Price'             => $price['item_setup'],
                                                    'm_Recurring'         => 0,
                                                    'm_IncludeNextPayment'=> 1,
                                                    'm_AppliesToID'       => $userPackageId,
                                                    'm_Setup'             => 0,
                                                    'm_AddonSetup'        => 1,
                                                    'm_Taxable'           => (@$addon['taxable'])? 1 : 0,
                                                );
                                                $invoiceEntry = new InvoiceEntry($tParams);
                                                $invoiceEntry->updateRecord();

                                                $invoiceEntries .= $invoiceEntry->m_EntryID." ";
                                                $this->log($this->signupLogLevel, "Signup: Cart: Created Invoice Entry '".$invoiceEntry->m_EntryID."'. For :".$tParams['m_Description']);
                                            }

                                            ViewSignup_CreateAccounts::addStaffNotificationEvent($addonDescription." (".$price['item_price'].")");

                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                
                
                // Handle coupon code invoice entries
                if (@$key['couponCode']) {
                     
                    // Get the coupon info
                    $coupon = @$cartItems['couponCodes'][$key['couponCode']];
                    
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("");
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("Coupon:");
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");
                    
                    ViewSignup_CreateAccounts::addStaffNotificationEvent("Coupon Code: ".$coupon['code']);
                    
                    if ( $coupon['type'] == 1 ) {
                        ViewSignup_CreateAccounts::addStaffNotificationEvent("Coupon Discount: ".($coupon['discount']*100) . '%');
                    } else {
                        ViewSignup_CreateAccounts::addStaffNotificationEvent("Coupon Discount: ". $this->currencys->format($this->currency, $coupon['discount'], true));
                    }
                    
                    // Generate the descriptions
                    $m_Description = $this->lang('Discount coupon')." ".$coupon['code']." ($productFullName)";
                    $m_Detail = $m_Description."<br>Code: ".$coupon['code'];
                    $m_CouponRecurringAppliesTo = 0;
                    
                    $appendOnDescription = '';
                    if (@$coupon['recurring']) {

                        if($newUser->getUsePaypalSubscriptions() && $this->firstCycle != @$key['params']['term']) {
                            $disableGenerate = -1;
                        } elseif ($newUser->getUsePaypalSubscriptions()) {
                            $disableGenerate = 1;
                        } else {
                            $disableGenerate = 0;
                        }
                             
                        // create recurring entry
                        $nextBillDate = ViewSignup_CreateAccounts::generateNextBillDate(@$key['params']['term'], $productGroupInfo[$package->planid]->fields['type']);
                        $recurringEntry = new RecurringWork(array(
                            'description'       => $m_Description,
                            'detail'            => $m_Detail,
                            'billingtypeid'     => BILLINGTYPE_COUPON_DISCOUNT,
                            'amount'            => -$coupon['discount'],
                            'amountPercent'     => $coupon['type']? $coupon['discount'] : 0,
                            'disablegenerate'   => $disableGenerate,
                            'customerid'        => $this->customerId,
                            'paymentterm'       => @$key['params']['term'],
                            'nextbilldate'      => $nextBillDate['nextBilling'],
                            'appliestoid'       => $userPackageId,
                            'couponApplicableTo'=> $coupon['applicableTo'],
                            'taxable'           => ($coupon['taxable'] && $package->isTaxable())? 1 : 0,
                            'monthlyusage'      => @$key['params']['term'].'|'.$coupon['recurringmonths']));
                         $recurringEntry->update();
                         $m_CouponRecurringAppliesTo = $recurringEntry->vars['id']['data'];
                         $this->log($this->signupLogLevel, "Signup: Cart: Created Recurring work. Paymentterm: '".$key['params']['term']."'. For: ".$m_Description);

                        $todaybillingNice = date($this->settings->get('Date Format'), mktime(0, 0, 0, date("m"), date("d"),  date("Y")));
                        $secondsInADay = 60*60*24;
                        $nextbillingNice = date($this->settings->get('Date Format'), mktime(0, 0, 0, date("m", strtotime($nextBillDate['nextBilling'])), date("d", strtotime($nextBillDate['nextBilling'])),  date("Y", strtotime($nextBillDate['nextBilling']))) - $secondsInADay);
                        $appendOnDescription = ', '.$todaybillingNice.' '.$this->lang("thru").' '.$nextbillingNice;
                    }

                    $discountInvEntry = new InvoiceEntry(array(
                        'm_CustomerID'         => $this->customerId,
                        'm_Description'        => $m_Description.$appendOnDescription,
                        'm_Detail'             => $m_Detail,
                        'm_invoiceid'          =>  0,
                        'm_Date'               => date("Y-m-d"),
                        'm_BillingTypeID'      => BILLINGTYPE_COUPON_DISCOUNT,
                        'm_IsProrating'        => 0,
                        'm_Price'              => -$coupon['discount'],
                        'm_PricePercent'       => $coupon['type']? $coupon['discount'] : 0,
                        'm_Recurring'          => (@$coupon['recurring'])? $coupon['recurring'] : 0,
                        'm_RecurringAppliesTo' => $m_CouponRecurringAppliesTo,
                        'm_IncludeNextPayment' => 1,
                        'm_AppliesToID'        => $userPackageId,
                        'm_CouponApplicableTo' => $coupon['applicableTo'],
                        'm_Taxable'            => ($coupon['taxable'] && $package->isTaxable())? 1 : 0,
                    ));
                    $discountInvEntry->updateRecord();

                    $invoiceEntries .= $discountInvEntry->m_EntryID." ";
                    $this->log($this->signupLogLevel, "Signup: Cart: Created Invoice Entry '".$discountInvEntry->m_EntryID."'. For :".$m_Description);

                    $query = "INSERT INTO coupons_usage (invoiceentryid,couponid,isrecurring) VALUES(?,?,?)";
                    $data_insert = $this->db->query($query, $discountInvEntry->m_EntryID, $coupon['id'],0);


                    Coupon::updateQuantity($coupon['code']);
                }

                // Save the user package incase we made any changes
                $userPackage->save();
                $this->log($this->signupLogLevel, "Signup: Cart: Saved Product!");
            }


            // Handle the bundling of products
            // Not the most efficient way of doing things but we don't always know what
            // order products will be saved in the cart so we have to handle the bundling
            // outside of the main product creating loop
            foreach($productsToBundle AS $value => $key) {

                if(@is_numeric($cartItems[$key]['savedProductId'])) {

                    // Get the product
                    $userPackage = new UserPackage($cartItems[$key]['savedProductId']);

                    // Push the bundle ID
                    $userPackage->parentPackageId = $value;

                    $this->log($this->signupLogLevel, "Signup: Cart: Bundling Product '".$userPackage->fields['id']."' to '".$value."'");

                    // Save the product
                    $userPackage->save();
                }
            }
            
        } else {

            $this->log($this->signupLogLevel, "Signup: Something went wrong.");

            // Redirect to step 1
            include("modules/admin/views/public/Signup_0_PackageGroup.php");
            ViewSignup_0_PackageGroup::dispatch();
            return;
        }

        // Check for fraud message
        if ( isset($_SESSION['fraudmsg']) ) {
            ViewSignup_CreateAccounts::addStaffNotificationEvent("");
            ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");
            ViewSignup_CreateAccounts::addStaffNotificationEvent("Fraud Details");
            ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");
            foreach ( $_SESSION['fraudmsg'] as $msg ) {
                ViewSignup_CreateAccounts::addStaffNotificationEvent($msg);
            }
            unset($_SESSION['fraudmsg']);
        }

        // Add the IP and host information
        ViewSignup_CreateAccounts::addStaffNotificationEvent("");
        ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");
        ViewSignup_CreateAccounts::addStaffNotificationEvent("Signup Environment");
        ViewSignup_CreateAccounts::addStaffNotificationEvent("--------------");
        ViewSignup_CreateAccounts::addStaffNotificationEvent("IP: ".NE_Network::getRemoteAddr());
        ViewSignup_CreateAccounts::addStaffNotificationEvent("Hostname: ".@gethostbyaddr(NE_Network::getRemoteAddr()));
        ViewSignup_CreateAccounts::addStaffNotificationEvent("User Agent: ".@$_SERVER['HTTP_USER_AGENT']);

        $this->log($this->signupLogLevel, "Signup: STARTING PROCESSING PAYMENT");

        
        /*
         *  Process the actual billing & invoice any recurring work OR un-invoiced work created above
         */
        $processInvoice = true;
        $billingGateway = new BillingGateway($this->user);
        $invoiceData = $billingGateway->createInvoiceWithEntries($invoiceEntries,null,1);
        $tInvoiceID = $invoiceData['InvoiceID'];

        $this->log($this->signupLogLevel, "Signup: Payment: Merged Invoice Entries '".$invoiceEntries."' & created Invoice: ".$tInvoiceID);

        // Get the total invoice amount
        $query="SELECT id,balance_due, subtotal FROM invoice WHERE status = 0 AND customerid=? ORDER BY id DESC";
        $result = $this->db->query($query, $this->customerId);
        list($tinvoiceid,$invoiceAmount,$subtotal) = $result->fetch();

        // This information can be required for affiliates URL
        $invoice_information = array(
            'invoice_id'            => $tinvoiceid,
            'invoice_amount_no_tax' => $subtotal,
            'invoice_amount'        => $invoiceAmount
        );
        $_SESSION['invoice_information'] = base64_encode(serialize($invoice_information));

        //time to send staff notifications
        ViewSignup_CreateAccounts::sendStaffNotificationEmail($newUser);
        
        // Handle null invoices. Set to paid.
        if($invoiceAmount == 0) {

            $this->log($this->signupLogLevel, "Signup: Payment: Invoice '".$tinvoiceid."' amount was 0, marking as paid!");
            
            // Mark the invoice as paid
            $today = strftime("%Y-%m-%d",mktime (0,0,0,date("m"),date("d"),  date("Y")));
            $billingGateway->setPayInvoice($tinvoiceid);
            
            $processInvoice = false;

            // process invoice if user has recurring entries with subscriptions that'll generate
            // a non null payment in the future
            /*$query = "SELECT nextbilldate, "
                    ."paymentterm, "
                    ."SUM(amount) "
                    ."FROM recurringfee "
                    ."WHERE customerid = ? "
                    ."AND disablegenerate != 0 "
                    //."AND status = 1 "
                    ."GROUP BY nextbilldate, "
                    ."paymentterm "
                    ."HAVING SUM(amount) > 0 ";
            $result = $this->db->query($query, $this->customerId);
            if (!$result->getNumRows()) {
                $processInvoice = false;
            }*/
        }

        //If existing member, do not run the charge right now because of the CC number
        if($this->existingMember && @$this->settings->get("plugin_".$newUser->getPaymentType()."_Accept CC Number") == 1){
            $processInvoice = false;
        }

        //determine if plugin is of type dummy (manually processing)
        if (@$this->settings->get("plugin_".$newUser->getPaymentType()."_Dummy Plugin") == 1){
           $isDummy = true;
        } else {
           $isDummy = false;
        }

        if (!$newUser->isAutopayment() || !$processInvoice || $isDummy || $this->settings->get('Forward To Gateway') != 1

            // special case: quantum gateway is autopayment, but may redirect at signup when using VbV or MC SecureCode verifications,
            // so we need to send the signup notification before it gets redirected
            || (    $newUser->getPaymentType() == 'quantum'
                    && (    $this->settings->get('plugin_quantum_Use Verify By Visa and MasterCard SecureCode')
                            || $this->settings->get('plugin_quantum_Use DialVerify Service')
                       )
                    && !isset($this->existingMember) // when it's an existing member, there's no redirection
               )
           )
        {
            // Send out the notification before the user is redirected
            $this->log($this->signupLogLevel, "Signup: Payment: Selected gateway may take us off this page, so send relevant emails now.");
            ViewSignup_CreateAccounts::sendAccountCreationEmail($newUser);
            $this->log($this->signupLogLevel, "Signup: Sent account creation email");
        }

        //Always send invoice, no matter if later forwarding to gateway or not
        if($invoiceAmount == 0) {
            $billingGateway->sendPaymentEmail($tinvoiceid, $this);
        }else{
            if($this->settings->get('Send Invoice Immediately')){
                $mailStatus = $billingGateway->sendInvoiceByEmail($tinvoiceid);
                if(!is_a($mailStatus, 'NE_Error')) {
                    $billingGateway->updateInvoiceSent($tinvoiceid);
                }
            }
        }
                
		//for stock enabled items this call removes the items
		//from active_orders so that the items are not readded
		//as stock when the expires datetime is reached.  Since this
		//order is complete we don't need to worry about it's cart contents
		$this->orderCompleted();

        if (($this->settings->get('Forward To Gateway')==1) && $processInvoice && !$isDummy) {
        
			//lets remove cart items if it isn't autopayment
			//or if it is quantum with forward to gateway instead of gateway processing
			if (!$newUser->isAutopayment() || (    $newUser->getPaymentType() == 'quantum'
                    && (    $this->settings->get('plugin_quantum_Use Verify By Visa and MasterCard SecureCode')
                            || $this->settings->get('plugin_quantum_Use DialVerify Service')
                       )
                    && !isset($this->existingMember) // when it's an existing member, there's no redirection
               )) {
				$this->destroyCart();
				$this->destroyCurrency();
				//$this->destroyInvoiceInformation(); // This line will cause issues with affiliate
			}

            $this->log($this->signupLogLevel, "Signup: Payment: Fowarding to selected gateway: '".$newUser->getPaymentType()."'");

            //Need to get invoice and then forward to gateway
            //prep variables needed for sendToBill
            $tSendToBill_InvoiceID=$tinvoiceid;
            $tSendToBill_Signup=true;
            $tSendToBill_FirstTime=true;
            $tSendToBill_CreditCardNumber = @$_REQUEST[@$_REQUEST['paymentMethod'].'_ccNumber'];
            if( isset($_REQUEST[@$_REQUEST['paymentMethod'].'_ccMonth']) && isset($_REQUEST[@$_REQUEST['paymentMethod'].'_ccYear'])){
                $tSendToBill_CreditCardExp = sprintf("%02d", $_REQUEST[@$_REQUEST['paymentMethod'].'_ccMonth'])."/".$_REQUEST[@$_REQUEST['paymentMethod'].'_ccYear'];
                if (isset($_REQUEST[@$_REQUEST['paymentMethod'].'_ccCVV2'])) {
                    $tSendToBill_CreditCardCVV2 = htmlspecialchars($_REQUEST[@$_REQUEST['paymentMethod'].'_ccCVV2']);
                }
            }
            require_once 'modules/billing/actSendToBill.php';
            if ($tError != '') {

                // ** don't delete client if he's an existing member !! **
                if (!$this->existingMember) {
                    $tUser = new User($this->customerId);
                    $tUser->delete(false, false);

                    $this->log($this->signupLogLevel, "Signup: Payment: DELETING CLIENT DUE TO PAYMENT ERROR.");
                }

                $this->log($this->signupLogLevel, "Signup: Payment: ERROR: ".$tError);

                // Throw the error
                $this->failedValidation($tError);
                return;
            } elseif ($newUser->isAutopayment()) {
                //$this->sendOutNotifications($tFirstName,$tLastName,$this->domain,$strMessageOutput,$bMember);
                ViewSignup_CreateAccounts::sendAccountCreationEmail($newUser);
                $this->log($this->signupLogLevel, "Signup: Sent account creation email");
            }

            $this->log($this->signupLogLevel, "Signup: Payment: Gateway payment went without errors!");
        }
        
        // Un-cancel a user
        if($newUser->getStatus() == -2){
            $newUser->setStatus(0);
            $newUser->save();

            $this->log($this->signupLogLevel, "Signup: Payment: Un-cancelling User account!");
        }

        $this->log($this->signupLogLevel, "******* SIGNUP COMPLETE ********");	           

        // Actually handle the signup URL setting
        if($this->settings->get('Signup Completion URL') != '') {
            NE_Lib::redirectPage($this->settings->get('Signup Completion URL'). '?success=1');
            exit;
        } 
		
        // For now just faux send people to step 5
        include("modules/admin/views/public/Signup_5_Complete.php");
        ViewSignup_5_Complete::dispatch();
    }


    /**
    * If the new customer previously had a guest account, move the tickets from the guest account
    * and delete the guest account.
    *
    * @access private
    */
    function _importGuestTickets(&$user)
    {
        $userGateway = new UserGateway();

        if (!$guestUserIt = $userGateway->getGuestUserIteratorWithEmail($user->getEmail())) {
            return;
        }

        if (!$guestUser = $guestUserIt->fetch()) {
            return;
        }

        $this->log($this->signupLogLevel, "Signup: Attempting to import guest tickets from: '".$guestUser->getId()."'.");

        require_once 'modules/support/actions/SetOwner.php';
        $setOwner = new SetOwner('support', 'SetOwner');
        $setOwner->setUser($this->user);
        $setOwner->setCustomer($this->customer);
        $setOwner->moveTicketsFromGuestUser($guestUser, $user);
    }

    /*
     * Generate the next recurring billing date when given the term
     * and type
     */
    function generateNextBillDate($paymentterm, $type) {

        $nextbilldate = time();

        // Domains
        if($type == 3 ) {
            $nextbilling = date("Y") + $paymentterm ."-".date("m-d");
            $nextbillingNice = $nextbilling;
        } else {
            // Individual cases for this
            if($paymentterm < '12') {
                $nextbilling = strftime("%Y-%m-%d",mktime (0, 0, 0, date("m", $nextbilldate) + $paymentterm, date("d", $nextbilldate),  date("Y", $nextbilldate)));
                $nextbillingNice = date($this->settings->get('Date Format'), mktime (0, 0, 0, date("m", $nextbilldate) + $paymentterm, date("d", $nextbilldate),  date("Y", $nextbilldate)));
            } else {
                $tYear = $paymentterm / 12;
                $nextbilling = strftime("%Y-%m-%d", mktime (0, 0,0, date("m", $nextbilldate), date("d", $nextbilldate), date("Y", $nextbilldate) + $tYear));
                $nextbillingNice = date($this->settings->get('Date Format'), mktime (0, 0, 0, date("m", $nextbilldate), date("d", $nextbilldate),  date("Y", $nextbilldate) + $tYear));
            }
        }

        return array('nextBilling' => $nextbilling, 'formattedBilling' => $nextbillingNice);

    }


    /**
     * Function to send new order email to staff
     *
     * @param User $newUser passes User object
     *
     * @return void
     */
    function sendStaffNotificationEmail($newUser)
    {
        //check if we have any staff emails we need to notify
        $emailAddresses = $this->settings->get('E-mail For New Signups');
        $emailAddresses = trim($emailAddresses);
        if ($emailAddresses == '') {
            return;
        }
        
        // Get the template
        $templategateway = new AutoresponderTemplateGateway();
        $template = $templategateway->getEmailTemplateByName("New Order Notification");
        $strMessage = $template->getContents(true);

        //Replace the non-standard
        //Need to add order information
        foreach ($strMessage as $mailType => $trash) {
            $strMessage[$mailType] = str_replace("[ORDERINFO]", $this->signupEmail[$mailType], $strMessage[$mailType]);
        }
        $mailer = new NE_MailGateway();
        $aSupportEmail = explode("\r\n", $emailAddresses);
        foreach ($aSupportEmail as $email)
        {
            $mailer->mailMessageEmail(  $strMessage,
                $this->settings->get('Support E-mail'),
                $this->settings->get('Billing Name'),
                $email,
                '',
                $template->getSubject(),
                3,
                0,
                '',
                '');
        }
    }

    /**
     * Function to add an entry to the email to send to staff
     */
    function addStaffNotificationEvent($event) {
        @$this->signupEmail['HTML'] .= $event."<br>";
        @$this->signupEmail['plainText'] .= $event."\n";
    }

    /**
     * Function to send the account creation email to the customer. Need to do this in a function
     * so that we can call it before we redirect to the gateway but not if we're deleting a user
     */
    function sendAccountCreationEmail(&$newUser)
    {
         /*
         * Handle sending of account welcome email if required
         * No need to send it to existing members
         */
        if($this->settings->get('Send Account Welcome E-mail') == 0 && $this->existingMember == false) {

            // Get the template
            $templategateway = new AutoresponderTemplateGateway();
            $template = $templategateway->getEmailTemplateByName("Account Creation");
            $strMessage = $template->getContents(true);

            // Replace the non-standard
            foreach ($strMessage as $mailType => $trash) {
                $strMessage[$mailType] = str_replace("[CLIENTEMAIL]", $newUser->getEmail(), $strMessage[$mailType]);
                $strMessage[$mailType] = str_replace("[CLIENTNAME]", $newUser->getFullName(), $strMessage[$mailType]);
                $strMessage[$mailType] = str_replace("[COMPANYNAME]", $this->settings->get("Company Name"), $strMessage[$mailType]);
                $strMessage[$mailType] = str_replace("[CLIENTAPPLICATIONURL]", NE_Lib::getSoftwareURL(), $strMessage[$mailType]);
            }

            // Send the email
            if ($newUser->getEmail() != "") {
                $mailer = new NE_MailGateway();
                $mailer->mailMessageEmail(  $strMessage,
                                            $this->settings->get('Billing E-mail'),
                                            $this->settings->get('Billing Name'),
                                            $newUser->getEmail(),
                                            '',
                                            $template->getSubject(),
                                            3,
                                            0,
                                            '',
                                            '');

                // Log the email sending
                $clientLog = Client_EventLog::newInstance($this->customerId, $this->customerId, CLIENT_EVENTLOG_SENTACCTEMAIL, -2);
                $this->logger->addEventLog($clientLog);
            }
        }
    }

}

?>
