1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-09 12:42:36 +01:00

Working on basic reports

This commit is contained in:
Hillel Coren 2015-04-30 20:54:19 +03:00
parent bc10719fbe
commit 1d6013178f
20 changed files with 462 additions and 206 deletions

View File

@ -98,7 +98,7 @@ class AccountController extends BaseController
Auth::login($user, true); Auth::login($user, true);
Event::fire(new UserLoggedIn()); Event::fire(new UserLoggedIn());
return Redirect::to('invoices/create')->with('sign_up', Input::get('sign_up')); return Redirect::to('invoices/create')->with('sign_up', Input::get('sign_up'));
} }
@ -343,40 +343,27 @@ class AccountController extends BaseController
header('Content-Disposition:attachment;filename=export.csv'); header('Content-Disposition:attachment;filename=export.csv');
$clients = Client::scope()->get(); $clients = Client::scope()->get();
AccountController::exportData($output, $clients->toArray()); Utils::exportData($output, $clients->toArray());
$contacts = Contact::scope()->get(); $contacts = Contact::scope()->get();
AccountController::exportData($output, $contacts->toArray()); Utils::exportData($output, $contacts->toArray());
$invoices = Invoice::scope()->get(); $invoices = Invoice::scope()->get();
AccountController::exportData($output, $invoices->toArray()); Utils::exportData($output, $invoices->toArray());
$invoiceItems = InvoiceItem::scope()->get(); $invoiceItems = InvoiceItem::scope()->get();
AccountController::exportData($output, $invoiceItems->toArray()); Utils::exportData($output, $invoiceItems->toArray());
$payments = Payment::scope()->get(); $payments = Payment::scope()->get();
AccountController::exportData($output, $payments->toArray()); Utils::exportData($output, $payments->toArray());
$credits = Credit::scope()->get(); $credits = Credit::scope()->get();
AccountController::exportData($output, $credits->toArray()); Utils::exportData($output, $credits->toArray());
fclose($output); fclose($output);
exit; exit;
} }
private function exportData($output, $data)
{
if (count($data) > 0) {
fputcsv($output, array_keys($data[0]));
}
foreach ($data as $record) {
fputcsv($output, $record);
}
fwrite($output, "\n");
}
private function importFile() private function importFile()
{ {
$data = Session::get('data'); $data = Session::get('data');

View File

@ -187,7 +187,7 @@ class InvoiceController extends BaseController
$server = explode('.', Request::server('HTTP_HOST')); $server = explode('.', Request::server('HTTP_HOST'));
$subdomain = $server[0]; $subdomain = $server[0];
if ($subdomain != 'app' && $subdomain != $account->subdomain) { if (!in_array($subdomain, ['app', 'www']) && $subdomain != $account->subdomain) {
return View::make('invoices.deleted'); return View::make('invoices.deleted');
} }
} }

View File

