예제 #1
0
 /**
  * Create or update an invoice from a subscription
  *
  * @param   object $sub The subscription record
  *
  * @return  bool
  */
 public function createInvoice($sub)
 {
     // Do we already have an invoice record?
     $db = $this->getDbo();
     $query = $db->getQuery(true)->select('*')->from($db->qn('#__akeebasubs_invoices'))->where($db->qn('akeebasubs_subscription_id') . ' = ' . $db->q($sub->akeebasubs_subscription_id));
     $db->setQuery($query);
     $invoiceRecord = $db->loadObject();
     $existingRecord = is_object($invoiceRecord);
     // Flag to know if the template allows me to create an invoice
     $preventInvoice = false;
     $invoiceData = array();
     // Preload helper classes
     if (!class_exists('AkeebasubsHelperCparams')) {
         require_once JPATH_ADMINISTRATOR . '/components/com_akeebasubs/helpers/cparams.php';
     }
     if (!class_exists('AkeebasubsHelperFormat')) {
         require_once JPATH_ADMINISTRATOR . '/components/com_akeebasubs/helpers/format.php';
     }
     if (!class_exists('AkeebasubsHelperMessage')) {
         require_once JPATH_ROOT . '/components/com_akeebasubs/helpers/message.php';
     }
     // Get the template
     $templateRow = $this->findTemplate($sub);
     if (is_object($templateRow)) {
         $template = $templateRow->template;
         $templateId = $templateRow->akeebasubs_invoicetemplate_id;
         $globalFormat = $templateRow->globalformat;
         $globalNumbering = $templateRow->globalnumbering;
         // Do I have a "no invoice" flag?
         $preventInvoice = (bool) $templateRow->noinvoice;
     } else {
         $template = '';
         $templateId = 0;
         $globalFormat = true;
         $globalNumbering = true;
     }
     // Do I have a "no invoice" flag on template or subscription?
     $sub_params = new JRegistry($sub->params);
     if ($preventInvoice || $sub_params->get('noinvoice', false)) {
         $sub_params->set('noinvoice', true);
         // I have to manually update the db, using the table object will cause an endless loop
         $query = $db->getQuery(true)->update('#__akeebasubs_subscriptions')->set($db->qn('params') . ' = ' . $db->quote((string) $sub_params))->where($db->qn('akeebasubs_subscription_id') . ' = ' . $sub->akeebasubs_subscription_id);
         $db->setQuery($query)->query();
         return false;
     }
     if ($globalFormat) {
         $numberFormat = AkeebasubsHelperCparams::getParam('invoice_number_format', '[N:5]');
     } else {
         $numberFormat = $templateRow->format;
     }
     if ($globalNumbering) {
         $numberOverride = AkeebasubsHelperCparams::getParam('invoice_override', 0);
     } else {
         $numberOverride = $templateRow->number_reset;
     }
     // Get the configuration variables
     if (!$existingRecord) {
         $jInvoiceDate = JFactory::getDate();
         $invoiceData = array('akeebasubs_subscription_id' => $sub->akeebasubs_subscription_id, 'extension' => 'akeebasubs', 'invoice_date' => $jInvoiceDate->toSql(), 'enabled' => 1, 'created_on' => $jInvoiceDate->toSql(), 'created_by' => $sub->user_id);
         if ($numberOverride) {
             // There's an override set. Use it and reset the override to 0.
             $invoice_no = $numberOverride;
             if ($globalNumbering) {
                 // Global number override reset
                 AkeebasubsHelperCparams::setParam('invoice_override', 0);
             } else {
                 // Invoice template number override reset
                 $templateTable = F0FModel::getTmpInstance('Invoicetemplates', 'AkeebasubsModel')->getItem($templateRow->akeebasubs_invoicetemplate_id);
                 $templateTable->save(array('number_reset' => 0));
             }
         } else {
             if ($globalNumbering) {
                 // Find all the invoice template IDs using Global Numbering and filter by them
                 $q = $db->getQuery(true)->select($db->qn('akeebasubs_invoicetemplate_id'))->from($db->qn('#__akeebasubs_invoicetemplates'))->where($db->qn('globalnumbering') . ' = ' . $db->q(1));
                 $db->setQuery($q);
                 $rawIDs = $db->loadColumn();
                 $gnitIDs = array();
                 foreach ($rawIDs as $id) {
                     $gnitIDs[] = $db->q($id);
                 }
             }
             // Get the new invoice number by adding one to the previous number
             $query = $db->getQuery(true)->select($db->qn('invoice_no'))->from($db->qn('#__akeebasubs_invoices'))->where($db->qn('extension') . ' = ' . $db->q('akeebasubs'))->order($db->qn('created_on') . ' DESC');
             // When not using global numbering search only invoices using this specific invoice template
             if (!$globalNumbering) {
                 $query->where($db->qn('akeebasubs_invoicetemplate_id') . ' = ' . $db->q($templateId));
             } else {
                 $query->where($db->qn('akeebasubs_invoicetemplate_id') . ' IN(' . implode(',', $gnitIDs) . ')');
             }
             $db->setQuery($query, 0, 1);
             $invoice_no = (int) $db->loadResult();
             if (empty($invoice_no)) {
                 $invoice_no = 0;
             }
             $invoice_no++;
         }
         // Parse the invoice number
         $formated_invoice_no = $this->formatInvoiceNumber($numberFormat, $invoice_no, $jInvoiceDate->toUnix());
         // Add the invoice number (plain and formatted) to the record
         $invoiceData['invoice_no'] = $invoice_no;
         $invoiceData['display_number'] = $formated_invoice_no;
         // Add the invoice template ID to the record
         $invoiceData['akeebasubs_invoicetemplate_id'] = $templateId;
     } else {
         // Existing record, make sure it's extension=akeebasubs or quit
         if ($invoiceRecord->extension != 'akeebasubs') {
             $this->setId(0);
             return false;
         }
         $invoice_no = $invoiceRecord->invoice_no;
         $formated_invoice_no = $invoiceRecord->display_number;
         if (empty($formated_invoice_no)) {
             $formated_invoice_no = $invoice_no;
         }
         $jInvoiceDate = JFactory::getDate($invoiceRecord->invoice_date);
         $invoiceData = (array) $invoiceRecord;
     }
     // Get the custom variables
     $vat_notice = '';
     $cyprus_tag = 'TRIANGULAR TRANSACTION';
     $cyprus_note = 'We are obliged by local tax laws to write the words "triangular transaction" on all invoices issued in Euros. This doesn\'t mean anything in particular about your transaction.';
     $kuser = F0FModel::getTmpInstance('Users', 'AkeebasubsModel')->user_id($sub->user_id)->getFirstItem();
     $country = $kuser->country;
     $isbusiness = $kuser->isbusiness;
     $viesregistered = $kuser->viesregistered;
     $inEU = AkeebasubsHelperEuVATInfo::isEUVATCountry($country);
     // If the shopCountry is the same as the user's country we don't need to put the reverse charge info
     $shopCountry = AkeebasubsHelperCparams::getParam('invoice_country');
     $reverse = $country == $shopCountry ? false : true;
     if ($inEU && $isbusiness && $viesregistered && $reverse) {
         $vat_notice = AkeebasubsHelperCparams::getParam('invoice_vatnote', 'VAT liability is transferred to the recipient, pursuant EU Directive nr 2006/112/EC and local tax laws implementing this directive.');
         $cyprus_tag = 'REVERSE CHARGE';
         $cyprus_note = 'We are obliged by local and European tax laws to write the words "reverse charge" on all invoices issued to EU business when no VAT is charged. This is supposed to serve as a reminder that the recipient of the invoice (you) have to be registered to your local VAT office so as to apply to YOUR business\' VAT form the VAT owed by this transaction on the reverse charge basis, as described above. The words "reverse charge" DO NOT indicate a problem with your transaction, a cancellation or a refund.';
     }
     $extras = array('[INV:ID]' => $invoice_no, '[INV:PLAIN_NUMBER]' => $invoice_no, '[INV:NUMBER]' => $formated_invoice_no, '[INV:INVOICE_DATE]' => AkeebasubsHelperFormat::date($jInvoiceDate->toUnix()), '[INV:INVOICE_DATE_EU]' => $jInvoiceDate->format('d/m/Y', true), '[INV:INVOICE_DATE_USA]' => $jInvoiceDate->format('m/d/Y', true), '[INV:INVOICE_DATE_JAPAN]' => $jInvoiceDate->format('Y/m/d', true), '[VAT_NOTICE]' => $vat_notice, '[CYPRUS_TAG]' => $cyprus_tag, '[CYPRUS_NOTE]' => $cyprus_note);
     // Render the template into HTML
     $invoiceData['html'] = AkeebasubsHelperMessage::processSubscriptionTags($template, $sub, $extras);
     // Save the record
     if ($existingRecord) {
         $o = (object) $invoiceData;
         $db->updateObject('#__akeebasubs_invoices', $o, 'akeebasubs_subscription_id');
     } else {
         $o = (object) $invoiceData;
         $db->insertObject('#__akeebasubs_invoices', $o);
     }
     // Set up the return value
     $ret = $invoice_no;
     $this->setId($sub->akeebasubs_subscription_id);
     // Create PDF
     $this->createPDF();
     // Update subscription record with the invoice number without saving the
     // record through the Model, as this triggers the integration plugins,
     // which in turn causes double emails to be sent out. Baazinga!
     $query = $db->getQuery(true)->update($db->qn('#__akeebasubs_subscriptions'))->set($db->qn('akeebasubs_invoice_id') . ' = ' . $db->q($invoice_no))->where($db->qn('akeebasubs_subscription_id') . ' = ' . $db->q($sub->akeebasubs_subscription_id));
     $db->setQuery($query);
     $db->execute();
     $sub->akeebasubs_invoice_id = $invoice_no;
     // If auto-send is enabled, send the invoice by email
     $autoSend = AkeebasubsHelperCparams::getParam('invoice_autosend', 1);
     if ($autoSend) {
         $this->emailPDF();
     }
     return true;
 }
