format('m'), $businessStart); $query = new Builder(self::$db); $query->raw( 'SELECT address_country, YEAR(billing_bill_performance_date) as salesyear, MONTH(billing_bill_performance_date) as salesmonth, SUM(billing_bill_netsales) as netsales, SUM(billing_bill_netprofit) as netprofit FROM billing_bill LEFT JOIN clientmgmt_client ON clientmgmt_client_id = billing_bill_client LEFT JOIN address ON clientmgmt_client_address = address_id WHERE billing_bill_performance_date >= \'' . $start->format('Y-m-d') . '\' AND billing_bill_performance_date <= \'' . $end->format('Y-m-d') . '\' GROUP BY address_country, YEAR(billing_bill_performance_date), MONTH(billing_bill_performance_date) ORDER BY YEAR(billing_bill_performance_date) ASC, MONTH(billing_bill_performance_date) ASC, address_country' ); $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['address_country']])) { $monthlySales[$result['address_country']] = []; $mtdA[$result['address_country']] = ['net_sales' => 0, 'net_profit' => 0]; $mtdPY[$result['address_country']] = ['net_sales' => 0, 'net_profit' => 0]; $ytdA[$result['address_country']] = ['net_sales' => 0, 'net_profit' => 0]; $ytdPY[$result['address_country']] = ['net_sales' => 0, 'net_profit' => 0]; for ($i = 1; $i < 3; ++$i) { $monthlySales[$result['address_country']][$i] = \array_fill(1, 12, [ 'net_sales' => null, 'net_profit' => null, ]); } } // indexed according to the fiscal year $monthlySales[$result['address_country']][$monthIndex] = [ 'net_sales' => (int) $result['netsales'], 'net_profit' => (int) $result['netprofit'], ]; if ($monthIndex === $endCurrentIndex) { $mtd[$result['address_country']] = $monthlySales[$result['address_country']][$monthIndex]; } if ($monthIndex <= $endCurrentIndex) { $ytd[$result['address_country']]['net_sales'] += $monthlySales[$result['address_country']][$monthIndex]['net_sales']; $ytd[$result['address_country']]['net_profit'] += $monthlySales[$result['address_country']][$monthIndex]['net_profit']; } } return [$mtd, $ytd, $monthlySales]; } public static function annualCustomerCountry( SmartDateTime $historyStart, \DateTime $endCurrent, int $businessStart = 1 ) : array { $query = new Builder(self::$db); $query->raw( 'SELECT address_country, 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 clientmgmt_client ON clientmgmt_client_id = billing_bill_client LEFT JOIN address ON clientmgmt_client_address = address_id WHERE billing_bill_performance_date >= \'' . $historyStart->format('Y-m-d') . '\' AND billing_bill_performance_date <= \'' . $endCurrent->format('Y-m-d') . '\' GROUP BY address_country, YEAR(billing_bill_performance_date), MONTH(billing_bill_performance_date) ORDER BY YEAR(billing_bill_performance_date) ASC, MONTH(billing_bill_performance_date) ASC, address_country' ); $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['address_country']])) { for ($i = 1; $i < 11; ++$i) { $annualCustomer[$result['address_country']][$i] = [ 'client_count' => 0 ]; $historyStart->smartModify(1); } $historyStart->smartModify(-10); } // indexed according to the fiscal year $annualCustomer[$result['address_country']][$period]['client_count'] += (int) $result['client_count']; } return $annualCustomer; } public static function mtdYtdClientCountry( \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 address_country, 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 clientmgmt_client ON clientmgmt_client_id = billing_bill_client LEFT JOIN address ON clientmgmt_client_address = address_id WHERE billing_bill_performance_date >= \'' . $startComparison->format('Y-m-d') . '\' AND billing_bill_performance_date <= \'' . $endCurrent->format('Y-m-d') . '\' GROUP BY address_country, YEAR(billing_bill_performance_date), MONTH(billing_bill_performance_date) ORDER BY YEAR(billing_bill_performance_date) ASC, MONTH(billing_bill_performance_date) ASC, address_country 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['address_country']] = $temp; } else { $mtdAClientCountry[$result['address_country']] = $temp; } } if ($monthIndex <= $endCurrentIndex) { if (!isset($ytdPYClientCountry[$result['address_country']])) { $ytdPYClientCountry[$result['address_country']] = [ 'client_count' => 0, ]; $ytdAClientCountry[$result['address_country']] = [ 'client_count' => 0, ]; } if ($period === 1) { $ytdPYClientCountry[$result['address_country']]['client_count'] += $temp['client_count']; } else { $ytdAClientCountry[$result['address_country']]['client_count'] += $temp['client_count']; } } } return [ $mtdPYClientCountry, $mtdAClientCountry, $ytdPYClientCountry, $ytdAClientCountry, ]; } public static function annualSalesProfitCountry( SmartDateTime $historyStart, \DateTime $endCurrent, int $businessStart = 1 ) : array { $query = new Builder(self::$db); $query->raw( 'SELECT address_country, YEAR(billing_bill_performance_date) as salesyear, MONTH(billing_bill_performance_date) as salesmonth, SUM(billing_bill_netsales) as netsales, SUM(billing_bill_netprofit) as netprofit FROM billing_bill LEFT JOIN clientmgmt_client ON clientmgmt_client_id = billing_bill_client LEFT JOIN address ON clientmgmt_client_address = address_id WHERE billing_bill_performance_date >= \'' . $historyStart->format('Y-m-d') . '\' AND billing_bill_performance_date <= \'' . $endCurrent->format('Y-m-d') . '\' GROUP BY address_country, YEAR(billing_bill_performance_date), MONTH(billing_bill_performance_date) ORDER BY YEAR(billing_bill_performance_date) ASC, MONTH(billing_bill_performance_date) ASC, address_country' ); $results = $query->execute()->fetchAll(\PDO::FETCH_ASSOC); $annualSales = []; $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($annualSales[$result['address_country']])) { for ($i = 1; $i < 11; ++$i) { $annualSales[$result['address_country']][$i] = [ 'net_sales' => 0, 'net_profit' => 0, 'year' => $historyStart->format('Y'), ]; $historyStart->smartModify(1); } $historyStart->smartModify(-10); } // indexed according to the fiscal year $annualSales[$result['address_country']][$period]['net_sales'] += (int) $result['netsales']; $annualSales[$result['address_country']][$period]['net_profit'] += (int) $result['netprofit']; } return $annualSales; } public static function mtdYtdCountry( \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 address_country, YEAR(billing_bill_performance_date) as salesyear, MONTH(billing_bill_performance_date) as salesmonth, SUM(billing_bill_netsales) as netsales, SUM(billing_bill_netprofit) as netprofit FROM billing_bill LEFT JOIN clientmgmt_client ON clientmgmt_client_id = billing_bill_client LEFT JOIN address ON clientmgmt_client_address = address_id WHERE billing_bill_performance_date >= \'' . $startComparison->format('Y-m-d') . '\' AND billing_bill_performance_date <= \'' . $endCurrent->format('Y-m-d') . '\' GROUP BY address_country, YEAR(billing_bill_performance_date), MONTH(billing_bill_performance_date) ORDER BY YEAR(billing_bill_performance_date) ASC, MONTH(billing_bill_performance_date) ASC, address_country 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['address_country']] = $temp; } else { $mtdAClientCountry[$result['address_country']] = $temp; } } if ($monthIndex <= $endCurrentIndex) { if (!isset($ytdPYClientCountry[$result['address_country']])) { $ytdPYClientCountry[$result['address_country']] = [ 'net_sales' => 0, 'net_profit' => 0, ]; $ytdAClientCountry[$result['address_country']] = [ 'net_sales' => 0, 'net_profit' => 0, ]; } if ($period === 1) { $ytdPYClientCountry[$result['address_country']]['net_sales'] += $temp['net_sales']; $ytdPYClientCountry[$result['address_country']]['net_profit'] += $temp['net_profit']; } else { $ytdAClientCountry[$result['address_country']]['net_sales'] += $temp['net_sales']; $ytdAClientCountry[$result['address_country']]['net_profit'] += $temp['net_profit']; } } } return [ $mtdPYClientCountry, $mtdAClientCountry, $ytdPYClientCountry, $ytdAClientCountry, ]; } public static function countryToRegion(array $countries, array $region, array $columns) : array { $tempStruct = []; foreach ($columns as $column) { $tempStruct[$column] = 0; } $regions = ['Other' => $tempStruct]; foreach ($region as $r) { $definitions[$r] = ($temp = ISO3166TwoEnum::getRegion($r)) === [] ? [$r] : $temp; $regions[$r] = $tempStruct; } foreach ($countries as $country => $data) { $found = false; foreach ($definitions as $r => $c) { if (\in_array($country, $c)) { foreach ($columns as $column) { $regions[$r][$column] += $data[$column]; } $found = true; } } if (!$found) { foreach ($columns as $column) { $regions['Other'][$column] += $data[$column]; } } } return $regions; } public static function countryIntervalToRegion(array $countries, array $region, array $columns) : array { $count = \count(\reset($countries)); $tempStruct = []; foreach ($columns as $column) { $tempStruct[$column] = 0; } $regions = [ 'Other' => \array_fill(1, $count, $tempStruct), ]; foreach ($region as $r) { $definitions[$r] = ($temp = ISO3166TwoEnum::getRegion($r)) === [] ? [$r] : $temp; $regions[$r] = \array_fill(1, $count, $tempStruct); } foreach ($countries as $country => $data) { $found = false; foreach ($definitions as $r => $c) { if (\in_array($country, $c)) { foreach ($data as $idx => $value) { foreach ($columns as $column) { $regions[$r][$idx][$column] += $value[$column]; } } $found = true; } } if (!$found) { foreach ($data as $idx => $value) { foreach ($columns as $column) { $regions['Other'][$idx][$column] += $value[$column]; } } } } return $regions; } }