@ -37,18 +37,26 @@ class ReportController extends BaseController
return View::make('reports.d3', $data); return View::make('reports.d3', $data);
} }
public function report() public function showReports()
{ {
$action = Input::get('action');
if (Input::all()) { if (Input::all()) {
$groupBy = Input::get('group_by'); $groupBy = Input::get('group_by');
$chartType = Input::get('chart_type'); $chartType = Input::get('chart_type');
$reportType = Input::get('report_type');
$startDate = Utils::toSqlDate(Input::get('start_date'), false); $startDate = Utils::toSqlDate(Input::get('start_date'), false);
$endDate = Utils::toSqlDate(Input::get('end_date'), false); $endDate = Utils::toSqlDate(Input::get('end_date'), false);
$enableReport = Input::get('enable_report') ? true : false;
$enableChart = Input::get('enable_chart') ? true : false;
} else { } else {
$groupBy = 'MONTH'; $groupBy = 'MONTH';
$chartType = 'Bar'; $chartType = 'Bar';
$reportType = '';
$startDate = Utils::today(false)->modify('-3 month'); $startDate = Utils::today(false)->modify('-3 month');
$endDate = Utils::today(false); $endDate = Utils::today(false);
$enableReport = true;
$enableChart = true;
} }
$padding = $groupBy == 'DAYOFYEAR' ? 'day' : ($groupBy == 'WEEK' ? 'week' : 'month'); $padding = $groupBy == 'DAYOFYEAR' ? 'day' : ($groupBy == 'WEEK' ? 'week' : 'month');
@ -58,55 +66,142 @@ class ReportController extends BaseController
$maxTotals = 0; $maxTotals = 0;
$width = 10; $width = 10;
$displayData = [];
$exportData = [];
$columns = [];
$reportTotals = [
'amount' => [],
'balance' => [],
'paid' => []
];
if (Auth::user()->account->isPro()) { if (Auth::user()->account->isPro()) {
foreach ([ENTITY_INVOICE, ENTITY_PAYMENT, ENTITY_CREDIT] as $entityType) {
$records = DB::table($entityType.'s')
->select(DB::raw('sum(amount) as total, '.$groupBy.'('.$entityType.'_date) as '.$groupBy))
->where('account_id', '=', Auth::user()->account_id)
->where($entityType.'s.is_deleted', '=', false)
->where($entityType.'s.'.$entityType.'_date', '>=', $startDate->format('Y-m-d'))
->where($entityType.'s.'.$entityType.'_date', '<=', $endDate->format('Y-m-d'))
->groupBy($groupBy);
if ($entityType == ENTITY_INVOICE) { if ($enableReport) {
$records->where('is_quote', '=', false) $query = DB::table('invoices')
->where('is_recurring', '=', false); ->join('clients', 'clients.id', '=', 'invoices.client_id')
->join('contacts', 'contacts.client_id', '=', 'clients.id')
->where('invoices.account_id', '=', Auth::user()->account_id)
->where('invoices.is_deleted', '=', false)
->where('clients.is_deleted', '=', false)
->where('contacts.deleted_at', '=', null)
->where('invoices.invoice_date', '>=', $startDate->format('Y-m-d'))
->where('invoices.invoice_date', '<=', $endDate->format('Y-m-d'))
->where('invoices.is_quote', '=', false)
->where('invoices.is_recurring', '=', false)
->where('contacts.is_primary', '=', true);
$select = ['clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'clients.name as client_name', 'clients.public_id as client_public_id', 'invoices.public_id as invoice_public_id'];
if ($reportType) {
$query->groupBy('clients.id');
array_push($select, DB::raw('sum(invoices.amount) amount'), DB::raw('sum(invoices.balance) balance'), DB::raw('sum(invoices.amount - invoices.balance) paid'));
$columns = ['client', 'amount', 'paid', 'balance'];
} else {
array_push($select, 'invoices.invoice_number', 'invoices.amount', 'invoices.balance', 'invoices.invoice_date', DB::raw('(invoices.amount - invoices.balance) paid'));
$query->orderBy('invoices.id');
$columns = ['client', 'invoice_number', 'invoice_date', 'amount', 'paid', 'balance'];
} }
$query->select($select);
$data = $query->get();
$totals = $records->lists('total'); foreach ($data as $record) {
$dates = $records->lists($groupBy); // web display data
$data = array_combine($dates, $totals); $displayRow = [link_to('/clients/'.$record->client_public_id, Utils::getClientDisplayName($record))];
if (!$reportType) {
$interval = new DateInterval('P1'.substr($groupBy, 0, 1)); array_push($displayRow,
$period = new DatePeriod($startDate, $interval, $endDate); link_to('/invoices/'.$record->invoice_public_id, $record->invoice_number),
Utils::fromSqlDate($record->invoice_date, true)
$totals = []; );
foreach ($period as $d) {
$dateFormat = $groupBy == 'DAYOFYEAR' ? 'z' : ($groupBy == 'WEEK' ? 'W' : 'n');
$date = $d->format($dateFormat);
$totals[] = isset($data[$date]) ? $data[$date] : 0;
if ($entityType == ENTITY_INVOICE) {
$labelFormat = $groupBy == 'DAYOFYEAR' ? 'j' : ($groupBy == 'WEEK' ? 'W' : 'F');
$label = $d->format($labelFormat);
$labels[] = $label;
} }
array_push($displayRow,
Utils::formatMoney($record->amount, $record->currency_id),
Utils::formatMoney($record->paid, $record->currency_id),
Utils::formatMoney($record->balance, $record->currency_id)
);
// export data
$exportRow = [trans('texts.client') => Utils::getClientDisplayName($record)];
if (!$reportType) {
$exportRow[trans('texts.invoice_number')] = $record->invoice_number;
$exportRow[trans('texts.invoice_date')] = Utils::fromSqlDate($record->invoice_date, true);
}
$exportRow[trans('texts.amount')] = Utils::formatMoney($record->amount, $record->currency_id);
$exportRow[trans('texts.paid')] = Utils::formatMoney($record->paid, $record->currency_id);
$exportRow[trans('texts.balance')] = Utils::formatMoney($record->balance, $record->currency_id);
$displayData[] = $displayRow;
$exportData[] = $exportRow;
$accountCurrencyId = Auth::user()->account->currency_id;
$currencyId = $record->currency_id ? $record->currency_id : ($accountCurrencyId ? $accountCurrencyId : DEFAULT_CURRENCY);
if (!isset($reportTotals['amount'][$currencyId])) {
$reportTotals['amount'][$currencyId] = 0;
$reportTotals['balance'][$currencyId] = 0;
$reportTotals['paid'][$currencyId] = 0;
}
$reportTotals['amount'][$currencyId] += $record->amount;
$reportTotals['paid'][$currencyId] += $record->paid;
$reportTotals['balance'][$currencyId] += $record->balance;
} }
$max = max($totals); if ($action == 'export') {
self::export($exportData, $reportTotals);
if ($max > 0) {
$datasets[] = [
'totals' => $totals,
'colors' => $entityType == ENTITY_INVOICE ? '78,205,196' : ($entityType == ENTITY_CREDIT ? '199,244,100' : '255,107,107'),
];
$maxTotals = max($max, $maxTotals);
} }
} }
$width = (ceil($maxTotals / 100) * 100) / 10; if ($enableChart) {
$width = max($width, 10); foreach ([ENTITY_INVOICE, ENTITY_PAYMENT, ENTITY_CREDIT] as $entityType) {
$records = DB::table($entityType.'s')
->select(DB::raw('sum(amount) as total, '.$groupBy.'('.$entityType.'_date) as '.$groupBy))
->where('account_id', '=', Auth::user()->account_id)
->where($entityType.'s.is_deleted', '=', false)
->where($entityType.'s.'.$entityType.'_date', '>=', $startDate->format('Y-m-d'))
->where($entityType.'s.'.$entityType.'_date', '<=', $endDate->format('Y-m-d'))
->groupBy($groupBy);
if ($entityType == ENTITY_INVOICE) {
$records->where('is_quote', '=', false)
->where('is_recurring', '=', false);
}
$totals = $records->lists('total');
$dates = $records->lists($groupBy);
$data = array_combine($dates, $totals);
$interval = new DateInterval('P1'.substr($groupBy, 0, 1));
$period = new DatePeriod($startDate, $interval, $endDate);
$totals = [];
foreach ($period as $d) {
$dateFormat = $groupBy == 'DAYOFYEAR' ? 'z' : ($groupBy == 'WEEK' ? 'W' : 'n');
$date = $d->format($dateFormat);
$totals[] = isset($data[$date]) ? $data[$date] : 0;
if ($entityType == ENTITY_INVOICE) {
$labelFormat = $groupBy == 'DAYOFYEAR' ? 'j' : ($groupBy == 'WEEK' ? 'W' : 'F');
$label = $d->format($labelFormat);
$labels[] = $label;
}
}
$max = max($totals);
if ($max > 0) {
$datasets[] = [
'totals' => $totals,
'colors' => $entityType == ENTITY_INVOICE ? '78,205,196' : ($entityType == ENTITY_CREDIT ? '199,244,100' : '255,107,107'),
];
$maxTotals = max($max, $maxTotals);
}
}
$width = (ceil($maxTotals / 100) * 100) / 10;
$width = max($width, 10);
}
} }
$dateTypes = [ $dateTypes = [
@ -120,6 +215,11 @@ class ReportController extends BaseController
'Line' => 'Line', 'Line' => 'Line',
]; ];
$reportTypes = [
'' => '',
'Client' => trans('texts.client')
];
$params = [ $params = [
'labels' => $labels, 'labels' => $labels,
'datasets' => $datasets, 'datasets' => $datasets,
@ -131,8 +231,35 @@ class ReportController extends BaseController
'endDate' => $endDate->modify('-1'.$padding)->format(Session::get(SESSION_DATE_FORMAT)), 'endDate' => $endDate->modify('-1'.$padding)->format(Session::get(SESSION_DATE_FORMAT)),
'groupBy' => $groupBy, 'groupBy' => $groupBy,
'feature' => ACCOUNT_CHART_BUILDER, 'feature' => ACCOUNT_CHART_BUILDER,
'displayData' => $displayData,
'columns' => $columns,
'reportTotals' => $reportTotals,
'reportTypes' => $reportTypes,
'reportType' => $reportType,
'enableChart' => $enableChart,
'enableReport' => $enableReport,
]; ];
return View::make('reports.report_builder', $params); return View::make('reports.chart_builder', $params);
}
private function export($data, $totals)
{
$output = fopen('php://output', 'w') or Utils::fatalError();
header('Content-Type:application/csv');
header('Content-Disposition:attachment;filename=ninja-report.csv');
Utils::exportData($output, $data);
foreach (['amount', 'paid', 'balance'] as $type) {
$csv = trans("texts.{$type}") . ',';
foreach ($totals[$type] as $currencyId => $amount) {
$csv .= Utils::formatMoney($amount, $currencyId) . ',';
}
fwrite($output, $csv . "\n");
}
fclose($output);
exit;
} }
} }

