mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-09 12:42:36 +01:00
Working on the calendar
This commit is contained in:
parent
52940b5242
commit
c472bf92c8
40
app/Http/Controllers/CalendarController.php
Normal file
40
app/Http/Controllers/CalendarController.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Jobs\GenerateCalendarEvents;
|
||||
|
||||
/**
|
||||
* Class ReportController.
|
||||
*/
|
||||
class CalendarController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function showCalendar()
|
||||
{
|
||||
if (! auth()->user()->hasPermission('view_all')) {
|
||||
return redirect('/');
|
||||
}
|
||||
|
||||
$data = [
|
||||
//'showBreadcrumbs' => false,
|
||||
];
|
||||
|
||||
return view('calendar', $data);
|
||||
}
|
||||
|
||||
public function loadEvents()
|
||||
{
|
||||
$events = dispatch(new GenerateCalendarEvents());
|
||||
//dd($events);
|
||||
\Log::info(print_r(request()->input(), true));
|
||||
\Log::info(print_r($events, true));
|
||||
//echo '[{"title": "Test Event", "start": "2017-09-14T16:00:00", "color": "green"}]';
|
||||
//exit;
|
||||
|
||||
return response()->json($events);
|
||||
}
|
||||
|
||||
}
|
@ -248,6 +248,8 @@ Route::group(['middleware' => ['lookup:user', 'auth:user']], function () {
|
||||
|
||||
Route::get('reports', 'ReportController@showReports');
|
||||
Route::post('reports', 'ReportController@showReports');
|
||||
Route::get('calendar', 'CalendarController@showCalendar');
|
||||
Route::get('calendar_events', 'CalendarController@loadEvents');
|
||||
});
|
||||
|
||||
Route::group([
|
||||
|
49
app/Jobs/GenerateCalendarEvents.php
Normal file
49
app/Jobs/GenerateCalendarEvents.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Jobs\Job;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Task;
|
||||
|
||||
class GenerateCalendarEvents extends Job
|
||||
{
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$data = [];
|
||||
|
||||
$invoices = Invoice::scope()
|
||||
->where('is_recurring', '=', false)
|
||||
->get();
|
||||
foreach ($invoices as $invoice) {
|
||||
$data[] = $invoice->present()->calendarEvent;
|
||||
}
|
||||
|
||||
$tasks = Task::scope()
|
||||
->get();
|
||||
foreach ($tasks as $task) {
|
||||
$data[] = $task->present()->calendarEvent;
|
||||
}
|
||||
|
||||
$payments = Payment::scope()
|
||||
->get();
|
||||
foreach ($payments as $payment) {
|
||||
$data[] = $payment->present()->calendarEvent;
|
||||
}
|
||||
|
||||
$expenses = Expense::scope()
|
||||
->get();
|
||||
foreach ($expenses as $expense) {
|
||||
$data[] = $expense->present()->calendarEvent;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ namespace App\Ninja\Presenters;
|
||||
use Laracasts\Presenter\Presenter;
|
||||
use URL;
|
||||
use Utils;
|
||||
use stdClass;
|
||||
|
||||
class EntityPresenter extends Presenter
|
||||
{
|
||||
@ -67,4 +68,17 @@ class EntityPresenter extends Presenter
|
||||
|
||||
return sprintf('%s: %s', trans('texts.' . $entityType), $entity->getDisplayName());
|
||||
}
|
||||
|
||||
public function calendarEvent()
|
||||
{
|
||||
$entity = $this->entity;
|
||||
|
||||
$data = new stdClass();
|
||||
$data->id = $entity->getEntityType() . ':' . $entity->public_id;
|
||||
$data->allDay = true;
|
||||
$data->url = $this->url();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -48,4 +48,26 @@ class ExpensePresenter extends EntityPresenter
|
||||
{
|
||||
return $this->entity->expense_category ? $this->entity->expense_category->name : '';
|
||||
}
|
||||
|
||||
public function calendarEvent()
|
||||
{
|
||||
$data = parent::calendarEvent();
|
||||
$expense = $this->entity;
|
||||
|
||||
$data->title = trans('texts.expense') . ' ' . $this->amount() . ' | ' . $this->category();
|
||||
|
||||
$data->title = trans('texts.expense') . ' ' . $this->amount();
|
||||
if ($category = $this->category()) {
|
||||
$data->title .= ' | ' . $category;
|
||||
}
|
||||
if ($this->public_notes) {
|
||||
$data->title .= ' | ' . $this->public_notes;
|
||||
}
|
||||
|
||||
|
||||
$data->start = $expense->expense_date;
|
||||
$data->borderColor = $data->backgroundColor = 'gray';
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
@ -323,4 +323,17 @@ class InvoicePresenter extends EntityPresenter
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
public function calendarEvent()
|
||||
{
|
||||
$data = parent::calendarEvent();
|
||||
$invoice = $this->entity;
|
||||
$entityType = $invoice->getEntityType();
|
||||
|
||||
$data->title = trans("texts.{$entityType}") . ' ' . $invoice->invoice_number . ' | ' . $this->amount() . ' | ' . $this->client();
|
||||
$data->start = $invoice->invoice_date;
|
||||
$data->borderColor = $data->backgroundColor = $invoice->isQuote() ? 'orange' : 'blue';
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
@ -45,4 +45,17 @@ class PaymentPresenter extends EntityPresenter
|
||||
return trans('texts.payment_type_' . $this->entity->payment_type->name);
|
||||
}
|
||||
}
|
||||
|
||||
public function calendarEvent()
|
||||
{
|
||||
$data = parent::calendarEvent();
|
||||
$payment = $this->entity;
|
||||
$invoice = $payment->invoice;
|
||||
|
||||
$data->title = trans('texts.payment') . ' ' . $invoice->invoice_number . ' | ' . $this->amount() . ' | ' . $this->client();
|
||||
$data->start = $payment->payment_date;
|
||||
$data->borderColor = $data->backgroundColor = 'green';
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
@ -70,4 +70,32 @@ class TaskPresenter extends EntityPresenter
|
||||
|
||||
return $str . implode("\n", $times);
|
||||
}
|
||||
|
||||
public function calendarEvent()
|
||||
{
|
||||
$data = parent::calendarEvent();
|
||||
$task = $this->entity;
|
||||
|
||||
$data->title = trans('texts.task');
|
||||
if ($project = $this->project()) {
|
||||
$data->title .= ' | ' . $project;
|
||||
}
|
||||
$data->title .= ' | ' . $this->description();
|
||||
|
||||
$data->allDay = false;
|
||||
$data->borderColor = $data->backgroundColor = 'purple';
|
||||
|
||||
$parts = json_decode($task->time_log) ?: [];
|
||||
if (count($parts)) {
|
||||
$first = $parts[0];
|
||||
$start = $first[0];
|
||||
$data->start = date('Y-m-d H:i:m', $start);
|
||||
|
||||
$last = $parts[count($parts) - 1];
|
||||
$end = count($last) == 2 ? $last[1] : $last[0];
|
||||
$data->end = date('Y-m-d H:i:m', $end);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,8 @@
|
||||
"select2": "select2-dist#^4.0.3",
|
||||
"mousetrap": "^1.6.0",
|
||||
"tablesorter": "jquery.tablesorter#^2.28.4",
|
||||
"card": "^2.1.1"
|
||||
"card": "^2.1.1",
|
||||
"fullcalendar": "^3.5.1"
|
||||
},
|
||||
"resolutions": {
|
||||
"jquery": "~1.11"
|
||||
|
@ -76,6 +76,10 @@ elixir(function(mix) {
|
||||
bowerDir + '/tablesorter/dist/css/widget.grouping.min.css'
|
||||
], 'public/css/tablesorter.css');
|
||||
|
||||
mix.styles([
|
||||
bowerDir + '/fullcalendar/dist/fullcalendar.css'
|
||||
], 'public/css/fullcalendar.css');
|
||||
|
||||
|
||||
/**
|
||||
* JS configuration
|
||||
@ -94,6 +98,10 @@ elixir(function(mix) {
|
||||
bowerDir + '/bootstrap-daterangepicker/daterangepicker.js'
|
||||
], 'public/js/daterangepicker.min.js');
|
||||
|
||||
mix.scripts([
|
||||
bowerDir + '/fullcalendar/dist/fullcalendar.js'
|
||||
], 'public/js/fullcalendar.min.js');
|
||||
|
||||
mix.scripts([
|
||||
bowerDir + '/card/dist/card.js',
|
||||
], 'public/js/card.min.js');
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6
public/css/fullcalendar.css
vendored
Normal file
6
public/css/fullcalendar.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/css/fullcalendar.css.map
Normal file
1
public/css/fullcalendar.css.map
Normal file
File diff suppressed because one or more lines are too long
7
public/js/fullcalendar.min.js
vendored
Normal file
7
public/js/fullcalendar.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/fullcalendar.min.js.map
Normal file
1
public/js/fullcalendar.min.js.map
Normal file
File diff suppressed because one or more lines are too long
@ -726,7 +726,7 @@ function calculateAmounts(invoice) {
|
||||
}
|
||||
|
||||
// calculate line item tax
|
||||
var lineTotal = roundToTwo(NINJA.parseFloat(item.cost)) * roundToTwo(NINJA.parseFloat(item.qty));
|
||||
var lineTotal = NINJA.parseFloat(item.cost) * NINJA.parseFloat(item.qty);
|
||||
if (invoice.discount != 0) {
|
||||
if (parseInt(invoice.is_amount_discount)) {
|
||||
lineTotal -= roundToTwo((lineTotal/total) * invoice.discount);
|
||||
|
@ -2445,6 +2445,7 @@ $LANG = array(
|
||||
'enable_sofort' => 'Accept EU bank transfers',
|
||||
'stripe_alipay_help' => 'These gateways also need to be activated in :link.',
|
||||
'gocardless_webhook_help_link_text' => 'add this URL as an endpoint in GoCardless',
|
||||
'calendar' => 'Calendar',
|
||||
|
||||
);
|
||||
|
||||
|
83
resources/views/calendar.blade.php
Normal file
83
resources/views/calendar.blade.php
Normal file
@ -0,0 +1,83 @@
|
||||
@extends('header')
|
||||
|
||||
@section('head')
|
||||
@parent
|
||||
|
||||
<script src="{{ asset('js/select2.min.js') }}" type="text/javascript"></script>
|
||||
<link href="{{ asset('css/select2.css') }}" rel="stylesheet" type="text/css"/>
|
||||
|
||||
<script src="{{ asset('js/fullcalendar.min.js') }}" type="text/javascript"></script>
|
||||
<link href="{{ asset('css/fullcalendar.css') }}" rel="stylesheet" type="text/css"/>
|
||||
|
||||
@stop
|
||||
|
||||
@section('top-right')
|
||||
<select class="form-control" style="width: 220px" id="entityTypeFilter" multiple="true">
|
||||
@foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, ENTITY_TASK, ENTITY_EXPENSE] as $value)
|
||||
<option value="{{ $value }}">{{ trans("texts.{$value}") }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@stop
|
||||
|
||||
@section('content')
|
||||
|
||||
<div id='calendar'></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$(function() {
|
||||
|
||||
// Setup state/status filter
|
||||
$('#entityTypeFilter').select2({
|
||||
placeholder: "{{ trans('texts.filter') }}",
|
||||
/*
|
||||
templateSelection: function(data, container) {
|
||||
if (data.id == 'archived') {
|
||||
$(container).css('color', '#fff');
|
||||
$(container).css('background-color', '#f0ad4e');
|
||||
$(container).css('border-color', '#eea236');
|
||||
}
|
||||
return data.text;
|
||||
}
|
||||
*/
|
||||
}).on('change', function() {
|
||||
/*
|
||||
var filter = $('#statuses').val();
|
||||
if (filter) {
|
||||
filter = filter.join(',');
|
||||
} else {
|
||||
filter = '';
|
||||
}
|
||||
*/
|
||||
}).maximizeSelect2Height();
|
||||
|
||||
|
||||
$('#calendar').fullCalendar({
|
||||
header: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'month,basicWeek,basicDay,listWeek'
|
||||
},
|
||||
defaultDate: '{{ date('Y-m-d') }}',
|
||||
//navLinks: true,
|
||||
//editable: true,
|
||||
eventLimit: true,
|
||||
events: {
|
||||
url: '{{ url('/calendar_events') }}',
|
||||
type: 'GET',
|
||||
data: {
|
||||
custom_param1: 'something',
|
||||
custom_param2: 'somethingelse'
|
||||
},
|
||||
error: function() {
|
||||
alert('there was an error while fetching events!');
|
||||
},
|
||||
color: 'red', // a non-ajax option
|
||||
textColor: 'white' // a non-ajax option
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@stop
|
@ -448,6 +448,10 @@
|
||||
<div class="alert alert-danger">{!! Session::get('error') !!}</div>
|
||||
@endif
|
||||
|
||||
<div class="pull-right">
|
||||
@yield('top-right')
|
||||
</div>
|
||||
|
||||
@if (!isset($showBreadcrumbs) || $showBreadcrumbs)
|
||||
{!! Form::breadcrumbs((isset($entity) && $entity->exists) ? $entity->present()->statusLabel : false) !!}
|
||||
@endif
|
||||
|
Loading…
Reference in New Issue
Block a user