diff --git a/Controller/BackendController.php b/Controller/BackendController.php index 57a311f..7489e74 100755 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -19,6 +19,7 @@ use Modules\SalesAnalysis\Models\ClientMapper; use Modules\SalesAnalysis\Models\GeneralMapper; use Modules\SalesAnalysis\Models\ItemMapper; use Modules\SalesAnalysis\Models\RegionMapper; +use Modules\SalesAnalysis\Models\SalesRepMapper; use phpOMS\Asset\AssetType; use phpOMS\Contract\RenderableInterface; use phpOMS\Localization\ISO3166CharEnum; @@ -37,6 +38,12 @@ use phpOMS\Views\View; * @license OMS License 1.0 * @link https://jingga.app * @since 1.0.0 + * + * @feature Create a map of sales (maybe as data points or as heat maps) + * https://github.com/Karaka-Management/oms-ClientManagement/issues/14 + * + * @feature Create a map of all customers (maybe as data points or as heat maps) + * https://github.com/Karaka-Management/oms-ClientManagement/issues/15 */ final class BackendController extends Controller { @@ -348,7 +355,7 @@ final class BackendController extends Controller * @since 1.0.0 * @codeCoverageIgnore */ - public function viewBillAnalysis(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface + public function viewSalesRepAnalysis(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface { $head = $response->data['Content']->head; $nonce = $this->app->appSettings->getOption('script-nonce'); @@ -358,9 +365,79 @@ final class BackendController extends Controller $head->addAsset(AssetType::JSLATE, 'Modules/SalesAnalysis/Controller/Controller.js?v=' . self::VERSION, ['nonce' => $nonce, 'type' => 'module']); $view = new View($this->app->l11nManager, $request, $response); - $view->setTemplate('/Modules/SalesAnalysis/Theme/Backend/analysis-bill'); + $view->setTemplate('/Modules/SalesAnalysis/Theme/Backend/analysis-rep'); $view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1005401001, $request, $response); + $businessStart = 1; + $startOfYear = SmartDateTime::createFromDateTime(SmartDateTime::startOfYear($businessStart)); + $startCurrent = $request->getDataDateTime('startcurrent') ?? clone $startOfYear; + $endCurrent = $request->getDataDateTime('endcurrent') ?? SmartDateTime::endOfMonth(); + $endCurrentIndex = SmartDateTime::calculateMonthIndex((int) $endCurrent->format('m'), $businessStart); + $startComparison = $request->getDataDateTime('startcomparison') ?? SmartDateTime::createFromDateTime($startCurrent)->createModify(-1); + $endComparison = $request->getDataDateTime('endcomparison') ?? SmartDateTime::createFromDateTime(SmartDateTime::endOfYear($businessStart))->smartModify(-1); + $historyStart = $startOfYear->createModify(-9); + + $view->data['startCurrent'] = $startCurrent; + $view->data['endCurrent'] = $endCurrent; + $view->data['startComparison'] = $startComparison; + $view->data['endComparison'] = $endComparison; + $view->data['historyStart'] = $historyStart; + + $domestic = UnitMapper::get() + ->with('mainAddress') + ->where('id', $this->app->unitId) + ->execute(); + + [ + $mtdCurrent, + $ytdCurrent, + $monthlyCurrent + ] = SalesRepMapper::monthlySalesProfit( + $startCurrent, + $endCurrent, + $businessStart + ); + + [ + $mtdPY, + $ytdPY, + $monthlyPY + ] = SalesRepMapper::monthlySalesProfit( + $startComparison, + $endComparison, + $businessStart + ); + + [ + $view->data['mtdPYClientRep'], + $view->data['mtdAClientRep'], + $view->data['ytdPYClientRep'], + $view->data['ytdAClientRep'], + ] = SalesRepMapper::mtdYtdRep( + $startCurrent, + $endCurrent, + $startComparison, + $endComparison, + $businessStart + ); + + $annualRepSales = SalesRepMapper::salesProfitRep($historyStart, $startCurrent, $startCurrent, $endCurrent); + + [ + $view->data['mtdPYClientRepCount'], + $view->data['mtdAClientRepCount'], + $view->data['ytdPYClientRepCount'], + $view->data['ytdAClientRepCount'], + ] = SalesRepMapper::mtdYtdClientRep( + $startCurrent, + $endCurrent, + $startComparison, + $endComparison, + $businessStart + ); + + $annualRepCount = SalesRepMapper::annualCustomerRep(clone $historyStart, $endCurrent); + return $view; } @@ -376,7 +453,7 @@ final class BackendController extends Controller * @since 1.0.0 * @codeCoverageIgnore */ - public function viewSalesRepAnalysis(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface + public function viewBillAnalysis(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface { $head = $response->data['Content']->head; $nonce = $this->app->appSettings->getOption('script-nonce'); @@ -386,65 +463,9 @@ final class BackendController extends Controller $head->addAsset(AssetType::JSLATE, 'Modules/SalesAnalysis/Controller/Controller.js?v=' . self::VERSION, ['nonce' => $nonce, 'type' => 'module']); $view = new View($this->app->l11nManager, $request, $response); - $view->setTemplate('/Modules/SalesAnalysis/Theme/Backend/analysis-rep'); + $view->setTemplate('/Modules/SalesAnalysis/Theme/Backend/analysis-bill'); $view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1005401001, $request, $response); - ///// - $currentCustomerRegion = [ - 'Europe' => (int) (\mt_rand(200, 400) / 4), - 'America' => (int) (\mt_rand(200, 400) / 4), - 'Asia' => (int) (\mt_rand(200, 400) / 4), - 'Africa' => (int) (\mt_rand(200, 400) / 4), - 'CIS' => (int) (\mt_rand(200, 400) / 4), - 'Other' => (int) (\mt_rand(200, 400) / 4), - ]; - - $view->data['currentCustomerRegion'] = $currentCustomerRegion; - - $annualCustomerRegion = []; - for ($i = 1; $i < 11; ++$i) { - $annualCustomerRegion[] = [ - 'year' => 2020 - 10 + $i, - 'Europe' => $a = (int) (\mt_rand(200, 400) / 4), - 'America' => $b = (int) (\mt_rand(200, 400) / 4), - 'Asia' => $c = (int) (\mt_rand(200, 400) / 4), - 'Africa' => $d = (int) (\mt_rand(200, 400) / 4), - 'CIS' => $e = (int) (\mt_rand(200, 400) / 4), - 'Other' => $f = (int) (\mt_rand(200, 400) / 4), - 'Total' => $a + $b + $c + $d + $e + $f, - ]; - } - - $view->data['annualCustomerRegion'] = $annualCustomerRegion; - - ///// - $currentCustomersRep = []; - for ($i = 1; $i < 13; ++$i) { - $currentCustomersRep['Rep ' . $i] = [ - 'customers' => (int) (\mt_rand(200, 400) / 12), - ]; - } - - \uasort($currentCustomersRep, function($a, $b) { - return $b['customers'] <=> $a['customers']; - }); - - $view->data['currentCustomersRep'] = $currentCustomersRep; - - $annualCustomersRep = []; - for ($i = 1; $i < 13; ++$i) { - $annualCustomersRep['Rep ' . $i] = []; - - for ($j = 1; $j < 11; ++$j) { - $annualCustomersRep['Rep ' . $i][] = [ - 'customers' => (int) (\mt_rand(200, 400) / 12), - 'year' => 2020 - 10 + $j, - ]; - } - } - - $view->data['annualCustomersRep'] = $annualCustomersRep; - return $view; } diff --git a/Models/ClientMapper.php b/Models/ClientMapper.php index 9f34ca0..fbaa5bd 100755 --- a/Models/ClientMapper.php +++ b/Models/ClientMapper.php @@ -53,8 +53,8 @@ class ClientMapper extends DataMapperFactory clientmgmt_attr_value_l11n_title, YEAR(billing_bill_performance_date) as salesyear, MONTH(billing_bill_performance_date) as salesmonth, - SUM(billing_bill_netsales * billing_type_transfer_sign) as netsales, - SUM(billing_bill_netprofit * billing_type_transfer_sign) as netprofit + SUM(billing_bill_netsales * billing_type_sign) as netsales, + SUM(billing_bill_netprofit * billing_type_sign) as netprofit FROM billing_bill LEFT JOIN billing_type ON billing_bill_type = billing_type_id diff --git a/Models/GeneralMapper.php b/Models/GeneralMapper.php index 1213af3..1745ac4 100755 --- a/Models/GeneralMapper.php +++ b/Models/GeneralMapper.php @@ -47,8 +47,8 @@ class GeneralMapper extends DataMapperFactory 'SELECT YEAR(billing_bill_performance_date) as salesyear, MONTH(billing_bill_performance_date) as salesmonth, - SUM(billing_bill_netsales * billing_type_transfer_sign) as netsales, - SUM(billing_bill_netprofit * billing_type_transfer_sign) as netprofit + SUM(billing_bill_netsales * billing_type_sign) as netsales, + SUM(billing_bill_netprofit * billing_type_sign) as netprofit FROM billing_bill LEFT JOIN billing_type ON billing_bill_type = billing_type_id @@ -143,8 +143,8 @@ class GeneralMapper extends DataMapperFactory 'SELECT YEAR(billing_bill_performance_date) as salesyear, MONTH(billing_bill_performance_date) as salesmonth, - SUM(billing_bill_netsales * billing_type_transfer_sign) as netsales, - SUM(billing_bill_netprofit * billing_type_transfer_sign) as netprofit + SUM(billing_bill_netsales * billing_type_sign) as netsales, + SUM(billing_bill_netprofit * billing_type_sign) as netprofit FROM billing_bill LEFT JOIN billing_type ON billing_bill_type = billing_type_id diff --git a/Models/ItemMapper.php b/Models/ItemMapper.php index c861d4d..7f6ddb9 100755 --- a/Models/ItemMapper.php +++ b/Models/ItemMapper.php @@ -53,8 +53,8 @@ class ItemMapper extends DataMapperFactory itemmgmt_attr_value_l11n_title, YEAR(billing_bill_performance_date) as salesyear, MONTH(billing_bill_performance_date) as salesmonth, - SUM(billing_bill_element_total_netsalesprice * billing_type_transfer_sign) as netsales, - SUM(billing_bill_element_total_netprofit * billing_type_transfer_sign) as netprofit + SUM(billing_bill_element_total_netsalesprice * billing_type_sign) as netsales, + SUM(billing_bill_element_total_netprofit * billing_type_sign) as netprofit FROM billing_bill LEFT JOIN billing_type ON billing_bill_type = billing_type_id diff --git a/Models/RegionMapper.php b/Models/RegionMapper.php index 7eb0589..796855b 100755 --- a/Models/RegionMapper.php +++ b/Models/RegionMapper.php @@ -50,8 +50,8 @@ class RegionMapper extends DataMapperFactory address_country, YEAR(billing_bill_performance_date) as salesyear, MONTH(billing_bill_performance_date) as salesmonth, - SUM(billing_bill_netsales * billing_type_transfer_sign) as netsales, - SUM(billing_bill_netprofit * billing_type_transfer_sign) as netprofit + SUM(billing_bill_netsales * billing_type_sign) as netsales, + SUM(billing_bill_netprofit * billing_type_sign) as netprofit FROM billing_bill LEFT JOIN billing_type ON billing_bill_type = billing_type_id @@ -327,8 +327,8 @@ class RegionMapper extends DataMapperFactory address_country, YEAR(billing_bill_performance_date) as salesyear, MONTH(billing_bill_performance_date) as salesmonth, - SUM(billing_bill_netsales * billing_type_transfer_sign) as netsales, - SUM(billing_bill_netprofit * billing_type_transfer_sign) as netprofit + SUM(billing_bill_netsales * billing_type_sign) as netsales, + SUM(billing_bill_netprofit * billing_type_sign) as netprofit FROM billing_bill LEFT JOIN billing_type ON billing_bill_type = billing_type_id @@ -394,8 +394,8 @@ class RegionMapper extends DataMapperFactory address_country, YEAR(billing_bill_performance_date) as salesyear, MONTH(billing_bill_performance_date) as salesmonth, - SUM(billing_bill_netsales * billing_type_transfer_sign) as netsales, - SUM(billing_bill_netprofit * billing_type_transfer_sign) as netprofit + SUM(billing_bill_netsales * billing_type_sign) as netsales, + SUM(billing_bill_netprofit * billing_type_sign) as netprofit FROM billing_bill LEFT JOIN billing_type ON billing_bill_type = billing_type_id diff --git a/Models/SalesRepMapper.php b/Models/SalesRepMapper.php new file mode 100755 index 0000000..d2a2f19 --- /dev/null +++ b/Models/SalesRepMapper.php @@ -0,0 +1,490 @@ +format('m'), $businessStart); + + $query = new Builder(self::$db); + $query->raw( + 'SELECT + billing_bill_rep, + YEAR(billing_bill_performance_date) as salesyear, + MONTH(billing_bill_performance_date) as salesmonth, + SUM(billing_bill_netsales * billing_type_sign) as netsales, + SUM(billing_bill_netprofit * billing_type_sign) as netprofit + FROM billing_bill + LEFT JOIN billing_type + ON billing_bill_type = billing_type_id + LEFT JOIN clientmgmt_client + ON clientmgmt_client_id = billing_bill_client + LEFT JOIN address + ON clientmgmt_client_address = address_id + WHERE + billing_type_transfer_type = ' . BillTransferType::SALES . ' + AND billing_type_accounting = 1 + AND billing_bill_performance_date >= \'' . $start->format('Y-m-d') . '\' + AND billing_bill_performance_date <= \'' . $end->format('Y-m-d') . '\' + GROUP BY + billing_bill_rep, + YEAR(billing_bill_performance_date), + MONTH(billing_bill_performance_date) + ORDER BY + YEAR(billing_bill_performance_date) ASC, + MONTH(billing_bill_performance_date) ASC, + billing_bill_rep' + ); + + $results = $query->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; + + $monthlySales = []; + + $mtd = []; + $ytd = []; + + foreach ($results as $result) { + $monthIndex = SmartDateTime::calculateMonthIndex((int) $result['salesmonth'], $businessStart); + + if (!isset($monthlySales[$result['billing_bill_rep']])) { + $monthlySales[$result['billing_bill_rep']] = []; + + $mtdA[$result['billing_bill_rep']] = ['net_sales' => 0, 'net_profit' => 0]; + $mtdPY[$result['billing_bill_rep']] = ['net_sales' => 0, 'net_profit' => 0]; + + $ytdA[$result['billing_bill_rep']] = ['net_sales' => 0, 'net_profit' => 0]; + $ytdPY[$result['billing_bill_rep']] = ['net_sales' => 0, 'net_profit' => 0]; + + for ($i = 1; $i < 3; ++$i) { + $monthlySales[$result['billing_bill_rep']][$i] = \array_fill(1, 12, [ + 'net_sales' => null, + 'net_profit' => null, + ]); + } + } + + // indexed according to the fiscal year + $monthlySales[$result['billing_bill_rep']][$monthIndex] = [ + 'net_sales' => (int) $result['netsales'], + 'net_profit' => (int) $result['netprofit'], + ]; + + if ($monthIndex === $endCurrentIndex) { + $mtd[$result['billing_bill_rep']] = $monthlySales[$result['billing_bill_rep']][$monthIndex]; + } + + if ($monthIndex <= $endCurrentIndex) { + $ytd[$result['billing_bill_rep']]['net_sales'] += $monthlySales[$result['billing_bill_rep']][$monthIndex]['net_sales']; + $ytd[$result['billing_bill_rep']]['net_profit'] += $monthlySales[$result['billing_bill_rep']][$monthIndex]['net_profit']; + } + } + + return [$mtd, $ytd, $monthlySales]; + } + + /** + * @todo Re-implement, still in use? + */ + public static function annualCustomerRep( + SmartDateTime $historyStart, + \DateTime $endCurrent, + int $businessStart = 1 + ) : array { + $query = new Builder(self::$db); + $query->raw( + 'SELECT + billing_bill_rep, + YEAR(billing_bill_performance_date) as salesyear, + MONTH(billing_bill_performance_date) as salesmonth, + COUNT(billing_bill_netsales) as client_count + FROM billing_bill + LEFT JOIN billing_type + ON billing_bill_type = billing_type_id + LEFT JOIN clientmgmt_client + ON clientmgmt_client_id = billing_bill_client + LEFT JOIN address + ON clientmgmt_client_address = address_id + WHERE + billing_type_transfer_type = ' . BillTransferType::SALES . ' + AND billing_type_accounting = 1 + AND billing_bill_performance_date >= \'' . $historyStart->format('Y-m-d') . '\' + AND billing_bill_performance_date <= \'' . $endCurrent->format('Y-m-d') . '\' + GROUP BY + billing_bill_rep, + YEAR(billing_bill_performance_date), + MONTH(billing_bill_performance_date) + ORDER BY + YEAR(billing_bill_performance_date) ASC, + MONTH(billing_bill_performance_date) ASC, + billing_bill_rep' + ); + + $results = $query->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; + + $annualCustomer = []; + + $oldIndex = 1; + // @todo this calculation doesn't consider the start of the fiscal year + $period = (int) (((((int) $results[0]['salesyear']) - ((int) $historyStart->format('Y'))) * 12 + - ((int) $results[0]['salesmonth']) + ((int) $historyStart->format('m'))) / 12 + 1); + + foreach ($results as $result) { + $monthIndex = SmartDateTime::calculateMonthIndex((int) $result['salesmonth'], $businessStart); + if ($monthIndex < $oldIndex) { + $oldIndex = $monthIndex; + + ++$period; + } + + if ($period > 10) { + break; + } + + $oldIndex = $monthIndex; + + if (!isset($annualCustomer[$result['billing_bill_rep']])) { + for ($i = 1; $i < 11; ++$i) { + $annualCustomer[$result['billing_bill_rep']][$i] = [ + 'client_count' => 0, + ]; + + $historyStart->smartModify(1); + } + + $historyStart->smartModify(-10); + } + + // indexed according to the fiscal year + $annualCustomer[$result['billing_bill_rep']][$period]['client_count'] += (int) $result['client_count']; + } + + return $annualCustomer; + } + + /** + * @todo Re-implement, still in use? + */ + public static function mtdYtdClientRep( + \DateTime $startCurrent, + \DateTime $endCurrent, + \DateTime $startComparison, + \DateTime $endComparison, + int $businessStart = 1, + ) : array { + // @todo this cannot be correct since the same customer may buy something in two month (distinct is required over an actual period) + $endCurrentIndex = SmartDateTime::calculateMonthIndex((int) $endCurrent->format('m'), $businessStart); + + $query = new Builder(self::$db); + $query->raw( + 'SELECT + billing_bill_rep, + YEAR(billing_bill_performance_date) as salesyear, + MONTH(billing_bill_performance_date) as salesmonth, + COUNT(billing_bill_netsales) as client_count + FROM billing_bill + LEFT JOIN billing_type + ON billing_bill_type = billing_type_id + LEFT JOIN clientmgmt_client + ON clientmgmt_client_id = billing_bill_client + LEFT JOIN address + ON clientmgmt_client_address = address_id + WHERE + billing_type_transfer_type = ' . BillTransferType::SALES . ' + AND billing_type_accounting = 1 + AND billing_bill_performance_date >= \'' . $startComparison->format('Y-m-d') . '\' + AND billing_bill_performance_date <= \'' . $endCurrent->format('Y-m-d') . '\' + GROUP BY + billing_bill_rep, + YEAR(billing_bill_performance_date), + MONTH(billing_bill_performance_date) + ORDER BY + YEAR(billing_bill_performance_date) ASC, + MONTH(billing_bill_performance_date) ASC, + billing_bill_rep ASC' + ); + + $results = $query->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; + + $oldIndex = 1; + $period = 1; + + $mtdAClientCountry = []; + $mtdPYClientCountry = []; + + $ytdAClientCountry = []; + $ytdPYClientCountry = []; + + foreach ($results as $result) { + $monthIndex = SmartDateTime::calculateMonthIndex((int) $result['salesmonth'], $businessStart); + if ($monthIndex < $oldIndex) { + $oldIndex = $monthIndex; + + ++$period; + } + + if ($period > 2) { + break; + } + + $oldIndex = $monthIndex; + + // indexed according to the fiscal year + $temp = [ + 'client_count' => (int) $result['client_count'], + ]; + + if ($temp['client_count'] === 0) { + continue; + } + + if ($monthIndex === $endCurrentIndex) { + if ($period === 1) { + $mtdPYClientCountry[$result['billing_bill_rep']] = $temp; + } else { + $mtdAClientCountry[$result['billing_bill_rep']] = $temp; + } + } + + if ($monthIndex <= $endCurrentIndex) { + if (!isset($ytdPYClientCountry[$result['billing_bill_rep']])) { + $ytdPYClientCountry[$result['billing_bill_rep']] = [ + 'client_count' => 0, + ]; + + $ytdAClientCountry[$result['billing_bill_rep']] = [ + 'client_count' => 0, + ]; + } + + if ($period === 1) { + $ytdPYClientCountry[$result['billing_bill_rep']]['client_count'] += $temp['client_count']; + } else { + $ytdAClientCountry[$result['billing_bill_rep']]['client_count'] += $temp['client_count']; + } + } + } + + return [ + $mtdPYClientCountry, + $mtdAClientCountry, + $ytdPYClientCountry, + $ytdAClientCountry, + ]; + } + + // @todo remove businessStart, that should be baked into the historyStart + // Explanation: in the past I had to compare periods which weren't even business years!!! + /** + * @todo Re-implement, still in use? + */ + public static function salesProfitRep( + \DateTime $historyStart, + \DateTime $historyEnd, + \DateTime $currentStart, + \DateTime $currentEnd + ) : array { + $query = new Builder(self::$db); + $query->raw( + 'SELECT + billing_bill_rep, + YEAR(billing_bill_performance_date) as salesyear, + MONTH(billing_bill_performance_date) as salesmonth, + SUM(billing_bill_netsales * billing_type_sign) as netsales, + SUM(billing_bill_netprofit * billing_type_sign) as netprofit + FROM billing_bill + LEFT JOIN billing_type + ON billing_bill_type = billing_type_id + LEFT JOIN clientmgmt_client + ON clientmgmt_client_id = billing_bill_client + LEFT JOIN address + ON clientmgmt_client_address = address_id + WHERE + billing_type_transfer_type = ' . BillTransferType::SALES . ' + AND billing_type_accounting = 1 + AND billing_bill_performance_date >= \'' . $historyStart->format('Y-m-d') . '\' + AND billing_bill_performance_date <= \'' . $currentEnd->format('Y-m-d') . '\' + GROUP BY + billing_bill_rep, + YEAR(billing_bill_performance_date), + MONTH(billing_bill_performance_date) + ORDER BY + YEAR(billing_bill_performance_date) ASC, + MONTH(billing_bill_performance_date) ASC, + billing_bill_rep ASC' + ); + + $results = $query->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; + + $sales = []; + $period = 0; + + foreach ($results as $result) { + // @todo Handle fiscal year + $period = $result['salesyear'] - ((int) $historyStart->format('Y')) + 1; + if (!isset($sales[$result['billing_bill_rep']])) { + for ($i = 1; $i < 11; ++$i) { + $sales[$result['billing_bill_rep']][$i] = [ + 'net_sales' => 0, + 'net_profit' => 0, + 'year' => $period === 0 ? 'PY' : 'A', + ]; + } + } + + $sales[$result['billing_bill_rep']][$period]['net_sales'] += (int) $result['netsales']; + $sales[$result['billing_bill_rep']][$period]['net_profit'] += (int) $result['netprofit']; + } + + return $sales; + } + + /** + * @todo Re-implement, still in use? + */ + public static function mtdYtdRep( + \DateTime $startCurrent, + \DateTime $endCurrent, + \DateTime $startComparison, + \DateTime $endComparison, + int $businessStart = 1, + ) : array { + $endCurrentIndex = SmartDateTime::calculateMonthIndex((int) $endCurrent->format('m'), $businessStart); + + $query = new Builder(self::$db); + $query->raw( + 'SELECT + billing_bill_rep, + YEAR(billing_bill_performance_date) as salesyear, + MONTH(billing_bill_performance_date) as salesmonth, + SUM(billing_bill_netsales * billing_type_sign) as netsales, + SUM(billing_bill_netprofit * billing_type_sign) as netprofit + FROM billing_bill + LEFT JOIN billing_type + ON billing_bill_type = billing_type_id + LEFT JOIN clientmgmt_client + ON clientmgmt_client_id = billing_bill_client + LEFT JOIN address + ON clientmgmt_client_address = address_id + WHERE + billing_type_transfer_type = ' . BillTransferType::SALES . ' + AND billing_type_accounting = 1 + AND billing_bill_performance_date >= \'' . $startComparison->format('Y-m-d') . '\' + AND billing_bill_performance_date <= \'' . $endCurrent->format('Y-m-d') . '\' + GROUP BY + billing_bill_rep, + YEAR(billing_bill_performance_date), + MONTH(billing_bill_performance_date) + ORDER BY + YEAR(billing_bill_performance_date) ASC, + MONTH(billing_bill_performance_date) ASC, + billing_bill_rep ASC' + ); + + $results = $query->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; + + $oldIndex = 1; + $period = 1; + + $mtdAClientCountry = []; + $mtdPYClientCountry = []; + + $ytdAClientCountry = []; + $ytdPYClientCountry = []; + + foreach ($results as $result) { + $monthIndex = SmartDateTime::calculateMonthIndex((int) $result['salesmonth'], $businessStart); + if ($monthIndex < $oldIndex) { + $oldIndex = $monthIndex; + + ++$period; + } + + if ($period > 2) { + break; + } + + $oldIndex = $monthIndex; + + // indexed according to the fiscal year + $temp = [ + 'net_sales' => (int) $result['netsales'], + 'net_profit' => (int) $result['netprofit'], + ]; + + if (($temp['net_sales'] === 0 && $temp['net_profit'] === 0)) { + continue; + } + + if ($monthIndex === $endCurrentIndex) { + if ($period === 1) { + $mtdPYClientCountry[$result['billing_bill_rep']] = $temp; + } else { + $mtdAClientCountry[$result['billing_bill_rep']] = $temp; + } + } + + if ($monthIndex <= $endCurrentIndex) { + if (!isset($ytdPYClientCountry[$result['billing_bill_rep']])) { + $ytdPYClientCountry[$result['billing_bill_rep']] = [ + 'net_sales' => 0, + 'net_profit' => 0, + ]; + + $ytdAClientCountry[$result['billing_bill_rep']] = [ + 'net_sales' => 0, + 'net_profit' => 0, + ]; + } + + if ($period === 1) { + $ytdPYClientCountry[$result['billing_bill_rep']]['net_sales'] += $temp['net_sales']; + $ytdPYClientCountry[$result['billing_bill_rep']]['net_profit'] += $temp['net_profit']; + } else { + $ytdAClientCountry[$result['billing_bill_rep']]['net_sales'] += $temp['net_sales']; + $ytdAClientCountry[$result['billing_bill_rep']]['net_profit'] += $temp['net_profit']; + } + } + } + + return [ + $mtdPYClientCountry, + $mtdAClientCountry, + $ytdPYClientCountry, + $ytdAClientCountry, + ]; + } +} diff --git a/Theme/Backend/Lang/de.lang.php b/Theme/Backend/Lang/de.lang.php index fc5354b..2971838 100755 --- a/Theme/Backend/Lang/de.lang.php +++ b/Theme/Backend/Lang/de.lang.php @@ -68,4 +68,6 @@ return ['SalesAnalysis' => [ 'America' => 'Amerika', 'Oceania' => 'Ozeanien', 'Africa' => 'Afrika', + 'SalesRep' => 'Verkäufer', + 'SalesReps' => 'Verkäufer', ]]; diff --git a/Theme/Backend/Lang/en.lang.php b/Theme/Backend/Lang/en.lang.php index 3fde187..e463f22 100755 --- a/Theme/Backend/Lang/en.lang.php +++ b/Theme/Backend/Lang/en.lang.php @@ -68,4 +68,6 @@ return ['SalesAnalysis' => [ 'America' => 'America', 'Oceania' => 'Oceania', 'Africa' => 'Africa', + 'SalesRep' => 'SalesRep', + 'SalesReps' => 'SalesReps', ]]; diff --git a/Theme/Backend/analysis-rep.tpl.php b/Theme/Backend/analysis-rep.tpl.php index 8b8d0bf..cd59d3c 100755 --- a/Theme/Backend/analysis-rep.tpl.php +++ b/Theme/Backend/analysis-rep.tpl.php @@ -12,6 +12,10 @@ */ declare(strict_types=1); +use phpOMS\Localization\ISO3166CharEnum; +use phpOMS\Localization\ISO3166NameEnum; +use phpOMS\Stdlib\Base\FloatInt; + /** * @var \phpOMS\Views\View $this */ @@ -21,13 +25,1414 @@ echo $this->data['nav']->render();