Added: Expense Module
This commit is contained in:
parent
e76bcf2dde
commit
f12b52f6e7
|
@ -13,7 +13,7 @@ class Adjustment extends Model
|
|||
protected $guarded = [];
|
||||
|
||||
public function getDateAttribute($value) {
|
||||
return Carbon::parse($value)->format('M d, Y');
|
||||
return Carbon::parse($value)->format('d M, Y');
|
||||
}
|
||||
|
||||
public function adjustedProducts() {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateExpenseCategoriesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('expense_categories', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('category_name');
|
||||
$table->text('category_description')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('expense_categories');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateExpensesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('expenses', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('category_id');
|
||||
$table->date('date');
|
||||
$table->string('reference');
|
||||
$table->text('details')->nullable();
|
||||
$table->integer('amount');
|
||||
$table->foreign('category_id')->references('id')->on('expense_categories')->restrictOnDelete();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('expenses');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace Modules\Expense\Entities;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class Expense extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
public function category() {
|
||||
return $this->belongsTo(ExpenseCategory::class, 'category_id', 'id');
|
||||
}
|
||||
|
||||
public function getDateAttribute($value) {
|
||||
return Carbon::parse($value)->format('d M, Y');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Modules\Expense\Entities;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
class ExpenseCategory extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
public function expenses() {
|
||||
return $this->hasMany(Expense::class, 'category_id', 'id');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Modules\Expense\Http\Controllers;
|
||||
|
||||
use App\DataTables\ExpenseCategoriesDataTable;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Modules\Expense\Entities\ExpenseCategory;
|
||||
|
||||
class ExpenseCategoriesController extends Controller
|
||||
{
|
||||
|
||||
public function index(ExpenseCategoriesDataTable $dataTable) {
|
||||
abort_if(Gate::denies('access_expense_categories'), 403);
|
||||
|
||||
return $dataTable->render('expense::categories.index');
|
||||
}
|
||||
|
||||
public function store(Request $request) {
|
||||
abort_if(Gate::denies('access_expense_categories'), 403);
|
||||
|
||||
$request->validate([
|
||||
'category_name' => 'required|string|max:255|unique:expense_categories,category_name',
|
||||
'category_description' => 'nullable|string|max:1000'
|
||||
]);
|
||||
|
||||
ExpenseCategory::create([
|
||||
'category_name' => $request->category_name,
|
||||
'category_description' => $request->category_description
|
||||
]);
|
||||
|
||||
toast('Expense Category Created!', 'success');
|
||||
|
||||
return redirect()->route('expense-categories.index');
|
||||
}
|
||||
|
||||
|
||||
public function edit(ExpenseCategory $expenseCategory) {
|
||||
abort_if(Gate::denies('access_expense_categories'), 403);
|
||||
|
||||
return view('expense::categories.edit', compact('expenseCategory'));
|
||||
}
|
||||
|
||||
|
||||
public function update(Request $request, ExpenseCategory $expenseCategory) {
|
||||
abort_if(Gate::denies('access_expense_categories'), 403);
|
||||
|
||||
$request->validate([
|
||||
'category_name' => 'required|string|max:255|unique:expense_categories,category_name,' . $expenseCategory->id,
|
||||
'category_description' => 'nullable|string|max:1000'
|
||||
]);
|
||||
|
||||
$expenseCategory->update([
|
||||
'category_name' => $request->category_name,
|
||||
'category_description' => $request->category_description
|
||||
]);
|
||||
|
||||
toast('Expense Category Updated!', 'info');
|
||||
|
||||
return redirect()->route('expense-categories.index');
|
||||
}
|
||||
|
||||
|
||||
public function destroy(ExpenseCategory $expenseCategory) {
|
||||
abort_if(Gate::denies('access_expense_categories'), 403);
|
||||
|
||||
if ($expenseCategory->expenses()->isNotEmpty()) {
|
||||
return back()->withErrors('Can\'t delete beacuse there are expenses associated with this category.');
|
||||
}
|
||||
|
||||
$expenseCategory->delete();
|
||||
|
||||
toast('Expense Category Deleted!', 'warning');
|
||||
|
||||
return redirect()->route('expense-categories.index');
|
||||
}
|
||||
}
|
|
@ -2,78 +2,82 @@
|
|||
|
||||
namespace Modules\Expense\Http\Controllers;
|
||||
|
||||
use App\DataTables\ExpensesDataTable;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Modules\Expense\Entities\Expense;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Exp;
|
||||
|
||||
class ExpenseController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('expense::index');
|
||||
|
||||
public function index(ExpensesDataTable $dataTable) {
|
||||
return $dataTable->render('expense::expenses.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('expense::create');
|
||||
|
||||
public function create() {
|
||||
return view('expense::expenses.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
* @param Request $request
|
||||
* @return Renderable
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
|
||||
public function store(Request $request) {
|
||||
$request->validate([
|
||||
'date' => 'required|date',
|
||||
'reference' => 'required|string|max:255|unique:expenses,reference',
|
||||
'category_id' => 'required',
|
||||
'amount' => 'required|integer',
|
||||
'details' => 'nullable|string|max:1000'
|
||||
]);
|
||||
|
||||
Expense::create([
|
||||
'date' => $request->date,
|
||||
'reference' => $request->reference,
|
||||
'category_id' => $request->category_id,
|
||||
'amount' => $request->amount,
|
||||
'details' => $request->details
|
||||
]);
|
||||
|
||||
toast('Expense Created!', 'success');
|
||||
|
||||
return redirect()->route('expenses.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
return view('expense::show');
|
||||
|
||||
public function edit(Expense $expense) {
|
||||
return view('expense::expenses.edit', compact('expense'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
return view('expense::edit');
|
||||
|
||||
public function update(Request $request, Expense $expense) {
|
||||
$request->validate([
|
||||
'date' => 'required|date',
|
||||
'reference' => 'required|string|max:255|unique:expenses,reference,' . $expense->id,
|
||||
'category_id' => 'required',
|
||||
'amount' => 'required|integer',
|
||||
'details' => 'nullable|string|max:1000'
|
||||
]);
|
||||
|
||||
$expense->update([
|
||||
'date' => $request->date,
|
||||
'reference' => $request->reference,
|
||||
'category_id' => $request->category_id,
|
||||
'amount' => $request->amount,
|
||||
'details' => $request->details
|
||||
]);
|
||||
|
||||
toast('Expense Updated!', 'info');
|
||||
|
||||
return redirect()->route('expenses.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
//
|
||||
public function destroy(Expense $expense) {
|
||||
$expense->delete();
|
||||
|
||||
toast('Expense Deleted!', 'warning');
|
||||
|
||||
return redirect()->route('expenses.index');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Edit Expense Category')
|
||||
|
||||
@section('breadcrumb')
|
||||
<ol class="breadcrumb border-0 m-0">
|
||||
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ route('expenses.index') }}">Expenses</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ route('expense-categories.index') }}">Categories</a></li>
|
||||
<li class="breadcrumb-item active">Edit</li>
|
||||
</ol>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-7">
|
||||
@include('utils.alerts')
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form action="{{ route('expense-categories.update', $expenseCategory) }}" method="POST">
|
||||
@csrf
|
||||
@method('patch')
|
||||
<div class="form-group">
|
||||
<label for="category_name">Category Name <span class="text-danger">*</span></label>
|
||||
<input class="form-control" type="text" name="category_name" required value="{{ $expenseCategory->category_name }}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="category_description">Description</label>
|
||||
<textarea class="form-control" name="category_description" id="category_description" rows="5">{{ $expenseCategory->category_description }}</textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">Update <i class="bi bi-check"></i></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Expense Categories')
|
||||
|
||||
@section('third_party_stylesheets')
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.25/css/dataTables.bootstrap4.min.css">
|
||||
@endsection
|
||||
|
||||
@section('breadcrumb')
|
||||
<ol class="breadcrumb border-0 m-0">
|
||||
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ route('expenses.index') }}">Expenses</a></li>
|
||||
<li class="breadcrumb-item active">Categories</li>
|
||||
</ol>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
@include('utils.alerts')
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<!-- Button trigger modal -->
|
||||
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#categoryCreateModal">
|
||||
Add Category <i class="bi bi-plus"></i>
|
||||
</button>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="table-responsive">
|
||||
{!! $dataTable->table() !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Create Modal -->
|
||||
<div class="modal fade" id="categoryCreateModal" tabindex="-1" role="dialog" aria-labelledby="categoryCreateModal" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="categoryCreateModalLabel">Create Category</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form action="{{ route('expense-categories.store') }}" method="POST">
|
||||
@csrf
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="category_name">Category Name <span class="text-danger">*</span></label>
|
||||
<input class="form-control" type="text" name="category_name" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="category_description">Description</label>
|
||||
<textarea class="form-control" name="category_description" id="category_description" rows="5"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Create <i class="bi bi-check"></i></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('page_scripts')
|
||||
{!! $dataTable->scripts() !!}
|
||||
@endpush
|
|
@ -0,0 +1,15 @@
|
|||
<a href="{{ route('expense-categories.edit', $data->id) }}" class="btn btn-info btn-sm">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<button id="delete" class="btn btn-danger btn-sm" onclick="
|
||||
event.preventDefault();
|
||||
if (confirm('Are you sure? It will delete the data permanently!')) {
|
||||
document.getElementById('destroy{{ $data->id }}').submit();
|
||||
}
|
||||
">
|
||||
<i class="bi bi-trash"></i>
|
||||
<form id="destroy{{ $data->id }}" class="d-none" action="{{ route('expense-categories.destroy', $data->id) }}" method="POST">
|
||||
@csrf
|
||||
@method('delete')
|
||||
</form>
|
||||
</button>
|
|
@ -0,0 +1,73 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Create Expense')
|
||||
|
||||
@section('breadcrumb')
|
||||
<ol class="breadcrumb border-0 m-0">
|
||||
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ route('expenses.index') }}">Expenses</a></li>
|
||||
<li class="breadcrumb-item active">Add</li>
|
||||
</ol>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<form action="{{ route('expenses.store') }}" method="POST">
|
||||
@csrf
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
@include('utils.alerts')
|
||||
<div class="form-group">
|
||||
<button class="btn btn-primary">Create Expense <i class="bi bi-check"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="form-row">
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="reference">Reference <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" name="reference" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="date">Date <span class="text-danger">*</span></label>
|
||||
<input type="date" class="form-control" name="date" required value="{{ \Carbon\Carbon::now()->format('Y-m-d') }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="category_id">Category <span class="text-danger">*</span></label>
|
||||
<select name="category_id" id="category_id" class="form-control" required>
|
||||
<option value="" selected>Select Category</option>
|
||||
@foreach(\Modules\Expense\Entities\ExpenseCategory::all() as $category)
|
||||
<option value="{{ $category->id }}">{{ $category->category_name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="amount">Amount <span class="text-danger">*</span></label>
|
||||
<input type="number" class="form-control" name="amount" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="details">Details</label>
|
||||
<textarea class="form-control" rows="6" name="details"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Create Expense')
|
||||
|
||||
@section('breadcrumb')
|
||||
<ol class="breadcrumb border-0 m-0">
|
||||
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ route('expenses.index') }}">Expenses</a></li>
|
||||
<li class="breadcrumb-item active">Edit</li>
|
||||
</ol>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<form action="{{ route('expenses.update', $expense) }}" method="POST">
|
||||
@csrf
|
||||
@method('patch')
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
@include('utils.alerts')
|
||||
<div class="form-group">
|
||||
<button class="btn btn-primary">Update Expense <i class="bi bi-check"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="form-row">
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="reference">Reference <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" name="reference" required value="{{ $expense->reference }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="date">Date <span class="text-danger">*</span></label>
|
||||
<input type="date" class="form-control" name="date" required value="{{ $expense->getAttributes()['date'] }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="category_id">Category <span class="text-danger">*</span></label>
|
||||
<select name="category_id" id="category_id" class="form-control" required>
|
||||
@foreach(\Modules\Expense\Entities\ExpenseCategory::all() as $category)
|
||||
<option {{ $category->id == $expense->category_id ? 'selected' : '' }} value="{{ $category->id }}">{{ $category->category_name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="amount">Amount <span class="text-danger">*</span></label>
|
||||
<input type="number" class="form-control" name="amount" required value="{{ $expense->amount }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="details">Details</label>
|
||||
<textarea class="form-control" rows="6" name="details">
|
||||
{{ $expense->details }}
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Expenses')
|
||||
|
||||
@section('third_party_stylesheets')
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.25/css/dataTables.bootstrap4.min.css">
|
||||
@endsection
|
||||
|
||||
@section('breadcrumb')
|
||||
<ol class="breadcrumb border-0 m-0">
|
||||
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
|
||||
<li class="breadcrumb-item active">Expenses</li>
|
||||
</ol>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<a href="{{ route('expenses.create') }}" class="btn btn-primary">
|
||||
Add Expense <i class="bi bi-plus"></i>
|
||||
</a>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="table-responsive">
|
||||
{!! $dataTable->table() !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('page_scripts')
|
||||
{!! $dataTable->scripts() !!}
|
||||
@endpush
|
|
@ -0,0 +1,15 @@
|
|||
<a href="{{ route('expenses.edit', $data->id) }}" class="btn btn-info btn-sm">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<button id="delete" class="btn btn-danger btn-sm" onclick="
|
||||
event.preventDefault();
|
||||
if (confirm('Are you sure? It will delete the data permanently!')) {
|
||||
document.getElementById('destroy{{ $data->id }}').submit();
|
||||
}
|
||||
">
|
||||
<i class="bi bi-trash"></i>
|
||||
<form id="destroy{{ $data->id }}" class="d-none" action="{{ route('expenses.destroy', $data->id) }}" method="POST">
|
||||
@csrf
|
||||
@method('delete')
|
||||
</form>
|
||||
</button>
|
|
@ -1,9 +0,0 @@
|
|||
@extends('expense::layouts.master')
|
||||
|
||||
@section('content')
|
||||
<h1>Hello World</h1>
|
||||
|
||||
<p>
|
||||
This view is loaded from module: {!! config('expense.name') !!}
|
||||
</p>
|
||||
@endsection
|
|
@ -1,19 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Module Expense</title>
|
||||
|
||||
{{-- Laravel Mix - CSS File --}}
|
||||
{{-- <link rel="stylesheet" href="{{ mix('css/expense.css') }}"> --}}
|
||||
|
||||
</head>
|
||||
<body>
|
||||
@yield('content')
|
||||
|
||||
{{-- Laravel Mix - JS File --}}
|
||||
{{-- <script src="{{ mix('js/expense.js') }}"></script> --}}
|
||||
</body>
|
||||
</html>
|
|
@ -11,6 +11,11 @@
|
|||
|
|
||||
*/
|
||||
|
||||
Route::prefix('expense')->group(function() {
|
||||
Route::get('/', 'ExpenseController@index');
|
||||
Route::group(['middleware' => 'auth'], function () {
|
||||
|
||||
//Expense Category
|
||||
Route::resource('expense-categories', 'ExpenseCategoriesController')->except('show', 'create');
|
||||
//Expense
|
||||
Route::resource('expenses', 'ExpenseController')->except('show');
|
||||
|
||||
});
|
||||
|
|
|
@ -71,7 +71,7 @@ class CategoriesController extends Controller
|
|||
|
||||
$category = Category::findOrFail($id);
|
||||
|
||||
if ($category->products->isNotEmpty()) {
|
||||
if ($category->products()->isNotEmpty()) {
|
||||
return back()->withErrors('Can\'t delete beacuse there are products associated with this category.');
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form action="" method="POST">
|
||||
<form action="{{ route('product-categories.store') }}" method="POST">
|
||||
@csrf
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
|
|
|
@ -28,6 +28,11 @@ class PermissionsTableSeeder extends Seeder
|
|||
'delete_products',
|
||||
'access_product_categories',
|
||||
'print_barcodes',
|
||||
'access_adjustments',
|
||||
'create_adjustments',
|
||||
'show_adjustments',
|
||||
'edit_adjustments',
|
||||
'delete_adjustments',
|
||||
];
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
|
|
|
@ -11,14 +11,8 @@ use Yajra\DataTables\Services\DataTable;
|
|||
|
||||
class AdjustmentsDataTable extends DataTable
|
||||
{
|
||||
/**
|
||||
* Build DataTable class.
|
||||
*
|
||||
* @param mixed $query Results from query() method.
|
||||
* @return \Yajra\DataTables\DataTableAbstract
|
||||
*/
|
||||
public function dataTable($query)
|
||||
{
|
||||
|
||||
public function dataTable($query) {
|
||||
return datatables()
|
||||
->eloquent($query)
|
||||
->addColumn('action', function ($data) {
|
||||
|
@ -26,24 +20,11 @@ class AdjustmentsDataTable extends DataTable
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query source of dataTable.
|
||||
*
|
||||
* @param \Modules\Adjustment\Entities\Adjustment $model
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function query(Adjustment $model)
|
||||
{
|
||||
public function query(Adjustment $model) {
|
||||
return $model->newQuery()->withCount('adjustedProducts');
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional method if you want to use html builder.
|
||||
*
|
||||
* @return \Yajra\DataTables\Html\Builder
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
public function html() {
|
||||
return $this->builder()
|
||||
->setTableId('adjustments-table')
|
||||
->columns($this->getColumns())
|
||||
|
@ -64,13 +45,7 @@ class AdjustmentsDataTable extends DataTable
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get columns.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getColumns()
|
||||
{
|
||||
protected function getColumns() {
|
||||
return [
|
||||
Column::make('date')
|
||||
->className('text-center align-middle'),
|
||||
|
@ -89,13 +64,7 @@ class AdjustmentsDataTable extends DataTable
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename for export.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function filename()
|
||||
{
|
||||
protected function filename() {
|
||||
return 'Adjustments_' . date('YmdHis');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace App\DataTables;
|
||||
|
||||
use Modules\Expense\Entities\ExpenseCategory;
|
||||
use Yajra\DataTables\Html\Button;
|
||||
use Yajra\DataTables\Html\Column;
|
||||
use Yajra\DataTables\Html\Editor\Editor;
|
||||
use Yajra\DataTables\Html\Editor\Fields;
|
||||
use Yajra\DataTables\Services\DataTable;
|
||||
|
||||
class ExpenseCategoriesDataTable extends DataTable
|
||||
{
|
||||
|
||||
public function dataTable($query) {
|
||||
return datatables()
|
||||
->eloquent($query)
|
||||
->addColumn('action', function ($data) {
|
||||
return view('expense::categories.partials.actions', compact('data'));
|
||||
});
|
||||
}
|
||||
|
||||
public function query(ExpenseCategory $model) {
|
||||
return $model->newQuery()->withCount('expenses');
|
||||
}
|
||||
|
||||
public function html() {
|
||||
return $this->builder()
|
||||
->setTableId('expensecategories-table')
|
||||
->columns($this->getColumns())
|
||||
->minifiedAjax()
|
||||
->dom("<'row'<'col-md-3'l><'col-md-5 mb-2'B><'col-md-4'f>> .
|
||||
'tr' .
|
||||
<'row'<'col-md-5'i><'col-md-7 mt-2'p>>")
|
||||
->orderBy(0, 'asc')
|
||||
->buttons(
|
||||
Button::make('excel')
|
||||
->text('<i class="bi bi-file-earmark-excel-fill"></i> Excel'),
|
||||
Button::make('print')
|
||||
->text('<i class="bi bi-printer-fill"></i> Print'),
|
||||
Button::make('reset')
|
||||
->text('<i class="bi bi-x-circle"></i> Reset'),
|
||||
Button::make('reload')
|
||||
->text('<i class="bi bi-arrow-repeat"></i> Reload')
|
||||
);
|
||||
}
|
||||
|
||||
protected function getColumns() {
|
||||
return [
|
||||
Column::make('category_name')
|
||||
->addClass('text-center'),
|
||||
|
||||
Column::make('category_description')
|
||||
->addClass('text-center'),
|
||||
|
||||
Column::make('expenses_count')
|
||||
->addClass('text-center'),
|
||||
|
||||
Column::computed('action')
|
||||
->exportable(false)
|
||||
->printable(false)
|
||||
->addClass('text-center'),
|
||||
];
|
||||
}
|
||||
|
||||
protected function filename() {
|
||||
return 'ExpenseCategories_' . date('YmdHis');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
namespace App\DataTables;
|
||||
|
||||
use Modules\Expense\Entities\Expense;
|
||||
use Yajra\DataTables\Html\Button;
|
||||
use Yajra\DataTables\Html\Column;
|
||||
use Yajra\DataTables\Html\Editor\Editor;
|
||||
use Yajra\DataTables\Html\Editor\Fields;
|
||||
use Yajra\DataTables\Services\DataTable;
|
||||
|
||||
class ExpensesDataTable extends DataTable
|
||||
{
|
||||
|
||||
public function dataTable($query) {
|
||||
return datatables()
|
||||
->eloquent($query)
|
||||
->addColumn('action', function ($data) {
|
||||
return view('expense::expenses.partials.actions', compact('data'));
|
||||
});
|
||||
}
|
||||
|
||||
public function query(Expense $model) {
|
||||
return $model->newQuery()->with('category');
|
||||
}
|
||||
|
||||
public function html() {
|
||||
return $this->builder()
|
||||
->setTableId('expenses-table')
|
||||
->columns($this->getColumns())
|
||||
->minifiedAjax()
|
||||
->dom("<'row'<'col-md-3'l><'col-md-5 mb-2'B><'col-md-4'f>> .
|
||||
'tr' .
|
||||
<'row'<'col-md-5'i><'col-md-7 mt-2'p>>")
|
||||
->orderBy(1)
|
||||
->buttons(
|
||||
Button::make('excel')
|
||||
->text('<i class="bi bi-file-earmark-excel-fill"></i> Excel'),
|
||||
Button::make('print')
|
||||
->text('<i class="bi bi-printer-fill"></i> Print'),
|
||||
Button::make('reset')
|
||||
->text('<i class="bi bi-x-circle"></i> Reset'),
|
||||
Button::make('reload')
|
||||
->text('<i class="bi bi-arrow-repeat"></i> Reload')
|
||||
);
|
||||
}
|
||||
|
||||
protected function getColumns() {
|
||||
return [
|
||||
Column::make('date')
|
||||
->className('text-center align-middle'),
|
||||
|
||||
Column::make('reference')
|
||||
->className('text-center align-middle'),
|
||||
|
||||
Column::make('category.category_name')
|
||||
->title('Category')
|
||||
->className('text-center align-middle'),
|
||||
|
||||
Column::make('amount')
|
||||
->className('text-center align-middle'),
|
||||
|
||||
Column::make('details')
|
||||
->className('text-center align-middle'),
|
||||
|
||||
Column::computed('action')
|
||||
->exportable(false)
|
||||
->printable(false)
|
||||
->className('text-center align-middle')
|
||||
];
|
||||
}
|
||||
|
||||
protected function filename() {
|
||||
return 'Expenses_' . date('YmdHis');
|
||||
}
|
||||
}
|
|
@ -11,14 +11,8 @@ use Yajra\DataTables\Services\DataTable;
|
|||
|
||||
class ProductCategoriesDataTable extends DataTable
|
||||
{
|
||||
/**
|
||||
* Build DataTable class.
|
||||
*
|
||||
* @param mixed $query Results from query() method.
|
||||
* @return \Yajra\DataTables\DataTableAbstract
|
||||
*/
|
||||
public function dataTable($query)
|
||||
{
|
||||
|
||||
public function dataTable($query) {
|
||||
return datatables()
|
||||
->eloquent($query)
|
||||
->addColumn('action', function ($data) {
|
||||
|
@ -26,24 +20,11 @@ class ProductCategoriesDataTable extends DataTable
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query source of dataTable.
|
||||
*
|
||||
* @param \Modules\Product\Entities\Category $model
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function query(Category $model)
|
||||
{
|
||||
public function query(Category $model) {
|
||||
return $model->newQuery()->withCount('products');
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional method if you want to use html builder.
|
||||
*
|
||||
* @return \Yajra\DataTables\Html\Builder
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
public function html() {
|
||||
return $this->builder()
|
||||
->setTableId('product_categories-table')
|
||||
->columns($this->getColumns())
|
||||
|
@ -64,13 +45,7 @@ class ProductCategoriesDataTable extends DataTable
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get columns.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getColumns()
|
||||
{
|
||||
protected function getColumns() {
|
||||
return [
|
||||
Column::make('category_code')
|
||||
->addClass('text-center'),
|
||||
|
@ -85,13 +60,7 @@ class ProductCategoriesDataTable extends DataTable
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename for export.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function filename()
|
||||
{
|
||||
protected function filename() {
|
||||
return 'ProductCategories_' . date('YmdHis');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,12 +11,7 @@ use Yajra\DataTables\Services\DataTable;
|
|||
|
||||
class ProductDataTable extends DataTable
|
||||
{
|
||||
/**
|
||||
* Build DataTable class.
|
||||
*
|
||||
* @param mixed $query Results from query() method.
|
||||
* @return \Yajra\DataTables\DataTableAbstract
|
||||
*/
|
||||
|
||||
public function dataTable($query)
|
||||
{
|
||||
return datatables()
|
||||
|
@ -31,23 +26,11 @@ class ProductDataTable extends DataTable
|
|||
->rawColumns(['product_image']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get query source of dataTable.
|
||||
*
|
||||
* @param \Modules\Product\Entities\Product $model
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function query(Product $model)
|
||||
{
|
||||
return $model->newQuery()->with('category');
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional method if you want to use html builder.
|
||||
*
|
||||
* @return \Yajra\DataTables\Html\Builder
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
return $this->builder()
|
||||
|
@ -70,11 +53,6 @@ class ProductDataTable extends DataTable
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get columns.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getColumns()
|
||||
{
|
||||
return [
|
||||
|
|
|
@ -11,14 +11,8 @@ use Yajra\DataTables\Services\DataTable;
|
|||
|
||||
class RolesDataTable extends DataTable
|
||||
{
|
||||
/**
|
||||
* Build DataTable class.
|
||||
*
|
||||
* @param mixed $query Results from query() method.
|
||||
* @return \Yajra\DataTables\DataTableAbstract
|
||||
*/
|
||||
public function dataTable($query)
|
||||
{
|
||||
|
||||
public function dataTable($query) {
|
||||
return datatables()
|
||||
->eloquent($query)
|
||||
->addColumn('action', function ($data) {
|
||||
|
@ -32,26 +26,13 @@ class RolesDataTable extends DataTable
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query source of dataTable.
|
||||
*
|
||||
* @param \Spatie\Permission\Models\Role $model
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function query(Role $model)
|
||||
{
|
||||
return $model->newQuery()->with(['permissions' => function($query) {
|
||||
public function query(Role $model) {
|
||||
return $model->newQuery()->with(['permissions' => function ($query) {
|
||||
$query->select('name')->get();
|
||||
}])->where('name', '!=', 'Super Admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional method if you want to use html builder.
|
||||
*
|
||||
* @return \Yajra\DataTables\Html\Builder
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
public function html() {
|
||||
return $this->builder()
|
||||
->setTableId('roles-table')
|
||||
->columns($this->getColumns())
|
||||
|
@ -72,13 +53,7 @@ class RolesDataTable extends DataTable
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get columns.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getColumns()
|
||||
{
|
||||
protected function getColumns() {
|
||||
return [
|
||||
Column::make('id')
|
||||
->addClass('text-center')
|
||||
|
@ -101,13 +76,7 @@ class RolesDataTable extends DataTable
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename for export.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function filename()
|
||||
{
|
||||
protected function filename() {
|
||||
return 'Roles_' . date('YmdHis');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,14 +11,8 @@ use Yajra\DataTables\Services\DataTable;
|
|||
|
||||
class UsersDataTable extends DataTable
|
||||
{
|
||||
/**
|
||||
* Build DataTable class.
|
||||
*
|
||||
* @param mixed $query Results from query() method.
|
||||
* @return \Yajra\DataTables\DataTableAbstract
|
||||
*/
|
||||
public function dataTable($query)
|
||||
{
|
||||
|
||||
public function dataTable($query) {
|
||||
return datatables()
|
||||
->eloquent($query)
|
||||
->addColumn('role', function ($data) {
|
||||
|
@ -35,23 +29,18 @@ class UsersDataTable extends DataTable
|
|||
} else {
|
||||
$html = '<span class="badge badge-warning">Deactivated</span>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
})
|
||||
->addColumn('image', function ($data) {
|
||||
$url = $data->getFirstMediaUrl('avatars');
|
||||
return '<img src="'.$url.'" style="width:50px;height:50px;" class="img-thumbnail rounded-circle"/>';
|
||||
|
||||
return '<img src="' . $url . '" style="width:50px;height:50px;" class="img-thumbnail rounded-circle"/>';
|
||||
})
|
||||
->rawColumns(['image', 'status']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query source of dataTable.
|
||||
*
|
||||
* @param \App\Models\User $model
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function query(User $model)
|
||||
{
|
||||
public function query(User $model) {
|
||||
return $model->newQuery()
|
||||
->with(['roles' => function ($query) {
|
||||
$query->select('name')->get();
|
||||
|
@ -59,13 +48,7 @@ class UsersDataTable extends DataTable
|
|||
->where('id', '!=', auth()->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional method if you want to use html builder.
|
||||
*
|
||||
* @return \Yajra\DataTables\Html\Builder
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
public function html() {
|
||||
return $this->builder()
|
||||
->setTableId('users-table')
|
||||
->columns($this->getColumns())
|
||||
|
@ -86,13 +69,7 @@ class UsersDataTable extends DataTable
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get columns.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getColumns()
|
||||
{
|
||||
protected function getColumns() {
|
||||
return [
|
||||
Column::computed('image')
|
||||
->className('text-center align-middle'),
|
||||
|
@ -116,13 +93,7 @@ class UsersDataTable extends DataTable
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename for export.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function filename()
|
||||
{
|
||||
protected function filename() {
|
||||
return 'Users_' . date('YmdHis');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,3 +86,32 @@
|
|||
</ul>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
@can('access_expenses')
|
||||
<li class="c-sidebar-nav-item c-sidebar-nav-dropdown {{ request()->routeIs('expenses.*') || request()->routeIs('expense-categories.*') ? 'c-show' : '' }}">
|
||||
<a class="c-sidebar-nav-link c-sidebar-nav-dropdown-toggle" href="#">
|
||||
<i class="c-sidebar-nav-icon bi bi-wallet2" style="line-height: 1;"></i> Expenses
|
||||
</a>
|
||||
<ul class="c-sidebar-nav-dropdown-items">
|
||||
@can('access_expense_categories')
|
||||
<li class="c-sidebar-nav-item">
|
||||
<a class="c-sidebar-nav-link {{ request()->routeIs('expense-categories.*') ? 'c-active' : '' }}" href="{{ route('expense-categories.index') }}">
|
||||
<i class="c-sidebar-nav-icon bi bi-collection" style="line-height: 1;"></i> Categories
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
@can('create_expenses')
|
||||
<li class="c-sidebar-nav-item">
|
||||
<a class="c-sidebar-nav-link {{ request()->routeIs('expenses.create') ? 'c-active' : '' }}" href="{{ route('expenses.create') }}">
|
||||
<i class="c-sidebar-nav-icon bi bi-journal-plus" style="line-height: 1;"></i> Create Expense
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
<li class="c-sidebar-nav-item">
|
||||
<a class="c-sidebar-nav-link {{ request()->routeIs('expenses.index') ? 'c-active' : '' }}" href="{{ route('expenses.index') }}">
|
||||
<i class="c-sidebar-nav-icon bi bi-journals" style="line-height: 1;"></i> All Expenses
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
@endcan
|
||||
|
|
Loading…
Reference in New Issue