Initial commit

This commit is contained in:
Kwesi Banson Jnr
2026-07-17 09:58:21 +00:00
commit b71f5c7553
8555 changed files with 725382 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ConfirmsPasswords;
class ConfirmPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Confirm Password Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password confirmations and
| uses a simple trait to include the behavior. You're free to explore
| this trait and override any functions that require customization.
|
*/
use ConfirmsPasswords;
/**
* Where to redirect users when the intended url fails.
*
* @var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
class ForgotPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset emails and
| includes a trait which assists in sending these notifications from
| your application to your users. Feel free to explore this trait.
|
*/
use SendsPasswordResetEmails;
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
$this->middleware('auth')->only('logout');
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\Models\User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* Where to redirect users after resetting their password.
*
* @var string
*/
protected $redirectTo = '/home';
}

View File

@@ -0,0 +1,41 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\VerifiesEmails;
class VerificationController extends Controller
{
/*
|--------------------------------------------------------------------------
| Email Verification Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling email verification for any
| user that recently registered with the application. Emails may also
| be re-sent if the user didn't receive the original email message.
|
*/
use VerifiesEmails;
/**
* Where to redirect users after verification.
*
* @var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify', 'resend');
}
}

View File

@@ -0,0 +1,150 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models;
class ClientsController extends Controller
{
public function index()
{
// $clients = Models\Client::get();
$data = [
'page_title' => 'Dashboard',
// 'clients' => $clients
];
return view('clients.index', $data);
}
public function fetchDataOld(Request $request)
{
$query = Models\Client::query();
if ($request->filled('search')) {
$searchTerm = $request->search;
$query->where(function ($q) use ($searchTerm) {
$q->where('name', 'like', "%{$searchTerm}%")
->orWhere('email', 'like', "%{$searchTerm}%")
->orWhere('contact_person', 'like', "%{$searchTerm}%");
});
}
if ($request->filled('service')) {
// $query->where('services', $request->service);
// $query->whereJsonContains('services', $request->service);
$query->where('services', 'LIKE', '%' . $request->service . '%');
}
if ($request->filled('billing')) {
$query->where('pay_mode', $request->billing);
}
$clients = $query->orderBy('created_at', 'desc')->paginate(30);
return response()->json($clients);
}
private function buildFilteredQuery(Request $request)
{
$query = Models\Client::query();
if ($request->filled('search')) {
$searchTerm = $request->search;
$query->where(function ($q) use ($searchTerm) {
$q->where('name', 'like', "%{$searchTerm}%")
->orWhere('email', 'like', "%{$searchTerm}%")
->orWhere('contact_person', 'like', "%{$searchTerm}%");
});
}
if ($request->filled('service')) {
$query->whereJsonContains('services', $request->service);
}
if ($request->filled('billing')) {
$query->where('pay_mode', $request->billing);
}
return $query->orderBy('created_at', 'desc');
}
/**
* Your existing AJAX fetch method (Refactored to use the new builder)
*/
public function fetchData(Request $request)
{
$clients = $this->buildFilteredQuery($request)->paginate(30);
return response()->json($clients);
}
/**
* Handle the Export Request
*/
public function export(Request $request)
{
// Get the filtered data but execute get() instead of paginate()
$clients = $this->buildFilteredQuery($request)->get();
$format = $request->input('format', 'csv');
if ($format === 'pdf') {
return $this->exportToPdf($clients);
}
return $this->exportToCsv($clients);
}
/**
* Generate Native CSV (Opens perfectly in Excel without massive dependencies)
*/
private function exportToCsv($clients)
{
$fileName = 'clients_export_' . date('Y-m-d_H-i') . '.csv';
$headers = [
"Content-type" => "text/csv",
"Content-Disposition" => "attachment; filename=$fileName",
"Pragma" => "no-cache",
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
"Expires" => "0"
];
$columns = ['ID', 'Company Name', 'Contact Person', 'Email', 'Phone', 'Country', 'Pay Mode', 'Status'];
$callback = function() use($clients, $columns) {
$file = fopen('php://output', 'w');
fputcsv($file, $columns);
foreach ($clients as $client) {
$row['ID'] = $client->id;
$row['Company Name'] = $client->name;
$row['Contact Person'] = $client->contact_person;
$row['Email'] = $client->email;
$row['Phone'] = $client->phone;
$row['Country'] = $client->country;
$row['Pay Mode'] = $client->pay_mode;
$row['Status'] = $client->status;
fputcsv($file, array_values($row));
}
fclose($file);
};
return new StreamedResponse($callback, 200, $headers);
}
/**
* Generate PDF
*/
private function exportToPdf($clients)
{
// You will need to create a simple blade view for the PDF layout: resources/views/exports/clients_pdf.blade.php
$pdf = Pdf::loadView('exports.clients_pdf', ['clients' => $clients])
->setPaper('a4', 'landscape');
return $pdf->download('clients_export_' . date('Y-m-d_H-i') . '.pdf');
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace App\Http\Controllers;
use Session;
use App\Models;
use Illuminate\Http\Request;
class CommentsController extends Controller
{
public function index(){
$user_id = \Auth::user()->id;
$result = Models\Comment::with('projectStatus')
->where('assignee_id', $user_id)
->orderBy('project_id', 'DESC')
->get();
$data = [
'page_title' => 'Projects Status List',
'project_statuses' => $result
];
return view('comments.index', $data);
}
public function add_comment($id){
$result = Models\ProjectStatus::with('comments', 'project')->where('id', $id)->firstOrFail();
// dd($result);
$data = [
'page_title' => 'Projects Status Comment',
'project_arr' => $result
];
// dump($data);
return view('comments.create', $data);
}
public function store(Request $request) {
// Save a new post
$this->validate($request, [
'description' => 'required',
'status' => 'required',
'project_id' => 'required',
'assignee_id' => 'required'
]);
$project_status_arr = $request->except('_token');
$result = Models\ProjectStatus::create($project_status_arr);
Session::flash('success_message', 'Project status added successfully!');
return redirect(url('project-status'));
}
public function show($id) {
// Show a specific post
}
public function edit($id) {
// Show form to edit a post
}
public function update(Request $request, $id) {
// Update a specific post
return redirect(url('project-status'));
}
public function destroy($id) {
// Delete a specific post
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
use AuthorizesRequests, ValidatesRequests;
}

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DashboardController extends Controller
{
public function index()
{
$data = [
'page_title' => 'Dashboard'
];
return view('dashboard.index_two', $data);
}
}
// Nana Ekua Banson

View File

@@ -0,0 +1,88 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
class DocumentsController extends Controller
{
public function store(Request $request)
{
// 1. Validate the incoming request
$request->validate([
'file' => 'required|file|max:10240', // 10MB
'type' => 'required|string',
]);
// 2. Store locally on your ERP server
$file = $request->file('file');
$originalName = $file->getClientOriginalName();
$localPath = $file->storeAs('documents/' . date('Y/m'), $originalName, 'local');
// 3. Check if it needs to be pushed to Paperless-Ngx
// You can base this on the checkbox OR force it based on type (e.g., $request->type === 'contract')
if ($request->boolean('push_to_paperless')) {
$this->pushToPaperless($localPath, $originalName, $request->all());
}
return response()->json(['message' => 'Document saved successfully.']);
}
public function storeTwo(Request $request)
{
// ... validation and local storage logic ...
$localPath = $file->storeAs('documents/' . date('Y/m'), $originalName, 'local');
// Retrieve the actual Eloquent models based on the form input
$entity = MnoPartner::find($request->input('entity_id'));
$docType = DocumentType::where('slug', $request->input('type'))->first();
if ($request->boolean('push_to_paperless')) {
// Dispatch the job to the queue
PushDocumentToPaperless::dispatch(
$localPath,
$originalName,
$entity,
$docType,
$request->input('notes')
);
}
return response()->json(['message' => 'Document saved and queued for archival.']);
}
private function pushToPaperless(string $localPath, string $fileName, array $metadata)
{
$paperlessUrl = env('PAPERLESS_URL');
$apiToken = env('PAPERLESS_API_TOKEN');
try {
// Get the raw file contents from local storage
$fileContents = Storage::disk('local')->get($localPath);
// Send to Paperless-Ngx /api/documents/post_document/ endpoint
$response = Http::withToken($apiToken)
->attach(
'document',
$fileContents,
$fileName
)
->post("{$paperlessUrl}/api/documents/post_document/", [
// Optional Paperless metadata fields
'title' => $metadata['notes'] ?? $fileName,
// You can map ERP tags to Paperless Tag IDs here
// 'tags' => [1, 4],
// 'correspondent' => 2
]);
if (!$response->successful()) {
Log::error('Paperless-Ngx Upload Failed', ['error' => $response->body()]);
}
} catch (\Exception $e) {
Log::error('Paperless-Ngx Connection Error', ['message' => $e->getMessage()]);
}
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DocumentsVaultController extends Controller
{
public function index()
{
$data = [
'page_title' => 'Dashboard'
];
return view('documents_vault.index', $data);
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
//$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* @return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
return view('home');
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class NetworkOperatorsControlle extends Controller
{
public function index()
{
$data = [
'page_title' => 'Dashboard'
];
return view('network_operators.index', $data);
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Http\Controllers;
use Session;
use App\Models;
use Illuminate\Http\Request;
class ProjectStatusesController extends Controller
{
//load up project status
public function index(){
$user_id = \Auth::user()->id;
// dd($user_id);
$result = Models\ProjectStatus::with('project')
->where('assignee_id', $user_id)
->orderBy('project_id', 'DESC')
->get();
$data = [
'page_title' => 'Projects Status List',
'project_statuses' => $result
];
return view('project_status.index', $data);
}
public function add_status($id){
$result = Models\Project::with('statusInfo')->where('id', $id)->firstOrFail();
$data = [
'page_title' => 'Projects Status Update',
'project' => $result
];
// dd($data);
return view('project_status.add_status', $data);
}
public function create() {
return view('project_status.create');
}
public function store(Request $request) {
// Save a new post
$this->validate($request, [
'description' => 'required',
'status' => 'required',
'project_id' => 'required',
'assignee_id' => 'required'
]);
$project_status_arr = $request->except('_token');
$result = Models\ProjectStatus::create($project_status_arr);
Session::flash('success_message', 'Project status added successfully!');
return redirect(url('projects'));
}
public function show($id) {
// Show a specific post
}
public function edit($id) {
// Show form to edit a post
}
public function update(Request $request, $id) {
// Update a specific post
return redirect(url('project-status'));
}
public function destroy($id) {
// Delete a specific post
}
}

View File

@@ -0,0 +1,86 @@
<?php
namespace App\Http\Controllers;
use Session;
use App\Models;
use Illuminate\Http\Request;
class ProjectsController extends Controller
{
public function index(){
$user_id = \Auth::user()->id;
// dd($user_id);
$result = Models\Project::where('user_id', $user_id)->get();
$data = [
'page_title' => 'Projects List',
'projects' => $result
];
return view('projects.index', $data);
}
public function create() {
// Show form to create a new post
return view('projects.create');
}
public function store(Request $request) {
// Save a new post
$this->validate($request, [
'name' => 'required',
'description'=> 'required',
'dependancy' => 'sometimes',
'status' => 'required',
]);
$project_arr = $request->except('_token');
$result = Models\Project::create($project_arr);
Session::flash('success_message', 'Project created successfully!');
return redirect(url('projects'));
}
public function show($id) {
// Show a specific post
$user_id = \Auth::user()->id;
$result = Models\Project::with('statusInfo')->where('id', $id)->firstOrFail();
$data = [
'page_title' => 'Projects Details',
'project' => $result
];
// dump($data);
return view('projects.show', $data);
}
public function edit($id) {
// Show form to edit a post
$user_id = \Auth::user()->id;
$result = Models\Project::with('statusInfo')->where('id', $id)->firstOrFail();
$data = [
'page_title' => 'Projects Update',
'project' => $result
];
return view('projects.edit', $data);
}
public function update(Request $request, $id) {
// Update a specific post
$this->validate($request, [
'name' => 'required',
'description'=> 'required',
'dependancy' => 'sometimes',
'status' => 'required',
]);
$project = Models\Project::findOrFail($id);
$project->name = $request->name;
$project->description = $request->description;
$project->dependancy = $request->dependancy;
$project->status = $request->status;
$result = $project->save();
Session::flash('success_message', 'Project details updated successfully!');
return redirect(url('projects'));
}
public function destroy($id) {
// Delete a specific post
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class SenderidsController extends Controller
{
public function index()
{
$data = [
'page_title' => 'Dashboard'
];
return view('senderids.index', $data);
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ShortCodesController extends Controller
{
public function index()
{
$data = [
'page_title' => 'Dashboard'
];
return view('shortcodes.index', $data);
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class StaffController extends Controller
{
public function index()
{
$data = [
'page_title' => 'Dashboard'
];
return view('staff.index', $data);
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
class PushDocumentToPaperless implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $localPath;
protected $fileName;
protected $relatedEntity; // E.g., The Client or MNO Model
protected $documentType; // E.g., The DocumentType Model
protected $notes;
public function __construct($localPath, $fileName, $relatedEntity, $documentType, $notes = null)
{
$this->localPath = $localPath;
$this->fileName = $fileName;
$this->relatedEntity = $relatedEntity;
$this->documentType = $documentType;
$this->notes = $notes;
}
public function handle()
{
$fileContents = Storage::disk('local')->get($this->localPath);
// 1. Build the multipart payload mapping
$payload = [
['name' => 'title', 'contents' => $this->fileName],
];
// 2. Map the Correspondent (Entity)
if ($this->relatedEntity && $this->relatedEntity->paperless_correspondent_id) {
$payload[] = [
'name' => 'correspondent',
'contents' => $this->relatedEntity->paperless_correspondent_id
];
}
// 3. Map the Tag (Document Type)
if ($this->documentType && $this->documentType->paperless_tag_id) {
// Paperless expects an array of tag IDs, even if it's just one
$payload[] = [
'name' => 'tags',
'contents' => $this->documentType->paperless_tag_id
];
}
// 4. Send to Paperless
$response = Http::withToken(env('PAPERLESS_API_TOKEN'))
->attach('document', $fileContents, $this->fileName)
// Http::send allows us to pass a complex multipart array
->send('POST', env('PAPERLESS_URL') . '/api/documents/post_document/', [
'multipart' => $payload
]);
if (!$response->successful()) {
Log::error('Paperless Upload Failed: ' . $response->body());
// Optionally, release the job back to the queue to try again later
$this->release(60);
}
}
}

14
app/Models/Client.php Normal file
View File

@@ -0,0 +1,14 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Client extends Model
{
protected $guarded = [
'id'
];
public $table = "clients";
// protected $appends = ['client_services'];
}

23
app/Models/Comment.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Comment extends Model
{
protected $guarded = [
'id'
];
public function userInfo(): HasOne
{
return $this->hasOne(User::class);
}
public function projectStatus(): BelongsTo
{
return $this->belongsTo(ProjectStatus::class);
}
}

31
app/Models/Project.php Normal file
View File

@@ -0,0 +1,31 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Project extends Model
{
protected $guarded = [
'id'
];
// public function userInfo()
// {
// return $this->hasMany('App\Models\User', 'org_id', 'id');
// }
// public function phone(): HasOne
// {
// return $this->hasOne(Phone::class);
// }
public function userInfo(): HasMany
{
return $this->hasMany(User::class);
}
public function statusInfo(): HasMany
{
return $this->hasMany(ProjectStatus::class);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class ProjectStatus extends Model
{
protected $guarded = [
'id'
];
public function project(): BelongsTo
{
return $this->belongsTo(Project::class);
}
public function comments(): HasMany
{
return $this->hasMany(Comment::class);
}
}

48
app/Models/User.php Normal file
View File

@@ -0,0 +1,48 @@
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var list<string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
//
}
}