mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Recurring Invoice ListView
This commit is contained in:
parent
03d67bbb52
commit
0892993afe
@ -11,7 +11,6 @@
|
||||
|
||||
namespace App\Http\Controllers\ClientPortal;
|
||||
|
||||
use App\Filters\InvoiceFilters;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
@ -37,19 +36,24 @@ class RecurringInvoiceController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(InvoiceFilters $filters, Builder $builder)
|
||||
public function index(Builder $builder)
|
||||
{
|
||||
$invoices = Invoice::filter($filters);
|
||||
$invoices = RecurringInvoice::whereClientId(auth()->user()->client->id)
|
||||
->whereIn('status_id', [RecurringInvoice::STATUS_PENDING, RecurringInvoice::STATUS_ACTIVE, RecurringInvoice::STATUS_COMPLETED])
|
||||
->orderBy('status_id', 'asc')
|
||||
->get();
|
||||
|
||||
if (request()->ajax()) {
|
||||
|
||||
return DataTables::of($invoices)->addColumn('action', function ($invoice) {
|
||||
return '<a href="/client/recurring_invoices/'. $invoice->hashed_id .'/edit" class="btn btn-xs btn-primary"><i class="glyphicon glyphicon-edit"></i>'.ctrans('texts.view').'</a>';
|
||||
})->addColumn('frequency_id', function ($invoice) {
|
||||
return RecurringInvoice::frequencyForKey($invoice->frequency_id);
|
||||
})
|
||||
->editColumn('status_id', function ($invoice){
|
||||
return Invoice::badgeForStatus($invoice->status);
|
||||
return RecurringInvoice::badgeForStatus($invoice->status);
|
||||
})
|
||||
->rawColumns(['checkbox', 'action', 'status_id'])
|
||||
->rawColumns(['action', 'status_id'])
|
||||
->make(true);
|
||||
|
||||
}
|
||||
|
@ -31,9 +31,9 @@ class RecurringInvoice extends BaseModel
|
||||
*/
|
||||
const STATUS_DRAFT = 2;
|
||||
const STATUS_ACTIVE = 3;
|
||||
const STATUS_CANCELLED = 4;
|
||||
const STATUS_PENDING = -1;
|
||||
const STATUS_COMPLETED = -2;
|
||||
const STATUS_CANCELLED = -3;
|
||||
|
||||
|
||||
/**
|
||||
@ -85,9 +85,9 @@ class RecurringInvoice extends BaseModel
|
||||
'line_items' => 'object',
|
||||
];
|
||||
|
||||
protected $with = [
|
||||
// 'client',
|
||||
// 'company',
|
||||
protected $appends = [
|
||||
'hashed_id',
|
||||
'status'
|
||||
];
|
||||
|
||||
public function company()
|
||||
@ -110,30 +110,42 @@ class RecurringInvoice extends BaseModel
|
||||
$this->morphMany(RecurringInvoiceInvitation::class);
|
||||
}
|
||||
|
||||
public function getStatusAttribute()
|
||||
{
|
||||
|
||||
if($this->status_id == RecurringInvoice::STATUS_ACTIVE && $this->start_date > Carbon::now()) //marked as active, but yet to fire first cycle
|
||||
return RecurringInvoice::STATUS_PENDING;
|
||||
else if($this->status_id == RecurringInvoice::STATUS_ACTIVE && $this->next_send_date > Carbon::now())
|
||||
return RecurringInvoice::STATUS_COMPLETED;
|
||||
else
|
||||
return $this->status_id;
|
||||
|
||||
}
|
||||
|
||||
public function nextSendDate() :?Carbon
|
||||
{
|
||||
|
||||
switch ($this->frequency_id)
|
||||
{
|
||||
case FREQUENCY_WEEKLY:
|
||||
case RecurringInvoice::FREQUENCY_WEEKLY:
|
||||
return Carbon::parse($this->next_send_date->addWeek());
|
||||
case FREQUENCY_TWO_WEEKS:
|
||||
case RecurringInvoice::FREQUENCY_TWO_WEEKS:
|
||||
return Carbon::parse($this->next_send_date->addWeeks(2));
|
||||
case FREQUENCY_FOUR_WEEKS:
|
||||
case RecurringInvoice::FREQUENCY_FOUR_WEEKS:
|
||||
return Carbon::parse($this->next_send_date->addWeeks(4));
|
||||
case FREQUENCY_MONTHLY:
|
||||
case RecurringInvoice::FREQUENCY_MONTHLY:
|
||||
return Carbon::parse($this->next_send_date->addMonth());
|
||||
case FREQUENCY_TWO_MONTHS:
|
||||
case RecurringInvoice::FREQUENCY_TWO_MONTHS:
|
||||
return Carbon::parse($this->next_send_date->addMonths(2));
|
||||
case FREQUENCY_THREE_MONTHS:
|
||||
case RecurringInvoice::FREQUENCY_THREE_MONTHS:
|
||||
return Carbon::parse($this->next_send_date->addMonths(3));
|
||||
case FREQUENCY_FOUR_MONTHS:
|
||||
case RecurringInvoice::FREQUENCY_FOUR_MONTHS:
|
||||
return Carbon::parse($this->next_send_date->addMonths(4));
|
||||
case FREQUENCY_SIX_MONTHS:
|
||||
case RecurringInvoice::FREQUENCY_SIX_MONTHS:
|
||||
return Carbon::parse($this->next_send_date->addMonths(6));
|
||||
case FREQUENCY_ANNUALLY:
|
||||
case RecurringInvoice::FREQUENCY_ANNUALLY:
|
||||
return Carbon::parse($this->next_send_date->addYear());
|
||||
case FREQUENCY_TWO_YEARS:
|
||||
case RecurringInvoice::FREQUENCY_TWO_YEARS:
|
||||
return Carbon::parse($this->next_send_date->addYears(2));
|
||||
default:
|
||||
return null;
|
||||
@ -160,4 +172,71 @@ class RecurringInvoice extends BaseModel
|
||||
$this->save();
|
||||
|
||||
}
|
||||
|
||||
public static function badgeForStatus(int $status)
|
||||
{
|
||||
switch ($status) {
|
||||
case RecurringInvoice::STATUS_DRAFT:
|
||||
return '<h4><span class="badge badge-light">'.ctrans('texts.draft').'</span></h4>';
|
||||
break;
|
||||
case RecurringInvoice::STATUS_PENDING:
|
||||
return '<h4><span class="badge badge-primary">'.ctrans('texts.sent').'</span></h4>';
|
||||
break;
|
||||
case RecurringInvoice::STATUS_ACTIVE:
|
||||
return '<h4><span class="badge badge-primary">'.ctrans('texts.partial').'</span></h4>';
|
||||
break;
|
||||
case RecurringInvoice::STATUS_COMPLETED:
|
||||
return '<h4><span class="badge badge-success">'.ctrans('texts.status_completed').'</span></h4>';
|
||||
break;
|
||||
case RecurringInvoice::STATUS_CANCELLED:
|
||||
return '<h4><span class="badge badge-danger">'.ctrans('texts.overdue').'</span></h4>';
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static function frequencyForKey(int $frequency_id) :string
|
||||
{
|
||||
switch ($frequency_id) {
|
||||
case RecurringInvoice::FREQUENCY_WEEKLY:
|
||||
return ctrans('texts.freq_weekly');
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_TWO_WEEKS:
|
||||
return ctrans('texts.freq_two_weeks');
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_FOUR_WEEKS:
|
||||
return ctrans('texts.freq_four_weeks');
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_MONTHLY:
|
||||
return ctrans('texts.freq_monthly');
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_TWO_MONTHS:
|
||||
return ctrans('texts.freq_two_months');
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_THREE_MONTHS:
|
||||
return ctrans('texts.freq_three_months');
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_FOUR_MONTHS:
|
||||
return ctrans('texts.freq_four_months');
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_SIX_MONTHS:
|
||||
return ctrans('texts.freq_six_months');
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_ANNUALLY:
|
||||
return ctrans('texts.freq_annually');
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_TWO_YEARS:
|
||||
return ctrans('texts.freq_two_years');
|
||||
break;
|
||||
case RecurringInvoice::RECURS_INDEFINITELY:
|
||||
return ctrans('texts.freq_indefinitely');
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use Faker\Generator as Faker;
|
||||
|
||||
$factory->define(App\Models\RecurringInvoice::class, function (Faker $faker) {
|
||||
return [
|
||||
'status_id' => App\Models\RecurringInvoice::STATUS_PENDING,
|
||||
'status_id' => App\Models\RecurringInvoice::STATUS_ACTIVE,
|
||||
'discount' => $faker->numberBetween(1,10),
|
||||
'is_amount_discount' => $faker->boolean(),
|
||||
'tax_name1' => 'GST',
|
||||
@ -28,5 +28,7 @@ $factory->define(App\Models\RecurringInvoice::class, function (Faker $faker) {
|
||||
'last_sent_date' => $faker->date(),
|
||||
'next_send_date' => $faker->date(),
|
||||
'remaining_cycles' => $faker->numberBetween(1,10),
|
||||
'amount' => $faker->randomFloat(2, $min = 1, $max = 1000) // 48.8932
|
||||
|
||||
];
|
||||
});
|
@ -468,7 +468,7 @@ class CreateUsersTable extends Migration
|
||||
$t->datetime('last_viewed')->nullable();
|
||||
|
||||
$t->unsignedInteger('frequency_id');
|
||||
$t->date('start_date')->nullable();
|
||||
$t->datetime('start_date')->nullable();
|
||||
$t->datetime('last_sent_date')->nullable();
|
||||
$t->datetime('next_send_date')->nullable();
|
||||
$t->unsignedInteger('remaining_cycles')->nullable();
|
||||
|
@ -98,11 +98,16 @@ class RandomDataSeeder extends Seeder
|
||||
/** Invoice Factory */
|
||||
factory(\App\Models\Invoice::class,500)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]);
|
||||
|
||||
/** Recurring Invoice Factory */
|
||||
factory(\App\Models\RecurringInvoice::class,20)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]);
|
||||
|
||||
|
||||
$clients = Client::all();
|
||||
|
||||
foreach($clients as $client)
|
||||
{
|
||||
$client->getNextClientNumber($client);
|
||||
//$client->getNextClientNumber($client);
|
||||
$client->id_number = $client->getNextClientNumber($client);
|
||||
$client->save();
|
||||
}
|
||||
|
||||
|
@ -3105,6 +3105,9 @@ $LANG = array(
|
||||
'email_already_register' => 'This email is already linked to an account',
|
||||
'create_account' => 'Create Account',
|
||||
'locations' => 'Locations',
|
||||
'freq_indefinitely' => 'Indefinitely',
|
||||
'next_send_date' => 'Next send date',
|
||||
'cycles_remaining' => 'Cycles remaining',
|
||||
);
|
||||
|
||||
return $LANG;
|
||||
|
@ -0,0 +1,82 @@
|
||||
@extends('portal.default.layouts.master')
|
||||
@section('header')
|
||||
@parent
|
||||
<link href="//cdn.datatables.net/1.10.19/css/dataTables.bootstrap4.min.css" rel="stylesheet" type="text/css"/>
|
||||
@stop
|
||||
@section('body')
|
||||
<main class="main">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row" style="padding-top: 30px;">
|
||||
|
||||
<div class="col-lg-12" style="padding-bottom: 10px;">
|
||||
|
||||
<div class="animated fadeIn">
|
||||
<div class="col-md-12 card">
|
||||
|
||||
{!! $html->table(['class' => 'table table-hover table-striped', 'id' => 'datatable'], true) !!}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
@endsection
|
||||
@push('scripts')
|
||||
<script src="//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js" type="text/javascript"></script>
|
||||
<script src="//cdn.datatables.net/1.10.18/js/dataTables.bootstrap4.min.js"></script>
|
||||
@endpush
|
||||
@section('footer')
|
||||
<script>
|
||||
|
||||
/*global json payload*/
|
||||
var data;
|
||||
|
||||
var data_table;
|
||||
|
||||
$(function() {
|
||||
|
||||
data_table = $('#datatable').DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
searching: false,
|
||||
bLengthChange: false,
|
||||
language: {
|
||||
processing: " {{ trans('texts.processing_request') }}",
|
||||
search: "{{ trans('texts.search') }}:",
|
||||
// info: "{{ trans('texts.info') }}",
|
||||
infoPostFix: "",
|
||||
loadingRecords: "{{ trans('texts.loading') }}",
|
||||
zeroRecords: "{{ trans('texts.no_records_found') }}"
|
||||
},
|
||||
ajax: {
|
||||
url: '{!! route('client.recurring_invoices.index') !!}',
|
||||
data: function(data) {
|
||||
}
|
||||
|
||||
},
|
||||
drawCallback: function(settings){
|
||||
|
||||
data = this.api().ajax.json().data;
|
||||
|
||||
},
|
||||
columns: [
|
||||
|
||||
{data: 'frequency_id', name: 'frequency_id', title: '{{trans('texts.frequency')}}', visible: true},
|
||||
{data: 'start_date', name: 'start_date', title: '{{trans('texts.start_date')}}', visible: true},
|
||||
{data: 'next_send_date', name: 'next_send_date', title: '{{trans('texts.next_send_date')}}', visible: true},
|
||||
{data: 'remaining_cycles', name: 'remaining_cycles', title: '{{trans('texts.cycles_remaining')}}', visible: true},
|
||||
{data: 'amount', name: 'amount', title: '{{trans('texts.amount')}}', visible: true},
|
||||
{data: 'action', name: 'action', title: '', searchable: false, orderable: false},
|
||||
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
@endsection
|
||||
|
@ -15,9 +15,13 @@ Route::post('client/password/reset', 'Auth\ContactResetPasswordController@reset'
|
||||
Route::group(['middleware' => ['auth:contact'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
||||
|
||||
Route::get('dashboard', 'ClientPortal\DashboardController@index')->name('dashboard'); // name = (dashboard. index / create / show / update / destroy / edit
|
||||
|
||||
Route::get('invoices', 'ClientPortal\InvoiceController@index')->name('invoices.index');
|
||||
Route::get('recurring_invoices', 'ClientPortal\RecurringInvoiceController@index')->name('recurring_invoices.index');
|
||||
Route::post('invoices/payment', 'ClientPortal\InvoiceController@bulk')->name('invoices.bulk');
|
||||
|
||||
Route::get('recurring_invoices', 'ClientPortal\RecurringInvoiceController@index')->name('recurring_invoices.index');
|
||||
|
||||
|
||||
Route::get('profile/{client_contact}/edit', 'ClientPortal\ProfileController@edit')->name('profile.edit');
|
||||
Route::put('profile/{client_contact}/edit', 'ClientPortal\ProfileController@update')->name('profile.update');
|
||||
Route::put('profile/{client_contact}/edit_client', 'ClientPortal\ProfileController@updateClient')->name('profile.edit_client');
|
||||
|
Loading…
x
Reference in New Issue
Block a user