mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-09 20:52:56 +01:00
working on email stats
This commit is contained in:
parent
3e81fc3925
commit
e97a35f916
@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Jobs\ExportReportResults;
|
||||
use App\Jobs\LoadPostmarkStats;
|
||||
use App\Jobs\RunReport;
|
||||
use App\Models\Account;
|
||||
use App\Models\ScheduledReport;
|
||||
@ -12,9 +13,6 @@ use Utils;
|
||||
use View;
|
||||
use Carbon;
|
||||
use Validator;
|
||||
use stdClass;
|
||||
use DateInterval;
|
||||
use DatePeriod;
|
||||
|
||||
|
||||
/**
|
||||
@ -189,67 +187,8 @@ class ReportController extends BaseController
|
||||
|
||||
public function loadEmailReport($startDate, $endDate)
|
||||
{
|
||||
$account = auth()->user()->account;
|
||||
$startDate = date_create($startDate);
|
||||
$endDate = date_create($endDate);
|
||||
$postmark = new \Postmark\PostmarkClient(config('services.postmark'));
|
||||
$obj = new stdClass;
|
||||
$data = dispatch(new LoadPostmarkStats($startDate, $endDate));
|
||||
|
||||
$eventTypes = ['sent', 'opened'];
|
||||
|
||||
foreach ($eventTypes as $eventType) {
|
||||
$data = [];
|
||||
$endDate->modify('+1 day');
|
||||
$interval = new DateInterval('P1D');
|
||||
$period = new DatePeriod($startDate, $interval, $endDate);
|
||||
$endDate->modify('-1 day');
|
||||
$records = [];
|
||||
|
||||
if ($eventType == 'sent') {
|
||||
$response = $postmark->getOutboundSendStatistics(null, request()->start_date, request()->end_date);
|
||||
} else {
|
||||
$response = $postmark->getOutboundOpenStatistics(null, request()->start_date, request()->end_date);
|
||||
}
|
||||
|
||||
foreach ($response->days as $key => $val) {
|
||||
$field = $eventType == 'opened' ? 'unique' : $eventType;
|
||||
$data[$val['date']] = $val[$field];
|
||||
}
|
||||
|
||||
foreach ($period as $day) {
|
||||
$date = $day->format('Y-m-d');
|
||||
$records[] = isset($data[$date]) ? $data[$date] : 0;
|
||||
|
||||
if ($eventType == 'sent') {
|
||||
$labels[] = $day->format('m/d/Y');
|
||||
}
|
||||
}
|
||||
|
||||
if ($eventType == 'sent') {
|
||||
$color = '51,122,183';
|
||||
} elseif ($eventType == 'opened') {
|
||||
$color = '54,193,87';
|
||||
} elseif ($eventType == 'bounced') {
|
||||
$color = '128,128,128';
|
||||
}
|
||||
|
||||
$group = new stdClass();
|
||||
$group->data = $records;
|
||||
$group->label = trans("texts.{$eventType}");
|
||||
$group->lineTension = 0;
|
||||
$group->borderWidth = 4;
|
||||
$group->borderColor = "rgba({$color}, 1)";
|
||||
$group->backgroundColor = "rgba({$color}, 0.1)";
|
||||
$datasets[] = $group;
|
||||
}
|
||||
|
||||
$data = new stdClass();
|
||||
$data->labels = $labels;
|
||||
$data->datasets = $datasets;
|
||||
|
||||
$response = new stdClass();
|
||||
$response->data = $data;
|
||||
|
||||
return response()->json($response);
|
||||
return response()->json($data);
|
||||
}
|
||||
}
|
||||
|
151
app/Jobs/LoadPostmarkStats.php
Normal file
151
app/Jobs/LoadPostmarkStats.php
Normal file
@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Jobs\Job;
|
||||
use Postmark\PostmarkClient;
|
||||
use stdClass;
|
||||
use DateInterval;
|
||||
use DatePeriod;
|
||||
|
||||
class LoadPostmarkStats extends Job
|
||||
{
|
||||
public function __construct($startDate, $endDate)
|
||||
{
|
||||
$this->startDate = $startDate;
|
||||
$this->endDate = $endDate;
|
||||
|
||||
$this->response = new stdClass();
|
||||
$this->postmark = new \Postmark\PostmarkClient(config('services.postmark'));
|
||||
$this->account = auth()->user()->account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->loadOverallStats();
|
||||
$this->loadSentStats();
|
||||
$this->loadPlatformStats();
|
||||
$this->loadEmailClientStats();
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
private function loadOverallStats() {
|
||||
$startDate = date_create($this->startDate);
|
||||
$endDate = date_create($this->endDate);
|
||||
|
||||
$eventTypes = ['sent', 'opened'];
|
||||
|
||||
foreach ($eventTypes as $eventType) {
|
||||
$data = [];
|
||||
$endDate->modify('+1 day');
|
||||
$interval = new DateInterval('P1D');
|
||||
$period = new DatePeriod($startDate, $interval, $endDate);
|
||||
$endDate->modify('-1 day');
|
||||
$records = [];
|
||||
|
||||
if ($eventType == 'sent') {
|
||||
$response = $this->postmark->getOutboundSendStatistics(null, request()->start_date, request()->end_date);
|
||||
} else {
|
||||
$response = $this->postmark->getOutboundOpenStatistics(null, request()->start_date, request()->end_date);
|
||||
}
|
||||
|
||||
foreach ($response->days as $key => $val) {
|
||||
$field = $eventType == 'opened' ? 'unique' : $eventType;
|
||||
$data[$val['date']] = $val[$field];
|
||||
}
|
||||
|
||||
foreach ($period as $day) {
|
||||
$date = $day->format('Y-m-d');
|
||||
$records[] = isset($data[$date]) ? $data[$date] : 0;
|
||||
|
||||
if ($eventType == 'sent') {
|
||||
$labels[] = $day->format('m/d/Y');
|
||||
}
|
||||
}
|
||||
|
||||
if ($eventType == 'sent') {
|
||||
$color = '51,122,183';
|
||||
} elseif ($eventType == 'opened') {
|
||||
$color = '54,193,87';
|
||||
} elseif ($eventType == 'bounced') {
|
||||
$color = '128,128,128';
|
||||
}
|
||||
|
||||
$group = new stdClass();
|
||||
$group->data = $records;
|
||||
$group->label = trans("texts.{$eventType}");
|
||||
$group->lineTension = 0;
|
||||
$group->borderWidth = 4;
|
||||
$group->borderColor = "rgba({$color}, 1)";
|
||||
$group->backgroundColor = "rgba({$color}, 0.1)";
|
||||
$datasets[] = $group;
|
||||
}
|
||||
|
||||
$data = new stdClass();
|
||||
$data->labels = $labels;
|
||||
$data->datasets = $datasets;
|
||||
$this->response->data = $data;
|
||||
}
|
||||
|
||||
private function loadSentStats() {
|
||||
$account = $this->account;
|
||||
$data = $this->postmark->getOutboundOverviewStatistics(null, request()->start_date, request()->end_date);
|
||||
$this->response->totals = [
|
||||
'sent' => $account->formatNumber($data->sent),
|
||||
'opened' => sprintf('%s | %s%%', $account->formatNumber($data->uniqueopens), $account->formatNumber($data->uniqueopens / $data->sent * 100)),
|
||||
'bounced' => sprintf('%s | %s%%', $account->formatNumber($data->bounced), $account->formatNumber($data->bouncerate, 3)),
|
||||
//'spam' => sprintf('%s | %s%%', $account->formatNumber($data->spamcomplaints), $account->formatNumber($data->spamcomplaintsrate, 3))
|
||||
];
|
||||
}
|
||||
|
||||
private function loadPlatformStats() {
|
||||
$data = $this->postmark->getOutboundPlatformStatistics(null, request()->start_date, request()->end_date);
|
||||
$account = $this->account;
|
||||
$str = '';
|
||||
$total = 0;
|
||||
|
||||
$total = $data['desktop'] + $data['mobile'] + $data['webmail'];
|
||||
|
||||
foreach (['mobile', 'desktop', 'webmail'] as $platform) {
|
||||
$str .= sprintf('<tr><td>%s</td><td>%s%%</td></tr>', trans('texts.' . $platform), $account->formatNumber($data[$platform] / $total * 100));
|
||||
}
|
||||
|
||||
$this->response->platforms = $str;
|
||||
}
|
||||
|
||||
private function loadEmailClientStats() {
|
||||
$data = $this->postmark->getOutboundEmailClientStatistics(null, request()->start_date, request()->end_date);
|
||||
$account = $this->account;
|
||||
$str = '';
|
||||
$total = 0;
|
||||
$clients = [];
|
||||
|
||||
foreach ($data as $key => $val) {
|
||||
if ($key == 'days') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$total += $val;
|
||||
$clients[$key] = $val;
|
||||
}
|
||||
|
||||
arsort($clients);
|
||||
|
||||
foreach ($clients as $key => $val) {
|
||||
$percent = $val / $total * 100;
|
||||
if ($percent < 0.5) {
|
||||
continue;
|
||||
}
|
||||
$str .= sprintf('<tr><td>%s</td><td>%s%%</td></tr>', ucwords($key), $account->formatNumber($percent));
|
||||
}
|
||||
|
||||
$this->response->emailClients = $str;
|
||||
}
|
||||
|
||||
}
|
@ -500,6 +500,21 @@ class Utils
|
||||
return $data->first();
|
||||
}
|
||||
|
||||
public static function formatNumber($value, $currencyId = false, $precision = 0)
|
||||
{
|
||||
$value = floatval($value);
|
||||
|
||||
if (! $currencyId) {
|
||||
$currencyId = Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY);
|
||||
}
|
||||
|
||||
$currency = self::getFromCache($currencyId, 'currencies');
|
||||
$thousand = $currency->thousand_separator;
|
||||
$decimal = $currency->decimal_separator;
|
||||
|
||||
return number_format($value, $precision, $decimal, $thousand);
|
||||
}
|
||||
|
||||
public static function formatMoney($value, $currencyId = false, $countryId = false, $decorator = false)
|
||||
{
|
||||
$value = floatval($value);
|
||||
|
@ -682,6 +682,17 @@ class Account extends Eloquent
|
||||
return Utils::formatMoney($amount, $currencyId, $countryId, $decorator);
|
||||
}
|
||||
|
||||
public function formatNumber($amount, $precision = 0)
|
||||
{
|
||||
if ($this->currency_id) {
|
||||
$currencyId = $this->currency_id;
|
||||
} else {
|
||||
$currencyId = DEFAULT_CURRENCY;
|
||||
}
|
||||
|
||||
return Utils::formatNumber($amount, $currencyId, $precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
|
@ -2755,6 +2755,15 @@ $LANG = array(
|
||||
'emails' => 'Emails',
|
||||
'opened' => 'Opened',
|
||||
'bounced' => 'Bounced',
|
||||
'total_sent' => 'Total Sent',
|
||||
'total_opened' => 'Total Opened',
|
||||
'total_bounced' => 'Total Bounced',
|
||||
'total_spam' => 'Total Spam',
|
||||
'platforms' => 'Platforms',
|
||||
'email_clients' => 'Email Clients',
|
||||
'mobile' => 'Mobile',
|
||||
'desktop' => 'Desktop',
|
||||
'webmail' => 'Webmail',
|
||||
|
||||
);
|
||||
|
||||
|
@ -66,11 +66,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
fontSize: 18,
|
||||
text: '{{ trans('texts.total_revenue') }}'
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'time',
|
||||
@ -164,8 +159,14 @@
|
||||
function loadData() {
|
||||
var url = "{!! url('/reports/emails_report') !!}/" + chartStartDate.format('YYYY-MM-DD') + '/' + chartEndDate.format('YYYY-MM-DD');
|
||||
$.get(url, function(response) {
|
||||
//response = JSON.parse(response);
|
||||
loadChart(response.data);
|
||||
$('#totalSentDiv').html(response.totals['sent']);
|
||||
$('#totalOpenedDiv').html(response.totals['opened']);
|
||||
$('#totalBouncedDiv').html(response.totals['bounced']);
|
||||
//$('#totalSpamDiv').html(response.totals['spam']);
|
||||
|
||||
$('#platformsTable').html(response.platforms);
|
||||
$('#emailClientsTable').html(response.emailClients);
|
||||
})
|
||||
}
|
||||
|
||||
@ -174,6 +175,68 @@
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div style="overflow:hidden">
|
||||
<div class="in-thin">
|
||||
{{ trans('texts.total_sent') }}
|
||||
</div>
|
||||
<div class="in-bold" id="totalSentDiv">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div style="overflow:hidden">
|
||||
<div class="in-thin">
|
||||
{{ trans('texts.total_opened') }}
|
||||
</div>
|
||||
<div class="in-bold" id="totalOpenedDiv">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div style="overflow:hidden">
|
||||
<div class="in-thin">
|
||||
{{ trans('texts.total_bounced') }}
|
||||
</div>
|
||||
<div class="in-bold" id="totalBouncedDiv">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="col-md-3">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body outstanding-panel">
|
||||
<div style="overflow:hidden">
|
||||
<div class="in-thin">
|
||||
{{ trans('texts.total_spam') }}
|
||||
</div>
|
||||
<div class="in-bold" id="totalSpamDiv">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="progress-div" class="progress">
|
||||
@ -184,4 +247,35 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" style="background-color:#777 !important">
|
||||
<h3 class="panel-title in-bold-white">
|
||||
<i class="glyphicon glyphicon-phone"></i> {{ trans('texts.platforms') }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body" style="height:260px;overflow-y:auto;">
|
||||
<table class="table table-striped" id="platformsTable">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" style="margin:0; background-color: #f5f5f5 !important;">
|
||||
<h3 class="panel-title" style="color: black !important">
|
||||
<i class="glyphicon glyphicon-inbox"></i> {{ trans('texts.email_clients') }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body" style="height:260px;overflow-y:auto;">
|
||||
<table class="table table-striped" id="emailClientsTable">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
Loading…
Reference in New Issue
Block a user