View File

@ -7,11 +7,17 @@ class DuplicateSubmissionCheck
// Prevent users from submitting forms twice // Prevent users from submitting forms twice
public function handle($request, Closure $next) public function handle($request, Closure $next)
{ {
$path = $request->path();
if (strpos($path, 'charts_and_reports') !== false) {
return $next($request);
}
if (in_array($request->method(), ['POST', 'PUT', 'DELETE'])) { if (in_array($request->method(), ['POST', 'PUT', 'DELETE'])) {
$lastPage = session(SESSION_LAST_REQUEST_PAGE); $lastPage = session(SESSION_LAST_REQUEST_PAGE);
$lastTime = session(SESSION_LAST_REQUEST_TIME); $lastTime = session(SESSION_LAST_REQUEST_TIME);
if ($lastPage == $request->path() && (microtime(true) - $lastTime <= 1.5)) { if ($lastPage == $path && (microtime(true) - $lastTime <= 1.5)) {
return redirect('/')->with('warning', trans('texts.duplicate_post')); return redirect('/')->with('warning', trans('texts.duplicate_post'));
} }

View File

@ -66,7 +66,8 @@ class StartupCheck
$count = Session::get(SESSION_COUNTER, 0); $count = Session::get(SESSION_COUNTER, 0);
Session::put(SESSION_COUNTER, ++$count); Session::put(SESSION_COUNTER, ++$count);
if (!Utils::startsWith($_SERVER['REQUEST_URI'], '/news_feed') && !Session::has('news_feed_id')) { //if (!Utils::startsWith($_SERVER['REQUEST_URI'], '/news_feed') && !Session::has('news_feed_id')) {
if (true) {
$data = false; $data = false;
if (Utils::isNinja()) { if (Utils::isNinja()) {
$data = Utils::getNewsFeedResponse(); $data = Utils::getNewsFeedResponse();
@ -75,12 +76,12 @@ class StartupCheck
$data = @json_decode($file); $data = @json_decode($file);
} }
if ($data) { if ($data) {
if ($data->version != NINJA_VERSION) { if (version_compare(NINJA_VERSION, $data->version, '<')) {
$params = [ $params = [
'user_version' => NINJA_VERSION, 'user_version' => NINJA_VERSION,
'latest_version' => $data->version, 'latest_version' => $data->version,
'releases_link' => link_to(RELEASES_URL, 'Invoice Ninja', ['target' => '_blank']), 'releases_link' => link_to(RELEASES_URL, 'Invoice Ninja', ['target' => '_blank']),
]; ];
Session::put('news_feed_id', NEW_VERSION_AVAILABLE); Session::put('news_feed_id', NEW_VERSION_AVAILABLE);
Session::put('news_feed_message', trans('texts.new_version_available', $params)); Session::put('news_feed_message', trans('texts.new_version_available', $params));
} else { } else {

View File

@ -112,8 +112,8 @@ Route::group(['middleware' => 'auth'], function() {
Route::get('products/{product_id}/archive', 'ProductController@archive'); Route::get('products/{product_id}/archive', 'ProductController@archive');
Route::get('company/advanced_settings/data_visualizations', 'ReportController@d3'); Route::get('company/advanced_settings/data_visualizations', 'ReportController@d3');
Route::get('company/advanced_settings/chart_builder', 'ReportController@report'); Route::get('company/advanced_settings/charts_and_reports', 'ReportController@showReports');
Route::post('company/advanced_settings/chart_builder', 'ReportController@report'); Route::post('company/advanced_settings/charts_and_reports', 'ReportController@showReports');
Route::post('company/cancel_account', 'AccountController@cancelAccount'); Route::post('company/cancel_account', 'AccountController@cancelAccount');
Route::get('account/getSearchData', array('as' => 'getSearchData', 'uses' => 'AccountController@getSearchData')); Route::get('account/getSearchData', array('as' => 'getSearchData', 'uses' => 'AccountController@getSearchData'));
@ -354,10 +354,11 @@ define('NINJA_GATEWAY_ID', GATEWAY_AUTHORIZE_NET);
define('NINJA_GATEWAY_CONFIG', ''); define('NINJA_GATEWAY_CONFIG', '');
define('NINJA_WEB_URL', 'https://www.invoiceninja.com'); define('NINJA_WEB_URL', 'https://www.invoiceninja.com');
define('NINJA_APP_URL', 'https://app.invoiceninja.com'); define('NINJA_APP_URL', 'https://app.invoiceninja.com');
define('NINJA_VERSION', '1.7.2'); define('NINJA_VERSION', '2.0.0');
define('NINJA_DATE', '2000-01-01'); define('NINJA_DATE', '2000-01-01');
define('NINJA_FROM_EMAIL', 'maildelivery@invoiceninja.com'); define('NINJA_FROM_EMAIL', 'maildelivery@invoiceninja.com');
define('RELEASES_URL', 'https://github.com/hillelcoren/invoice-ninja/releases/'); define('RELEASES_URL', 'https://github.com/hillelcoren/invoice-ninja/releases/');
define('ZAPIER_URL', 'https://zapier.com/developer/invite/11276/85cf0ee4beae8e802c6c579eb4e351f1/');
define('COUNT_FREE_DESIGNS', 4); define('COUNT_FREE_DESIGNS', 4);
define('PRODUCT_ONE_CLICK_INSTALL', 1); define('PRODUCT_ONE_CLICK_INSTALL', 1);

View File

@ -623,4 +623,17 @@ class Utils
return $str; return $str;
} }
public static function exportData($output, $data)
{
if (count($data) > 0) {
fputcsv($output, array_keys($data[0]));
}
foreach ($data as $record) {
fputcsv($output, $record);
}
fwrite($output, "\n");
}
} }

View File

@ -44,7 +44,7 @@ return [
| |
*/ */
'encrypt' => false, 'encrypt' => env('SESSION_ENCRYPT', false),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -109,7 +109,7 @@ return [
| |
*/ */
'cookie' => 'laravel_session', 'cookie' => 'ninja_session',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -135,7 +135,7 @@ return [
| |
*/ */
'domain' => null, 'domain' => env('SESSION_DOMAIN', null),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -148,6 +148,6 @@ return [
| |
*/ */
'secure' => false, 'secure' => env('SESSION_SECURE', false),
]; ];

10
public/css/built.css vendored
View File

@ -3238,11 +3238,15 @@ div.checkbox > label {
z-index: 9999; z-index: 9999;
} }
.dataTables_length { div.dataTables_length {
padding-left: 20px; padding-left: 20px;
padding-top: 8px; padding-top: 10px;
} }
.dataTables_length label { div.dataTables_length select {
background-color: white !important;
}
div.dataTables_length label {
font-weight: 500; font-weight: 500;
} }

10
public/css/style.css vendored
View File

@ -854,11 +854,15 @@ div.checkbox > label {
z-index: 9999; z-index: 9999;
} }
.dataTables_length { div.dataTables_length {
padding-left: 20px; padding-left: 20px;
padding-top: 8px; padding-top: 10px;
} }
.dataTables_length label { div.dataTables_length select {
background-color: white !important;
}
div.dataTables_length label {
font-weight: 500; font-weight: 500;
} }

View File

@ -4,6 +4,16 @@
If you'd like to use our code to sell your own invoicing app we have an affiliate program. Get in touch for more details. If you'd like to use our code to sell your own invoicing app we have an affiliate program. Get in touch for more details.
### Introduction
To setup the site you can either use the [zip file](https://www.invoiceninja.com/knowledgebase/self-host/) (easier to run) or checkout the code from GitHub (easier to make changes).
For updates follow [@invoiceninja](https://twitter.com/invoiceninja) or join the [Facebook Group](https://www.facebook.com/invoiceninja). For discussion of the code please use the [Google Group](https://groups.google.com/d/forum/invoiceninja).
If you'd like to translate the site please use [caouecs/Laravel4-long](https://github.com/caouecs/Laravel4-lang) for the starter files.
Developed by [@hillelcoren](https://twitter.com/hillelcoren) | Designed by [kantorp-wegl.in](http://kantorp-wegl.in/).
### Features ### Features
* Core application built using Laravel 5 * Core application built using Laravel 5

View File

@ -637,5 +637,18 @@ return array(
'www' => 'www', 'www' => 'www',
'logo' => 'Logo', 'logo' => 'Logo',
'subdomain' => 'Subdomain', 'subdomain' => 'Subdomain',
'provide_name_or_email' => 'Please provide a contact name or email',
'charts_and_reports' => 'Charts & Reports',
'chart' => 'Chart',
'report' => 'Report',
'group_by' => 'Group by',
'paid' => 'Paid',
'enable_report' => 'Report',
'enable_chart' => 'Chart',
'totals' => 'Totals',
'run' => 'Run',
'export' => 'Export',
'documentation' => 'Documentation',
'zapier' => 'Zapier <sup>Beta</sup>',
); );

View File

@ -2,7 +2,7 @@
{!! HTML::nav_link('company/advanced_settings/invoice_settings', 'invoice_settings') !!} {!! HTML::nav_link('company/advanced_settings/invoice_settings', 'invoice_settings') !!}
{!! HTML::nav_link('company/advanced_settings/invoice_design', 'invoice_design') !!} {!! HTML::nav_link('company/advanced_settings/invoice_design', 'invoice_design') !!}
{!! HTML::nav_link('company/advanced_settings/email_templates', 'email_templates') !!} {!! HTML::nav_link('company/advanced_settings/email_templates', 'email_templates') !!}
{!! HTML::nav_link('company/advanced_settings/chart_builder', 'chart_builder') !!} {!! HTML::nav_link('company/advanced_settings/charts_and_reports', 'charts_and_reports') !!}
{!! HTML::nav_link('company/advanced_settings/user_management', 'users_and_tokens') !!} {!! HTML::nav_link('company/advanced_settings/user_management', 'users_and_tokens') !!}
</ul> </ul>
<p>&nbsp;</p> <p>&nbsp;</p>

View File

@ -13,7 +13,8 @@
<div class="pull-right"> <div class="pull-right">
{!! Button::normal(trans('texts.view_documentation'))->asLinkTo(NINJA_WEB_URL.'/knowledgebase/api-documentation/')->withAttributes(['target' => '_blank']) !!} {!! Button::normal(trans('texts.documentation'))->asLinkTo(NINJA_WEB_URL.'/knowledgebase/api-documentation/')->withAttributes(['target' => '_blank']) !!}
{!! Button::normal(trans('texts.zapier'))->asLinkTo(ZAPIER_URL)->withAttributes(['target' => '_blank']) !!}
@if (Utils::isPro()) @if (Utils::isPro())
{!! Button::primary(trans('texts.add_token'))->asLinkTo('/tokens/create')->appendIcon(Icon::create('plus-sign')) !!} {!! Button::primary(trans('texts.add_token'))->asLinkTo('/tokens/create')->appendIcon(Icon::create('plus-sign')) !!}
@endif @endif

View File

@ -215,7 +215,7 @@
$(function() { $(function() {
window.setTimeout(function() { window.setTimeout(function() {
$(".alert-hide").fadeOut(500); $(".alert-hide").fadeOut(500);
}, 3000); }, 2000);
$('#search').focus(function(){ $('#search').focus(function(){
if (!window.hasOwnProperty('searchData')) { if (!window.hasOwnProperty('searchData')) {

View File

@ -473,7 +473,7 @@
</div> </div>
<div class="modal-footer" style="margin-top: 0px; padding-top:0px;"> <div class="modal-footer" style="margin-top: 0px; padding-top:0px;">
<span class="error-block" id="emailError" style="display:none;float:left;font-weight:bold">{{ trans('texts.provide_email') }}</span><span>&nbsp;</span> <span class="error-block" id="emailError" style="display:none;float:left;font-weight:bold">{{ trans('texts.provide_name_or_email') }}</span><span>&nbsp;</span>
<button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('texts.cancel') }}</button> <button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('texts.cancel') }}</button>
<button type="button" class="btn btn-default" data-bind="click: $root.showMoreFields, text: $root.showMore() ? '{{ trans('texts.less_fields') }}' : '{{ trans('texts.more_fields') }}'"></button> <button type="button" class="btn btn-default" data-bind="click: $root.showMoreFields, text: $root.showMore() ? '{{ trans('texts.less_fields') }}' : '{{ trans('texts.more_fields') }}'"></button>
<button id="clientDoneButton" type="button" class="btn btn-primary" data-bind="click: $root.clientFormComplete">{{ trans('texts.done') }}</button> <button id="clientDoneButton" type="button" class="btn btn-primary" data-bind="click: $root.clientFormComplete">{{ trans('texts.done') }}</button>

View File

@ -10,8 +10,8 @@
</div> </div>
{!! DropdownButton::normal(trans('texts.archive'))->withContents([ {!! DropdownButton::normal(trans('texts.archive'))->withContents([
['label' => trans('texts.archive_'.$entityType), 'url' => "javascript:submitForm('archive')"], ['label' => trans('texts.archive_'.$entityType), 'url' => 'javascript:submitForm("archive")'],
['label' => trans('texts.delete_'.$entityType), 'url' => "javascript:submitForm('delete')"], ['label' => trans('texts.delete_'.$entityType), 'url' => 'javascript:submitForm("delete")'],
])->withAttributes(['class'=>'archive'])->split() !!} ])->withAttributes(['class'=>'archive'])->split() !!}
&nbsp;<label for="trashed" style="font-weight:normal; margin-left: 10px;"> &nbsp;<label for="trashed" style="font-weight:normal; margin-left: 10px;">

View File

@ -0,0 +1,206 @@
@extends('accounts.nav')
@section('head')
@parent
<script src="{!! asset('js/Chart.js') !!}" type="text/javascript"></script>
@stop
@section('content')
@parent
@include('accounts.nav_advanced')
{!! Button::primary(trans('texts.data_visualizations'))
->asLinkTo('/company/advanced_settings/data_visualizations')
->withAttributes(['class' => 'pull-right'])
->appendIcon(Icon::create('globe')) !!}
<p>&nbsp;</p>
<p>&nbsp;</p>
<div class="row">
<div class="col-lg-4">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{!! trans('texts.settings') !!}</h3>
</div>
<div class="panel-body">
{!! Former::open()->addClass('warn-on-exit') !!}
<div style="display:none">
{!! Former::text('action') !!}
</div>
{!! Former::populateField('start_date', $startDate) !!}
{!! Former::populateField('end_date', $endDate) !!}
{!! Former::populateField('enable_report', intval($enableReport)) !!}
{!! Former::populateField('enable_chart', intval($enableChart)) !!}
{!! Former::text('start_date')->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))
->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'start_date\')"></i>') !!}
{!! Former::text('end_date')->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))
->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'end_date\')"></i>') !!}
<p>&nbsp;</p>
{!! Former::checkbox('enable_report')->text(trans('texts.enable')) !!}
{!! Former::select('report_type')->options($reportTypes, $reportType)->label(trans('texts.group_by')) !!}
<p>&nbsp;</p>
{!! Former::checkbox('enable_chart')->text(trans('texts.enable')) !!}
{!! Former::select('chart_type')->options($chartTypes, $chartType) !!}
{!! Former::select('group_by')->options($dateTypes, $groupBy) !!}
<p>&nbsp;</p>
@if (Auth::user()->isPro())
{!! Former::actions(
Button::primary(trans('texts.export'))->withAttributes(array('onclick' => 'onExportClick()'))->appendIcon(Icon::create('export')),
Button::success(trans('texts.run'))->withAttributes(array('id' => 'submitButton'))->submit()->appendIcon(Icon::create('play'))
) !!}
@else
<script>
$(function() {
$('form.warn-on-exit').find('input, select').prop('disabled', true);
});
</script>
@endif
{!! Former::close() !!}
</div>
</div>
</div>
<div class="col-lg-8">
@if ($enableReport)
<div class="panel panel-default">
<div class="panel-body">
<table class="table table-striped invoice-table">
<thead>
<tr>
@foreach ($columns as $column)
<th>
{{ trans("texts.{$column}") }}
</th>
@endforeach
</tr>
</thead>
<tbody>
@foreach ($displayData as $record)
<tr>
@foreach ($record as $field)
<td>
{!! $field !!}
</td>
@endforeach
</tr>
@endforeach
</tbody>
<tfoot>
<tr>
<td><b>{{ trans('texts.totals') }}</b></td>
@if (!$reportType)
<td></td>
<td></td>
@endif
<td>
@foreach ($reportTotals['amount'] as $currencyId => $total)
<b>{{ Utils::formatMoney($total, $currencyId) }}</b><br/>
@endforeach
</td>
<td>
@foreach ($reportTotals['paid'] as $currencyId => $total)
<b>{{ Utils::formatMoney($total, $currencyId) }}</b><br/>
@endforeach
</td>
<td>
@foreach ($reportTotals['balance'] as $currencyId => $total)
<b>{{ Utils::formatMoney($total, $currencyId) }}</b><br/>
@endforeach
</td>
<td>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
@endif
@if ($enableChart)
<div class="panel panel-default">
<div class="panel-body">
<canvas id="monthly-reports" width="700" height="400"></canvas>
<p>&nbsp;</p>
<div style="padding-bottom:8px">
<div style="float:left; height:22px; width:60px; background-color:rgba(78,205,196,.5); border: 1px solid rgba(78,205,196,1)"></div>
<div style="vertical-align: middle">&nbsp;Invoices</div>
</div>
<div style="padding-bottom:8px; clear:both">
<div style="float:left; height:22px; width:60px; background-color:rgba(255,107,107,.5); border: 1px solid rgba(255,107,107,1)"></div>
<div style="vertical-align: middle">&nbsp;Payments</div>
</div>
<div style="clear:both">
<div style="float:left; height:22px; width:60px; background-color:rgba(199,244,100,.5); border: 1px solid rgba(199,244,100,1)"></div>
<div style="vertical-align: middle">&nbsp;Credits</div>
</div>
</div>
</div>
@endif
</div>
</div>
<script type="text/javascript">
function onExportClick() {
$('#action').val('export');
$('#submitButton').click();
$('#action').val('');
}
var ctx = document.getElementById('monthly-reports').getContext('2d');
var chart = {
labels: {!! json_encode($labels) !!},
datasets: [
@foreach ($datasets as $dataset)
{
data: {!! json_encode($dataset['totals']) !!},
fillColor : "rgba({!! $dataset['colors'] !!},0.5)",
strokeColor : "rgba({!! $dataset['colors'] !!},1)",
},
@endforeach
]
}
var options = {
scaleOverride: true,
scaleSteps: 10,
scaleStepWidth: {!! $scaleStepWidth !!},
scaleStartValue: 0,
scaleLabel : "<%=value%>",
};
new Chart(ctx).{!! $chartType !!}(chart, options);
</script>
@stop
@section('onReady')
$('#start_date, #end_date').datepicker({
autoclose: true,
todayHighlight: true,
keyboardNavigation: false
});
@stop

View File

@ -32,10 +32,6 @@
@parent @parent
@include('accounts.nav_advanced') @include('accounts.nav_advanced')
{!! Former::open() !!}
{!! Former::legend('data_visualizations') !!}
{!! Former::close() !!}
<div id="tooltip" class="hidden"> <div id="tooltip" class="hidden">
<p> <p>
<strong><span id="tooltipTitle"></span></strong> <strong><span id="tooltipTitle"></span></strong>
@ -48,7 +44,7 @@
<form class="form-inline" role="form"> <form class="form-inline" role="form">
Group By &nbsp;&nbsp; Group By &nbsp;&nbsp;
<select id="groupBySelect" class="form-control" onchange="update()"> <select id="groupBySelect" class="form-control" onchange="update()" style="background-color:white !important">
<option>Clients</option> <option>Clients</option>
<option>Invoices</option> <option>Invoices</option>
<option>Products</option> <option>Products</option>

View File

@ -1,113 +0,0 @@
@extends('accounts.nav')
@section('head')
@parent
<script src="{!! asset('js/Chart.js') !!}" type="text/javascript"></script>
@stop
@section('content')
@parent
@include('accounts.nav_advanced')
{!! Button::primary(trans('texts.data_visualizations'))
->asLinkTo('/company/advanced_settings/data_visualizations')
->withAttributes(['class' => 'pull-right'])
->appendIcon(Icon::create('globe')) !!}
<p>&nbsp;</p>
<p>&nbsp;</p>
<div class="panel panel-default">
<div class="panel-body">
<div class="row">
<div class="col-lg-4">
{!! Former::open()->addClass('warn-on-exit') !!}
{!! Former::populateField('start_date', $startDate) !!}
{!! Former::populateField('end_date', $endDate) !!}
{!! Former::select('chart_type')->options($chartTypes, $chartType) !!}
{!! Former::select('group_by')->options($dateTypes, $groupBy) !!}
{!! Former::text('start_date')->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))
->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'start_date\')"></i>') !!}
{!! Former::text('end_date')->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))
->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'end_date\')"></i>') !!}
@if (Auth::user()->isPro())
{!! Former::actions( Button::primary('Generate')->submit() ) !!}
@else
<script>
$(function() {
$('form.warn-on-exit').find('input, select').prop('disabled', true);
});
</script>
@endif
{!! Former::close() !!}
<p>&nbsp;</p>
<div style="padding-bottom:8px">
<div style="float:left; height:22px; width:60px; background-color:rgba(78,205,196,.5); border: 1px solid rgba(78,205,196,1)"></div>
<div style="vertical-align: middle">&nbsp;Invoices</div>
</div>
<div style="padding-bottom:8px; clear:both">
<div style="float:left; height:22px; width:60px; background-color:rgba(255,107,107,.5); border: 1px solid rgba(255,107,107,1)"></div>
<div style="vertical-align: middle">&nbsp;Payments</div>
</div>
<div style="clear:both">
<div style="float:left; height:22px; width:60px; background-color:rgba(199,244,100,.5); border: 1px solid rgba(199,244,100,1)"></div>
<div style="vertical-align: middle">&nbsp;Credits</div>
</div>
</div>
<div class="col-lg-8">
<canvas id="monthly-reports" width="772" height="400"></canvas>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var ctx = document.getElementById('monthly-reports').getContext('2d');
var chart = {
labels: {!! json_encode($labels) !!},
datasets: [
@foreach ($datasets as $dataset)
{
data: {!! json_encode($dataset['totals']) !!},
fillColor : "rgba({!! $dataset['colors'] !!},0.5)",
strokeColor : "rgba({!! $dataset['colors'] !!},1)",
},
@endforeach
]
}
var options = {
scaleOverride: true,
scaleSteps: 10,
scaleStepWidth: {!! $scaleStepWidth !!},
scaleStartValue: 0,
scaleLabel : "<%=formatMoney(value)%>",
};
new Chart(ctx).{!! $chartType !!}(chart, options);
</script>
@stop
@section('onReady')
$('#start_date, #end_date').datepicker({
autoclose: true,
todayHighlight: true,
keyboardNavigation: false
});
@stop