mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-18 00:53:10 +01:00
Working on basic reports
This commit is contained in:
parent
bc10719fbe
commit
1d6013178f
@ -98,7 +98,7 @@ class AccountController extends BaseController
|
||||
|
||||
Auth::login($user, true);
|
||||
Event::fire(new UserLoggedIn());
|
||||
|
||||
|
||||
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');
|
||||
|
||||
$clients = Client::scope()->get();
|
||||
AccountController::exportData($output, $clients->toArray());
|
||||
Utils::exportData($output, $clients->toArray());
|
||||
|
||||
$contacts = Contact::scope()->get();
|
||||
AccountController::exportData($output, $contacts->toArray());
|
||||
Utils::exportData($output, $contacts->toArray());
|
||||
|
||||
$invoices = Invoice::scope()->get();
|
||||
AccountController::exportData($output, $invoices->toArray());
|
||||
Utils::exportData($output, $invoices->toArray());
|
||||
|
||||
$invoiceItems = InvoiceItem::scope()->get();
|
||||
AccountController::exportData($output, $invoiceItems->toArray());
|
||||
Utils::exportData($output, $invoiceItems->toArray());
|
||||
|
||||
$payments = Payment::scope()->get();
|
||||
AccountController::exportData($output, $payments->toArray());
|
||||
Utils::exportData($output, $payments->toArray());
|
||||
|
||||
$credits = Credit::scope()->get();
|
||||
AccountController::exportData($output, $credits->toArray());
|
||||
Utils::exportData($output, $credits->toArray());
|
||||
|
||||
fclose($output);
|
||||
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()
|
||||
{
|
||||
$data = Session::get('data');
|
||||
|
@ -187,7 +187,7 @@ class InvoiceController extends BaseController
|
||||
$server = explode('.', Request::server('HTTP_HOST'));
|
||||
$subdomain = $server[0];
|
||||
|
||||
if ($subdomain != 'app' && $subdomain != $account->subdomain) {
|
||||
if (!in_array($subdomain, ['app', 'www']) && $subdomain != $account->subdomain) {
|
||||
return View::make('invoices.deleted');
|
||||
}
|
||||
}
|
||||
|
@ -37,18 +37,26 @@ class ReportController extends BaseController
|
||||
return View::make('reports.d3', $data);
|
||||
}
|
||||
|
||||
public function report()
|
||||
public function showReports()
|
||||
{
|
||||
$action = Input::get('action');
|
||||
|
||||
if (Input::all()) {
|
||||
$groupBy = Input::get('group_by');
|
||||
$chartType = Input::get('chart_type');
|
||||
$reportType = Input::get('report_type');
|
||||
$startDate = Utils::toSqlDate(Input::get('start_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 {
|
||||
$groupBy = 'MONTH';
|
||||
$chartType = 'Bar';
|
||||
$reportType = '';
|
||||
$startDate = Utils::today(false)->modify('-3 month');
|
||||
$endDate = Utils::today(false);
|
||||
$enableReport = true;
|
||||
$enableChart = true;
|
||||
}
|
||||
|
||||
$padding = $groupBy == 'DAYOFYEAR' ? 'day' : ($groupBy == 'WEEK' ? 'week' : 'month');
|
||||
@ -58,55 +66,142 @@ class ReportController extends BaseController
|
||||
$maxTotals = 0;
|
||||
$width = 10;
|
||||
|
||||
$displayData = [];
|
||||
$exportData = [];
|
||||
$columns = [];
|
||||
$reportTotals = [
|
||||
'amount' => [],
|
||||
'balance' => [],
|
||||
'paid' => []
|
||||
];
|
||||
|
||||
|
||||
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) {
|
||||
$records->where('is_quote', '=', false)
|
||||
->where('is_recurring', '=', false);
|
||||
if ($enableReport) {
|
||||
$query = DB::table('invoices')
|
||||
->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');
|
||||
$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;
|
||||
foreach ($data as $record) {
|
||||
// web display data
|
||||
$displayRow = [link_to('/clients/'.$record->client_public_id, Utils::getClientDisplayName($record))];
|
||||
if (!$reportType) {
|
||||
array_push($displayRow,
|
||||
link_to('/invoices/'.$record->invoice_public_id, $record->invoice_number),
|
||||
Utils::fromSqlDate($record->invoice_date, true)
|
||||
);
|
||||
}
|
||||
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 ($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);
|
||||
if ($action == 'export') {
|
||||
self::export($exportData, $reportTotals);
|
||||
}
|
||||
}
|
||||
|
||||
$width = (ceil($maxTotals / 100) * 100) / 10;
|
||||
$width = max($width, 10);
|
||||
if ($enableChart) {
|
||||
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 = [
|
||||
@ -120,6 +215,11 @@ class ReportController extends BaseController
|
||||
'Line' => 'Line',
|
||||
];
|
||||
|
||||
$reportTypes = [
|
||||
'' => '',
|
||||
'Client' => trans('texts.client')
|
||||
];
|
||||
|
||||
$params = [
|
||||
'labels' => $labels,
|
||||
'datasets' => $datasets,
|
||||
@ -131,8 +231,35 @@ class ReportController extends BaseController
|
||||
'endDate' => $endDate->modify('-1'.$padding)->format(Session::get(SESSION_DATE_FORMAT)),
|
||||
'groupBy' => $groupBy,
|
||||
'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;
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,17 @@ class DuplicateSubmissionCheck
|
||||
// Prevent users from submitting forms twice
|
||||
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'])) {
|
||||
$lastPage = session(SESSION_LAST_REQUEST_PAGE);
|
||||
$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'));
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,8 @@ class StartupCheck
|
||||
$count = Session::get(SESSION_COUNTER, 0);
|
||||
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;
|
||||
if (Utils::isNinja()) {
|
||||
$data = Utils::getNewsFeedResponse();
|
||||
@ -75,12 +76,12 @@ class StartupCheck
|
||||
$data = @json_decode($file);
|
||||
}
|
||||
if ($data) {
|
||||
if ($data->version != NINJA_VERSION) {
|
||||
if (version_compare(NINJA_VERSION, $data->version, '<')) {
|
||||
$params = [
|
||||
'user_version' => NINJA_VERSION,
|
||||
'latest_version' => $data->version,
|
||||
'releases_link' => link_to(RELEASES_URL, 'Invoice Ninja', ['target' => '_blank']),
|
||||
];
|
||||
'user_version' => NINJA_VERSION,
|
||||
'latest_version' => $data->version,
|
||||
'releases_link' => link_to(RELEASES_URL, 'Invoice Ninja', ['target' => '_blank']),
|
||||
];
|
||||
Session::put('news_feed_id', NEW_VERSION_AVAILABLE);
|
||||
Session::put('news_feed_message', trans('texts.new_version_available', $params));
|
||||
} else {
|
||||
|
@ -112,8 +112,8 @@ Route::group(['middleware' => 'auth'], function() {
|
||||
Route::get('products/{product_id}/archive', 'ProductController@archive');
|
||||
|
||||
Route::get('company/advanced_settings/data_visualizations', 'ReportController@d3');
|
||||
Route::get('company/advanced_settings/chart_builder', 'ReportController@report');
|
||||
Route::post('company/advanced_settings/chart_builder', 'ReportController@report');
|
||||
Route::get('company/advanced_settings/charts_and_reports', 'ReportController@showReports');
|
||||
Route::post('company/advanced_settings/charts_and_reports', 'ReportController@showReports');
|
||||
|
||||
Route::post('company/cancel_account', 'AccountController@cancelAccount');
|
||||
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_WEB_URL', 'https://www.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_FROM_EMAIL', 'maildelivery@invoiceninja.com');
|
||||
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('PRODUCT_ONE_CLICK_INSTALL', 1);
|
||||
|
@ -623,4 +623,17 @@ class Utils
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
@ -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
10
public/css/built.css
vendored
@ -3238,11 +3238,15 @@ div.checkbox > label {
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.dataTables_length {
|
||||
div.dataTables_length {
|
||||
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;
|
||||
}
|
10
public/css/style.css
vendored
10
public/css/style.css
vendored
@ -854,11 +854,15 @@ div.checkbox > label {
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.dataTables_length {
|
||||
div.dataTables_length {
|
||||
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;
|
||||
}
|
10
readme.md
10
readme.md
@ -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.
|
||||
|
||||
### 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
|
||||
|
||||
* Core application built using Laravel 5
|
||||
|
@ -637,5 +637,18 @@ return array(
|
||||
'www' => 'www',
|
||||
'logo' => 'Logo',
|
||||
'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>',
|
||||
|
||||
);
|
||||
|
@ -2,7 +2,7 @@
|
||||
{!! 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/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') !!}
|
||||
</ul>
|
||||
<p> </p>
|
||||
|
@ -13,7 +13,8 @@
|
||||
|
||||
|
||||
<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())
|
||||
{!! Button::primary(trans('texts.add_token'))->asLinkTo('/tokens/create')->appendIcon(Icon::create('plus-sign')) !!}
|
||||
@endif
|
||||
|
@ -215,7 +215,7 @@
|
||||
$(function() {
|
||||
window.setTimeout(function() {
|
||||
$(".alert-hide").fadeOut(500);
|
||||
}, 3000);
|
||||
}, 2000);
|
||||
|
||||
$('#search').focus(function(){
|
||||
if (!window.hasOwnProperty('searchData')) {
|
||||
|
@ -473,7 +473,7 @@
|
||||
</div>
|
||||
|
||||
<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> </span>
|
||||
<span class="error-block" id="emailError" style="display:none;float:left;font-weight:bold">{{ trans('texts.provide_name_or_email') }}</span><span> </span>
|
||||
<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 id="clientDoneButton" type="button" class="btn btn-primary" data-bind="click: $root.clientFormComplete">{{ trans('texts.done') }}</button>
|
||||
|
@ -10,8 +10,8 @@
|
||||
</div>
|
||||
|
||||
{!! DropdownButton::normal(trans('texts.archive'))->withContents([
|
||||
['label' => trans('texts.archive_'.$entityType), 'url' => "javascript:submitForm('archive')"],
|
||||
['label' => trans('texts.delete_'.$entityType), 'url' => "javascript:submitForm('delete')"],
|
||||
['label' => trans('texts.archive_'.$entityType), 'url' => 'javascript:submitForm("archive")'],
|
||||
['label' => trans('texts.delete_'.$entityType), 'url' => 'javascript:submitForm("delete")'],
|
||||
])->withAttributes(['class'=>'archive'])->split() !!}
|
||||
|
||||
<label for="trashed" style="font-weight:normal; margin-left: 10px;">
|
||||
|
206
resources/views/reports/chart_builder.blade.php
Normal file
206
resources/views/reports/chart_builder.blade.php
Normal 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> </p>
|
||||
<p> </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> </p>
|
||||
{!! Former::checkbox('enable_report')->text(trans('texts.enable')) !!}
|
||||
{!! Former::select('report_type')->options($reportTypes, $reportType)->label(trans('texts.group_by')) !!}
|
||||
|
||||
<p> </p>
|
||||
{!! Former::checkbox('enable_chart')->text(trans('texts.enable')) !!}
|
||||
{!! Former::select('chart_type')->options($chartTypes, $chartType) !!}
|
||||
{!! Former::select('group_by')->options($dateTypes, $groupBy) !!}
|
||||
|
||||
<p> </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> </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"> 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"> 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"> 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
|
@ -32,10 +32,6 @@
|
||||
@parent
|
||||
@include('accounts.nav_advanced')
|
||||
|
||||
{!! Former::open() !!}
|
||||
{!! Former::legend('data_visualizations') !!}
|
||||
{!! Former::close() !!}
|
||||
|
||||
<div id="tooltip" class="hidden">
|
||||
<p>
|
||||
<strong><span id="tooltipTitle"></span></strong>
|
||||
@ -48,7 +44,7 @@
|
||||
|
||||
<form class="form-inline" role="form">
|
||||
Group By
|
||||
<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>Invoices</option>
|
||||
<option>Products</option>
|
||||
|
@ -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> </p>
|
||||
<p> </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> </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"> 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"> 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"> 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
|
Loading…
Reference in New Issue
Block a user