예제 #2
0
    switch ($code) {
        case 'XX':
            $options[] = JHtml::_('select.option', $code, JText::_('MOD_AKTAXCOUNTRY_LBL_INTERNATIONAL'));
            break;
        case 'EU-VIES':
            $options[] = JHtml::_('select.option', $code, JText::_('MOD_AKTAXCOUNTRY_LBL_EUBUSINES'));
            break;
        default:
            if (array_key_exists($code, $countryNames)) {
                $options[] = JHtml::_('select.option', $code, $countryNames[$code]);
            } else {
                $options[] = JHtml::_('select.option', $code, $code);
            }
            break;
    }
}
// Try to guess the default value
$default_option = JFactory::getSession()->get('country', null, 'mod_aktaxcountry');
if (empty($default_option)) {
    $taxHelper = F0FModel::getTmpInstance('Taxhelper', 'AkeebasubsModel');
    $taxparams = $taxHelper->getTaxDefiningParameters();
    $default_option = $taxparams['country'];
    if ($taxparams['vies'] && AkeebasubsHelperEuVATInfo::isEUVATCountry($taxparams['country'])) {
        $default_option = 'EU-VIES';
    }
}
if (empty($default_option)) {
    $default_option = 'XX';
}
// Load the layout file
require_once JModuleHelper::getLayoutPath($module->module);
예제 #3
0
 /**
  * Creates new tax rules based on the user preferences
  */
 public function createTaxRules()
 {
     // Get the state variables
     $params = $this->getStateVars();
     // Should I proceed?
     if ($params->novatcalc) {
         // User opted out from VAT configuration
         return;
     }
     // Is this an EU country?
     $euCountries = AkeebasubsHelperEuVATInfo::getEUVATCountries();
     $inEU = AkeebasubsHelperEuVATInfo::isEUVATCountry($params->country);
     // Store the country where the business is based (needed for proper invoicing)
     AkeebasubsHelperCparams::setParam('invoice_country', $params->country);
     // Prototype for tax rules
     $data = array('akeebasubs_level_id' => $params->akeebasubs_level_id, 'country' => '', 'state' => '', 'city' => '', 'vies' => 0, 'taxrate' => 0, 'enabled' => 1, 'ordering' => 0);
     $ordering = 0;
     if (!$inEU && !$params->viesreg) {
         // Non-EU business, without an EU VAT ID
         // A. All countries, with or without VIES registration: taxrate%
         $data['taxrate'] = $params->taxrate;
         $data['ordering'] = ++$ordering;
         F0FModel::getTmpInstance('Taxrules', 'AkeebasubsModel')->setId(0)->save($data);
         $data['vies'] = 1;
         $data['ordering'] = ++$ordering;
         F0FModel::getTmpInstance('Taxrules', 'AkeebasubsModel')->setId(0)->save($data);
     } elseif ($params->viesreg) {
         // EU VIES-registered business, or non-EU business with an EU VAT ID
         // A. All countries, with or without VIES registration, 0%
         $data['ordering'] = ++$ordering;
         F0FModel::getTmpInstance('Taxrules', 'AkeebasubsModel')->setId(0)->save($data);
         $data['vies'] = 1;
         $data['ordering'] = ++$ordering;
         F0FModel::getTmpInstance('Taxrules', 'AkeebasubsModel')->setId(0)->save($data);
         // B.1. All countries with the same VAT number prefix as mine, with or without VIES registration, taxrate%
         $data['taxrate'] = $params->taxrate;
         $myVATNrPrefix = AkeebasubsHelperEuVATInfo::getEUVATPrefix($params->country);
         foreach ($euCountries as $country) {
             $theirVATNrPrefix = AkeebasubsHelperEuVATInfo::getEUVATPrefix($country);
             if ($theirVATNrPrefix != $myVATNrPrefix) {
                 continue;
             }
             $data['country'] = $country;
             $data['vies'] = 0;
             $data['ordering'] = ++$ordering;
             F0FModel::getTmpInstance('Taxrules', 'AkeebasubsModel')->setId(0)->save($data);
             $data['vies'] = 1;
             $data['ordering'] = ++$ordering;
             F0FModel::getTmpInstance('Taxrules', 'AkeebasubsModel')->setId(0)->save($data);
         }
         // C. All other EU countries, without VIES registration, taxrate% (and with VIES: 0%)
         foreach ($euCountries as $country) {
             $theirVATNrPrefix = AkeebasubsHelperEuVATInfo::getEUVATPrefix($country);
             if ($theirVATNrPrefix == $myVATNrPrefix) {
                 continue;
             }
             // New VAT MOSS rules (post-2015): Each country gets its own VAT rate
             $data['taxrate'] = AkeebasubsHelperEuVATInfo::getEUVATRate($country);
             $data['vies'] = 0;
             $data['country'] = $country;
             $data['ordering'] = ++$ordering;
             F0FModel::getTmpInstance('Taxrules', 'AkeebasubsModel')->setId(0)->save($data);
         }
     } else {
         // EU non-VIES-registered business
         // A. All countries, with or without VIES registration, 0%
         $data['ordering'] = ++$ordering;
         F0FModel::getTmpInstance('Taxrules', 'AkeebasubsModel')->setId(0)->save($data);
         $data['vies'] = 1;
         $data['ordering'] = ++$ordering;
         F0FModel::getTmpInstance('Taxrules', 'AkeebasubsModel')->setId(0)->save($data);
         // B. All EU countries, with or without VIES registration, taxrate%
         foreach ($euCountries as $country) {
             // New VAT MOSS rules (post-2015): Each country gets its own VAT rate
             $data['taxrate'] = AkeebasubsHelperEuVATInfo::getEUVATRate($country);
             $data['country'] = $country;
             $data['vies'] = 0;
             $data['ordering'] = ++$ordering;
             F0FModel::getTmpInstance('Taxrules', 'AkeebasubsModel')->setId(0)->save($data);
             $data['vies'] = 1;
             $data['ordering'] = ++$ordering;
             F0FModel::getTmpInstance('Taxrules', 'AkeebasubsModel')->setId(0)->save($data);
         }
     }
 }
