// New profitability calculation

This commit is contained in:
Damien Metzger
2013-10-22 11:39:57 +02:00
parent d8d9436f51
commit 16cf10d586
3 changed files with 159 additions and 93 deletions
+30 -45
View File
@@ -404,61 +404,46 @@ class CarrierCore extends ObjectModel
*/ */
public static function getCarriers($id_lang, $active = false, $delete = false, $id_zone = false, $ids_group = null, $modules_filters = self::PS_CARRIERS_ONLY) public static function getCarriers($id_lang, $active = false, $delete = false, $id_zone = false, $ids_group = null, $modules_filters = self::PS_CARRIERS_ONLY)
{ {
if (!Validate::isBool($active)) // Filter by groups and no groups => return empty array
die(Tools::displayError()); if ($ids_group && (!is_array($ids_group) || !count($ids_group)))
if ($ids_group) return array();
{
$ids = ''; $sql = '
foreach ($ids_group as $id) SELECT c.*, cl.delay
$ids .= (int)$id.', '; FROM `'._DB_PREFIX_.'carrier` c
$ids = rtrim($ids, ', '); LEFT JOIN `'._DB_PREFIX_.'carrier_lang` cl ON (c.`id_carrier` = cl.`id_carrier` AND cl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('cl').')
if ($ids == '') LEFT JOIN `'._DB_PREFIX_.'carrier_zone` cz ON (cz.`id_carrier` = c.`id_carrier`)'.
return array(); ($id_zone ? 'LEFT JOIN `'._DB_PREFIX_.'zone` z ON (z.`id_zone` = '.(int)$id_zone.')' : '').'
} '.Shop::addSqlAssociation('carrier', 'c').'
WHERE c.`deleted` = '.($delete ? '1' : '0');
if ($active)
$sql .= ' AND c.`active` = 1 ';
if ($id_zone)
$sql .= ' AND cz.`id_zone` = '.(int)$id_zone.' AND z.`active` = 1 ';
if ($ids_group)
$sql .= ' AND c.id_carrier IN (SELECT id_carrier FROM '._DB_PREFIX_.'carrier_group WHERE id_group IN ('.implode(',', array_map('intval', $ids_group)).')) ';
$sql = 'SELECT c.*, cl.delay
FROM `'._DB_PREFIX_.'carrier` c
LEFT JOIN `'._DB_PREFIX_.'carrier_lang` cl ON (c.`id_carrier` = cl.`id_carrier` AND cl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('cl').')
LEFT JOIN `'._DB_PREFIX_.'carrier_zone` cz ON (cz.`id_carrier` = c.`id_carrier`)'.
($id_zone ? 'LEFT JOIN `'._DB_PREFIX_.'zone` z ON (z.`id_zone` = '.(int)$id_zone.')' : '').'
'.Shop::addSqlAssociation('carrier', 'c').'
WHERE c.`deleted` = '.($delete ? '1' : '0').
($active ? ' AND c.`active` = 1' : '').
($id_zone ? ' AND cz.`id_zone` = '.(int)$id_zone.'
AND z.`active` = 1 ' : ' ');
switch ($modules_filters) switch ($modules_filters)
{ {
case 1 : case 1 :
$sql .= 'AND c.is_module = 0 '; $sql .= ' AND c.is_module = 0 ';
break; break;
case 2 : case 2 :
$sql .= 'AND c.is_module = 1 '; $sql .= ' AND c.is_module = 1 ';
break; break;
case 3 : case 3 :
$sql .= 'AND c.is_module = 1 AND c.need_range = 1 '; $sql .= ' AND c.is_module = 1 AND c.need_range = 1 ';
break; break;
case 4 : case 4 :
$sql .= 'AND (c.is_module = 0 OR c.need_range = 1) '; $sql .= ' AND (c.is_module = 0 OR c.need_range = 1) ';
break; break;
case 5 :
$sql .= '';
break;
} }
$sql .= ($ids_group ? ' AND c.id_carrier IN (SELECT id_carrier FROM '._DB_PREFIX_.'carrier_group WHERE id_group IN ('.$ids.')) ' : '').' $sql .= ' GROUP BY c.`id_carrier` ORDER BY c.`position` ASC';
GROUP BY c.`id_carrier`
ORDER BY c.`position` ASC';
$carriers = Db::getInstance()->executeS($sql); $carriers = Db::getInstance()->executeS($sql);
foreach ($carriers as $key => $carrier)
if (is_array($carriers) && count($carriers)) if ($carrier['name'] == '0')
{ $carriers[$key]['name'] = Configuration::get('PS_SHOP_NAME');
foreach ($carriers as $key => $carrier)
if ($carrier['name'] == '0')
$carriers[$key]['name'] = Configuration::get('PS_SHOP_NAME');
}
else
$carriers = array();
return $carriers; return $carriers;
} }
+93 -40
View File
@@ -63,62 +63,103 @@ class AdminDashboardControllerCore extends AdminController
protected function getOptionFields() protected function getOptionFields()
{ {
$forms = array();
$currency = new Currency(Configuration::get('PS_CURRENCY_DEFAULT')); $currency = new Currency(Configuration::get('PS_CURRENCY_DEFAULT'));
$fields = array(); $carriers = Carrier::getCarriers($this->context->language->id, true);
$modules = Module::getModulesOnDisk(true); $modules = Module::getModulesOnDisk(true);
$forms = array(
'payment' => array('title' => $this->l('Average bank fees per payment method')),
'carriers' => array('title' => $this->l('Average shipping fees per shipping method')),
'other' => array('title' => $this->l('Other settings')),
'expenses' => array('title' => $this->l('Other expenses'))
);
foreach ($forms as &$form)
{
$form['icon'] = 'tab-preferences';
$form['fields'] = array();
$form['submit'] = array('title' => $this->l('Save'), 'class' => 'button');
}
foreach ($modules as $module) foreach ($modules as $module)
if ($module->tab == 'payments_gateways' && $module->id) if ($module->tab == 'payments_gateways' && $module->id)
{ {
$fields['CONF_'.strtoupper($module->name).'_FIXED_FEE'] = array( $forms['payment']['fields']['CONF_'.strtoupper($module->name).'_FIXED'] = array(
'title' => sprintf($this->l('Fixed fee / %s'), $module->displayName), 'title' => $module->displayName,
'desc' => sprintf($this->l('Choose a fixed fee for each order placed with %s.'), $module->displayName), 'desc' => sprintf($this->l('Choose a fixed fee for each order placed in %s with %s.'), $currency->iso_code, $module->displayName),
'validation' => 'isPrice', 'validation' => 'isPrice',
'cast' => 'floatval', 'cast' => 'floatval',
'type' => 'text', 'type' => 'text',
'default' => '0', 'default' => '0',
'suffix' => $currency->iso_code 'suffix' => $currency->iso_code
); );
$fields['CONF_'.strtoupper($module->name).'_VAR_FEE'] = array( $forms['payment']['fields']['CONF_'.strtoupper($module->name).'_VAR'] = array(
'title' => sprintf($this->l('Variable fee / %s'), $module->displayName), 'title' => $module->displayName,
'desc' => sprintf($this->l('Choose a variable fee for each order placed with %s. It will be applied on the total paid with taxes.'), $module->displayName), 'desc' => sprintf($this->l('Choose a variable fee for each order placed in %s with %s. It will be applied on the total paid with taxes.'), $currency->iso_code, $module->displayName),
'validation' => 'isPercentage', 'validation' => 'isPercentage',
'cast' => 'floatval', 'cast' => 'floatval',
'type' => 'text', 'type' => 'text',
'default' => '0', 'default' => '0',
'suffix' => '%' 'suffix' => '%'
); );
if (Currency::isMultiCurrencyActivated())
{
$forms['payment']['fields']['CONF_'.strtoupper($module->name).'_FIXED_FOREIGN'] = array(
'title' => $module->displayName,
'desc' => sprintf($this->l('Choose a fixed fee for each order placed with a foreign currency with %s.'), $module->displayName),
'validation' => 'isPrice',
'cast' => 'floatval',
'type' => 'text',
'default' => '0',
'suffix' => $currency->iso_code
);
$forms['payment']['fields']['CONF_'.strtoupper($module->name).'_VAR_FOREIGN'] = array(
'title' => $module->displayName,
'desc' => sprintf($this->l('Choose a variable fee for each order placed with a foreign currency with %s. It will be applied on the total paid with taxes.'), $module->displayName),
'validation' => 'isPercentage',
'cast' => 'floatval',
'type' => 'text',
'default' => '0',
'suffix' => '%'
);
}
} }
$fields['CONF_ORDER_FIXED_FEES'] = array(
'title' => $this->l('Other fixed fees'), foreach ($carriers as $carrier)
'desc' => $this->l('Other fixed fees applied to each order.'), {
'validation' => 'isPrice', $forms['carriers']['fields']['CONF_'.strtoupper($carrier['id_reference']).'_SHIP'] = array(
'cast' => 'floatval', 'title' => $carrier['name'],
'type' => 'text', 'desc' => sprintf($this->l('%% of what you charged the customer for domestic delivery with %s.'), $carrier['name']),
'default' => '0', 'validation' => 'isPercentage',
'suffix' => $currency->iso_code 'cast' => 'floatval',
); 'type' => 'text',
$fields['CONF_SHIPPING_MARGIN'] = array( 'default' => '0',
'title' => $this->l('Shipping Margin'), 'suffix' => '%'
'desc' => $this->l('Profit margin on your shipping fees.'), );
$forms['carriers']['fields']['CONF_'.strtoupper($carrier['id_reference']).'_SHIP_OVERSEAS'] = array(
'title' => $carrier['name'],
'desc' => sprintf($this->l('%% of what you charged the customer for overseas delivery with %s.'), $carrier['name']),
'validation' => 'isPercentage',
'cast' => 'floatval',
'type' => 'text',
'default' => '0',
'suffix' => '%'
);
}
$forms['other']['fields']['CONF_AVERAGE_PRODUCT_MARGIN'] = array(
'title' => $this->l('Average gross margin (Selling price / Buying price)'),
'desc' => $this->l('Only used if you do not specify your buying price for each product.'),
'validation' => 'isPercentage', 'validation' => 'isPercentage',
'cast' => 'floatval', 'cast' => 'intval',
'type' => 'text', 'type' => 'text',
'default' => '0', 'default' => '0',
'suffix' => '%' 'suffix' => '%'
); );
$fields['CONF_MONTHLY_FEES'] = array(
'title' => $this->l('Monthly fees'), $forms['other']['fields']['CONF_ORDER_FIXED'] = array(
'desc' => $this->l('Monthly fees like hosting, adwords, etc.'), 'title' => $this->l('Other fee per order'),
'validation' => 'isPrice',
'cast' => 'floatval',
'type' => 'text',
'default' => '0',
'suffix' => $currency->iso_code
);
$fields['CONF_YEARLY_FEES'] = array(
'title' => $this->l('Yearly fees'),
'desc' => $this->l('Yearly fees like hosting, subscriptions, etc.'),
'validation' => 'isPrice', 'validation' => 'isPrice',
'cast' => 'floatval', 'cast' => 'floatval',
'type' => 'text', 'type' => 'text',
@@ -126,14 +167,26 @@ class AdminDashboardControllerCore extends AdminController
'suffix' => $currency->iso_code 'suffix' => $currency->iso_code
); );
return array( $expense_types = array(
'profitability' => array( 'hosting' => $this->l('Hosting'),
'title' => $this->l('Profitability Configuration'), 'tools' => $this->l('Tools (E-mailing, etc.)'),
'icon' => 'tab-preferences', 'acounting' => $this->l('Accounting'),
'fields' => $fields, 'development' => $this->l('Development'),
'submit' => array('title' => $this->l('Save'), 'class' => 'button'), 'marketing' => $this->l('Marketing (Adwords, etc.)'),
), 'others' => $this->l('Others')
); );
foreach ($expense_types as $expense_type => $expense_label)
$forms['expenses']['fields']['CONF_MONTHLY_'.strtoupper($expense_type)] = array(
'title' => $expense_label,
'validation' => 'isPrice',
'cast' => 'floatval',
'type' => 'text',
'default' => '0',
'suffix' => $currency->iso_code
);
return $forms;
} }
public function renderView() public function renderView()
+36 -8
View File
@@ -324,27 +324,51 @@ class AdminStatsControllerCore extends AdminStatsTabController
public static function getExpenses($date_from, $date_to) public static function getExpenses($date_from, $date_to)
{ {
$secs_per_year = 365.25 * 86400;
$secs_per_month = 30.4375 * 86400; $secs_per_month = 30.4375 * 86400;
$total_secs = (strtotime($date_to) - min(strtotime($date_from), time())) / 86400; $total_secs = (strtotime($date_to) - min(strtotime($date_from), time())) / 86400;
$expenses = Configuration::get('CONF_MONTHLY_FEES') * $total_secs / $secs_per_month + Configuration::get('CONF_YEARLY_FEES') * $total_secs / $secs_per_year; $expenses =
Configuration::get('CONF_MONTHLY_ACOUNTING')
+ Configuration::get('CONF_MONTHLY_DEVELOPMENT')
+ Configuration::get('CONF_MONTHLY_HOSTING')
+ Configuration::get('CONF_MONTHLY_MARKETING')
+ Configuration::get('CONF_MONTHLY_OTHERS')
+ Configuration::get('CONF_MONTHLY_TOOLS');
$expenses *= $total_secs / $secs_per_month;
$orders = Db::getInstance()->ExecuteS(' $orders = Db::getInstance()->ExecuteS('
SELECT SELECT
total_paid_tax_incl / o.conversion_rate as total_paid_tax_incl, total_paid_tax_incl / o.conversion_rate as total_paid_tax_incl,
total_shipping_tax_excl / o.conversion_rate as total_shipping_tax_excl, total_shipping_tax_excl / o.conversion_rate as total_shipping_tax_excl,
module o.module,
a.id_country,
o.id_currency,
c.id_reference as carrier_reference
FROM `'._DB_PREFIX_.'orders` o FROM `'._DB_PREFIX_.'orders` o
LEFT JOIN `'._DB_PREFIX_.'address` a ON o.id_address_delivery = a.id_address
LEFT JOIN `'._DB_PREFIX_.'carrier` c ON o.id_carrier = c.id_carrier
WHERE `invoice_date` BETWEEN "'.pSQL($date_from).' 00:00:00" AND "'.pSQL($date_to).' 23:59:59" WHERE `invoice_date` BETWEEN "'.pSQL($date_from).' 00:00:00" AND "'.pSQL($date_to).' 23:59:59"
'.Shop::addSqlRestriction(false, 'o')); '.Shop::addSqlRestriction(false, 'o'));
foreach ($orders as $order) foreach ($orders as $order)
{ {
// Add flat fees for this order // Add flat fees for this order
$expenses += Configuration::get('CONF_ORDER_FIXED_FEES') + Configuration::get('CONF_'.strtoupper($order['module']).'_FIXED_FEE'); $expenses += Configuration::get('CONF_ORDER_FIXED') + (
$order['id_currency'] == Configuration::get('PS_DEFAULT_CURRENCY')
? Configuration::get('CONF_'.strtoupper($order['module']).'_FIXED')
: Configuration::get('CONF_'.strtoupper($order['module']).'_FIXED_FOREIGN')
);
// Add variable fees for this order // Add variable fees for this order
$expenses += $order['total_paid_tax_incl'] * (Configuration::get('CONF_ORDER_VAR_FEES') + Configuration::get('CONF_'.strtoupper($order['module']).'_VAR_FEE')) / 100; $expenses += $order['total_paid_tax_incl'] * (
$order['id_currency'] == Configuration::get('PS_DEFAULT_CURRENCY')
? Configuration::get('CONF_'.strtoupper($order['module']).'_VAR')
: Configuration::get('CONF_'.strtoupper($order['module']).'_VAR_FOREIGN')
) / 100;
// Add shipping fees for this order // Add shipping fees for this order
$expenses += $order['total_shipping_tax_excl'] * (100 - Configuration::get('CONF_SHIPPING_MARGIN')) / 100; //
$expenses += $order['total_shipping_tax_excl'] * (
$order['id_country'] == Configuration::get('PS_DEFAULT_COUNTRY')
? Configuration::get('CONF_'.strtoupper($order['carrier_reference']).'_SHIP')
: Configuration::get('CONF_'.strtoupper($order['carrier_reference']).'_SHIP_OVERSEAS')
) / 100;
} }
return $expenses; return $expenses;
} }
@@ -574,13 +598,17 @@ class AdminStatsControllerCore extends AdminStatsTabController
break; break;
case 'netprofit_visitor': case 'netprofit_visitor':
$date_from = date('Y-m-d', strtotime('-31 day')); $date_from = date('Y-m-d', strtotime('-131 day'));
$date_to = date('Y-m-d', strtotime('-1 day')); $date_to = date('Y-m-d', strtotime('-1 day'));
$total_visitors = AdminStatsController::getUniqueVisitors($date_from, $date_to); $total_visitors = AdminStatsController::getUniqueVisitors($date_from, $date_to);
$total_sales = AdminStatsController::getTotalSales($date_from, $date_to); $total_sales = AdminStatsController::getTotalSales($date_from, $date_to);
$total_expenses = AdminStatsController::getExpenses($date_from, $date_to); $total_expenses = AdminStatsController::getExpenses($date_from, $date_to);
$total_purchases = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue(' $total_purchases = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
SELECT SUM(od.`product_quantity` * od.`purchase_supplier_price` / `conversion_rate`) as total_purchase_price SELECT SUM(od.`product_quantity` * IF(
od.`purchase_supplier_price` > 0,
od.`purchase_supplier_price` / `conversion_rate`,
od.`original_product_price` * '.(int)Configuration::get('CONF_AVERAGE_PRODUCT_MARGIN').' / 100
)) as total_purchase_price
FROM `'._DB_PREFIX_.'orders` o FROM `'._DB_PREFIX_.'orders` o
LEFT JOIN `'._DB_PREFIX_.'order_detail` od ON o.id_order = od.id_order LEFT JOIN `'._DB_PREFIX_.'order_detail` od ON o.id_order = od.id_order
WHERE `invoice_date` BETWEEN "'.pSQL($date_from).' 00:00:00" AND "'.pSQL($date_to).' 23:59:59" WHERE `invoice_date` BETWEEN "'.pSQL($date_from).' 00:00:00" AND "'.pSQL($date_to).' 23:59:59"