예제 #4
0
 /**
  * Gets the applicable tax rule based on the state variables
  */
 private function _getTaxRule()
 {
     // Do we have a VIES registered VAT number?
     $validation = $this->_validateState();
     $state = $this->getStateVariables();
     $isVIES = $validation->vatnumber && AkeebasubsHelperEuVATInfo::isEUVATCountry($state->country);
     if ($state->slug && empty($state->id)) {
         $list = F0FModel::getTmpInstance('Levels', 'AkeebasubsModel')->slug($state->slug)->getItemList();
         if (!empty($list)) {
             $item = array_pop($list);
             $state->id = $item->akeebasubs_level_id;
         } else {
             $state->id = 0;
         }
     }
     /** @var AkeebasubsModelTaxhelper $taxModel */
     $taxModel = F0FModel::getTmpInstance('Taxhelper', 'AkeebasubsModel');
     return $taxModel->getTaxRule($state->id, $state->country, $state->state, $state->city, $isVIES);
 }
예제 #5
0
 public static function isVIESValidVATNumber($country, $vat)
 {
     // Get the VAT validation cache from the session
     if (false && !array_key_exists('vat', self::$cache)) {
         $session = JFactory::getSession();
         $encodedCacheData = $session->get('vat_validation_cache_data', null, 'com_akeebasubs');
         if (!empty($encodedCacheData)) {
             self::$cache = json_decode($encodedCacheData, true);
         } else {
             self::$cache = array();
         }
     }
     if (!is_array(self::$cache)) {
         self::$cache = array();
     }
     // Sanitize the VAT number
     list($vat, $prefix) = self::sanitizeVATNumber($country, $vat);
     // Is the validation already cached?
     $key = $prefix . $vat;
     $ret = null;
     if (array_key_exists('vat', self::$cache)) {
         if (array_key_exists($key, self::$cache['vat'])) {
             $ret = self::$cache['vat'][$key];
         }
     }
     if (!is_null($ret)) {
         return $ret;
     }
     if (empty($vat)) {
         $ret = false;
     } else {
         if (!class_exists('SoapClient')) {
             $ret = false;
         } else {
             // Using the SOAP API
             // Code credits: Angel Melguiz / KMELWEBDESIGN SLNE (www.kmelwebdesign.com)
             try {
                 $sOptions = array('user_agent' => 'PHP');
                 $sClient = new SoapClient('http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl', $sOptions);
                 $params = array('countryCode' => $prefix, 'vatNumber' => $vat);
                 $response = $sClient->checkVat($params);
                 if ($response->valid) {
                     $ret = true;
                 } else {
                     $ret = false;
                 }
             } catch (SoapFault $e) {
                 $ret = false;
             }
         }
     }
     // Cache the result
     if (!array_key_exists('vat', self::$cache)) {
         self::$cache['vat'] = array();
     }
     self::$cache['vat'][$key] = $ret;
     $encodedCacheData = json_encode(self::$cache);
     $session = JFactory::getSession();
     $session->set('vat_validation_cache_data', $encodedCacheData, 'com_akeebasubs');
     // Return the result
     return $ret;
 }