Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
1eaa1d1
Resolved
kithomeken Apr 28, 2026
9f7fcf1
Product Search Case Insensitve
kithomeken Apr 23, 2026
60a9648
Purchase Component Search List Improvement
kithomeken Apr 23, 2026
ddf7685
Default Currency Inclusion In Product Search List
kithomeken Apr 23, 2026
95d55f4
Config Name On Navbar
kithomeken Apr 23, 2026
7b6d9f6
Product Query Rollback
kithomeken Apr 23, 2026
d4c581f
Currency Addition to Product Resource
kithomeken Apr 23, 2026
fc257b5
Create Purchase JSX File Error Resolution
kithomeken Apr 23, 2026
b9c19f5
Resolved Conflicts
kithomeken Apr 28, 2026
d437998
Resolved Conflicts
kithomeken Apr 28, 2026
25976e2
Add .editorconfig for consistent coding styles
kithomeken Apr 23, 2026
c42c3ff
Payment Methods Schema, Model & Seeder
kithomeken Apr 25, 2026
9511e8d
Payment Methods Permissions
kithomeken Apr 25, 2026
c2e2411
Payment Method Resources & Controller
kithomeken Apr 25, 2026
aa1bfd8
Resolved Conflicts
kithomeken Apr 28, 2026
afe0901
Payment Methods Routes
kithomeken Apr 25, 2026
fa689ef
Payment Methods Menu
kithomeken Apr 25, 2026
f5f8106
Barcode Library
kithomeken Apr 25, 2026
d6d6d76
Order Reference Number Migration Creation
kithomeken Apr 25, 2026
ab44b8e
Generate Order Reference Number
kithomeken Apr 25, 2026
68986d3
Activate Payment Method Routes & Functionality
kithomeken Apr 25, 2026
a8f179a
Payment Method Icon
kithomeken Apr 25, 2026
ca643c4
POS Invoice/Receipt Redesign
kithomeken Apr 25, 2026
9283984
Brand Inclusion on Products DataTable & Number Formating
kithomeken Apr 25, 2026
82ae9e9
Purchase Order Break Down on DataTable
kithomeken Apr 25, 2026
a2af8b9
Purchase User Relationship
kithomeken Apr 25, 2026
de1918a
Applying Number Formatting To Fields
kithomeken Apr 25, 2026
b881372
Sale Item Improvements
kithomeken Apr 25, 2026
3a31aa1
Number Formating
kithomeken Apr 26, 2026
b647fbe
Purchase Data Table Additiona Columns - SubTotal, Discount, Shipping …
kithomeken Apr 26, 2026
d1696f0
Brand Name Addition to Products DataTable
kithomeken Apr 26, 2026
d346995
Image Column Commented Out on Brands DataTable
kithomeken Apr 26, 2026
983cfb0
File Modes Change
kithomeken Apr 23, 2026
9b1d1fa
.gitignore Update
kithomeken Apr 26, 2026
607bb49
Product Creation Form Redesign
kithomeken Apr 26, 2026
ce2f769
Product Store Request No Discount Type
kithomeken Apr 26, 2026
9cfb50a
Purchase Creation UI/UX Redesign
kithomeken Apr 26, 2026
458b080
Additional Product Search By Brand
kithomeken Apr 27, 2026
4bcc8ac
Brand Addition to Product Resource
kithomeken Apr 27, 2026
0465246
Title Removal & Margin Top Addition For a Cleaner UI/UX
kithomeken Apr 27, 2026
c982140
Products Status Improvement
kithomeken Apr 27, 2026
efb7311
Order & Payment Method Relationship
kithomeken Apr 27, 2026
0525f5e
Payment Details Addition to Orders
kithomeken Apr 27, 2026
1ff8107
SKU on Product Resource
kithomeken Apr 27, 2026
f38fb5b
Resolved Conflicts
kithomeken Apr 28, 2026
ceec2da
POS Redesign to Meet UI/UX Standards
kithomeken Apr 27, 2026
c052c09
POS Cart Enhancement - Product Name & SKU Search Into One Among Others
kithomeken Apr 27, 2026
d325d20
Payment Method Integration Into Order Creation
kithomeken Apr 27, 2026
95e0af9
Payment Creation Gate Correction
kithomeken Apr 27, 2026
919b5df
Surcharge Details Addition To POS Receipt
kithomeken Apr 27, 2026
557df4c
Title Change to New Order
kithomeken Apr 27, 2026
9d552d2
Navbar Clean Up
kithomeken Apr 27, 2026
e9f67ac
Refactored Order Transactions Totals With Agnostic Driver Check
kithomeken Apr 28, 2026
071e2ff
File Permissions Change
kithomeken Apr 28, 2026
c85e82e
File Permissions Change II
kithomeken Apr 28, 2026
facd22c
New Build Files
kithomeken Apr 28, 2026
92ecf71
Composer Lock
kithomeken Apr 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,4 @@ VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
GOOGLE_CLIENT_ID=""
GOOGLE_CLIENT_SECRET=""

GOOGLE_MAP_KEY=""
GOOGLE_MAP_KEY=""
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ yarn-error.log
/.fleet
/.idea
/.vscode
/~
/~
/public/assets/images/logo
/public/build
Empty file modified Dockerfile
100644 → 100755
Empty file.
Empty file modified Makefile
100644 → 100755
Empty file.
Empty file modified app/Exports/DemoProductsExport.php
100644 → 100755
Empty file.
Empty file modified app/Http/Controllers/Backend/CurrencyController.php
100644 → 100755
Empty file.
29 changes: 19 additions & 10 deletions app/Http/Controllers/Backend/DashboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use App\Models\SupportTicket;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class DashboardController extends Controller
{
Expand All @@ -34,7 +35,7 @@ public function index(Request $request)

$startDate = Carbon::now()->subDays(30)->format('Y-m-d');
$endDate = Carbon::now()->format('Y-m-d');
if($request->has('daterange')) {
if ($request->has('daterange')) {
$dates = explode(' to ', $request->query('daterange'));

if (count($dates) == 2) {
Expand All @@ -43,24 +44,32 @@ public function index(Request $request)
}
}
$dailyTotals = OrderTransaction::selectRaw('DATE(created_at) as date, SUM(amount) as total_amount')
->whereBetween('created_at', [$startDate, $endDate])
->groupBy('date')
->orderBy('date', 'DESC')
->get();
->whereBetween('created_at', [$startDate, $endDate])
->groupBy('date')
->orderBy('date', 'DESC')
->get();
$dates = $dailyTotals->pluck('date')->toArray();
$totalAmounts = $dailyTotals->pluck('total_amount')->toArray();
$data['dates'] = $dates;
$data['totalAmounts'] = $totalAmounts;
$data['dateRange'] = 'from '. $startDate . ' to ' . $endDate;
$data['dateRange'] = 'from ' . $startDate . ' to ' . $endDate;


$currentYear = now()->year;
$data['currentYear'] = $currentYear;

$salesData = OrderTransaction::selectRaw('DATE_FORMAT(created_at, "%Y-%m") as month, SUM(amount) as total_amount')
->whereYear('created_at', $currentYear)
->groupBy('month')
->orderBy('month', 'ASC')->pluck('total_amount', 'month')->toArray();
// Determine the date format based on the active driver
$driver = DB::getDriverName();
$format = ($driver === 'pgsql') ? "TO_CHAR(created_at, 'YYYY-MM')" : 'DATE_FORMAT(created_at, "%Y-%m")';

// Fetch data in a single chain
$salesData = OrderTransaction::selectRaw("$format as month, SUM(amount) as total_amount")
->whereYear('created_at', $currentYear)
->groupBy('month')
->orderBy('month', 'ASC')
->pluck('total_amount', 'month')
->toArray();

$tempMonths = [];
$tempTotalAmountMonth = [];
for ($i = 1; $i <= 12; $i++) {
Expand Down
307 changes: 307 additions & 0 deletions app/Http/Controllers/Backend/PaymentMethodsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
<?php

namespace App\Http\Controllers\Backend;

use Illuminate\Support\Facades\Cache;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Yajra\DataTables\DataTables;
use App\Models\PaymentMethods;
use Illuminate\Http\Request;
use App\Models\Currency;

class PaymentMethodsController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
abort_if(!auth()->user()->can('payment_view'), 403);

if ($request->ajax()) {
$paymentMethods = PaymentMethods::latest()
->orderBy('primary_method', 'desc')
->get();

# Get Default Currency
$defaultCurrency = Currency::where('active', true)
->first();

return DataTables::of($paymentMethods)
->addIndexColumn()
->addColumn('name', fn($data) => $data->name
. ($data->primary_method ? ' (Default Method)' : ''))
->addColumn('code', fn($data) => $data->code)
->addColumn('surcharge_type', fn($data) => ucfirst($data->surcharge_type))
->addColumn(
'surcharge_value',
function ($data) use ($defaultCurrency) {
switch ($data->surcharge_type) {
case 'fixed':
return $defaultCurrency->symbol . ' ' . $data->surcharge_value;

case 'percentage':
return $data->surcharge_value . ' %';

default:
return '0.00';
}
}
)
->addColumn('status', fn($data) => $data->active
? '<span class="badge bg-primary">Active</span>'
: '<span class="badge bg-danger">Disabled</span>')
->addColumn('action', function ($data) {
// Logic for Toggle Button (Activate vs Disable)
if ($data->active) {
$statusToggle = '
<form action="' . route('backend.admin.payments.destroy', $data->id) . '" method="POST" style="display:inline;">
' . csrf_field() . '
' . method_field("DELETE") . '
<button type="submit" class="dropdown-item text-danger" onclick="return confirm(\'Are you sure you want to disable this method?\')">
<i class="fas fa-ban"></i> Disable
</button>
</form>';
} else {
$statusToggle = '
<a class="dropdown-item text-success" href="' . route('backend.admin.payments.activate', $data->id) . '" onclick="return confirm(\'Activate this payment method?\')">
<i class="fas fa-check-circle"></i> Activate
</a>';
}

// Logic for Set Default (Only show/allow if active and not already default)
$defaultButton = '';
if ($data->active && !$data->primary_method) {
$defaultButton = '
<div class="dropdown-divider"></div>
<a class="dropdown-item" onclick="return confirm(\'Set this as the default payment method?\')" href="' . route('backend.admin.payments.setDefault', $data->id) . '">
<i class="fas fa-star text-warning"></i> Set Default
</a>';
} elseif ($data->primary_method) {
$defaultButton = '
<div class="dropdown-divider"></div>
<button class="dropdown-item disabled" disabled>
<i class="fas fa-certificate text-primary"></i> Current Default
</button>';
}

// Assemble the Dropdown
return '<div class="btn-group">
<button type="button" class="btn bg-gradient-primary btn-sm btn-flat">Action</button>
<button type="button" class="btn bg-gradient-primary btn-sm btn-flat dropdown-toggle dropdown-icon" data-toggle="dropdown" aria-expanded="false">
<span class="sr-only">Toggle Dropdown</span>
</button>

<div class="dropdown-menu shadow" role="menu">
<a class="dropdown-item" href="' . route('backend.admin.payments.edit', $data->id) . '">
<i class="fas fa-edit"></i> Edit
</a>

<div class="dropdown-divider"></div>

' . $statusToggle . '

' . $defaultButton . '
</div>
</div>';
})
->rawColumns(['name', 'code', 'surcharge_type', 'surcharge_value', 'status', 'action'])
->toJson();
}

return view('backend.settings.payments.index');
}

/**
* Show the form for creating a new resource.
*/
public function create()
{
abort_if(!auth()->user()->can('payment_create'), 403);

# Get Default Currency
$defaultCurrency = Currency::where('active', true)
->first();

return view('backend.settings.payments.create', compact('defaultCurrency'));
}

/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
abort_if(!auth()->user()->can('payment_create'), 403);

$validated = $request->validate([
'name' => 'required|string|min:3|max:255|unique:payment_methods,name',
'code' => 'required|string|min:3|max:50|unique:payment_methods,code',
'surcharge_type' => 'required|in:none,fixed,percentage',
'surcharge_value' => 'required|numeric|min:0',
'primary_method' => 'nullable|boolean',
]);

// Counter-measure:
// If this is set as primary, unset the previous one
if ($request->has('primary_method') && $request->primary_method == 1) {
PaymentMethods::where('primary_method', true)
->update(['primary_method' => false]);
}

// Create the record
$paymentData = array_merge($validated, [
'primary_method' => $request->has('primary_method')
]);

PaymentMethods::create($paymentData);

return redirect()
->route('backend.admin.payments.index')
->with('success', 'Payment method configured successfully!');
}

/**
* Show the form for editing the specified resource.
*/
public function edit($id)
{
abort_if(!auth()->user()->can('payment_update'), 403);

$paymentMethod = PaymentMethods::findOrFail($id);

# Get Default Currency
$defaultCurrency = Currency::where('active', true)
->first();

return view('backend.settings.payments.edit', compact('paymentMethod', 'defaultCurrency'));
}

/**
* Update the specified resource in storage.
*/
public function update(Request $request, $id)
{
$paymentMethod = PaymentMethods::findOrFail($id);

$validated = $request->validate([
'name' => 'required|string|min:3|max:255|unique:payment_methods,name,' . $id,
'code' => 'required|string|min:3|max:50|unique:payment_methods,code,' . $id,
'surcharge_type' => 'required|in:none,fixed,percentage',
'surcharge_value' => 'required|numeric|min:0',
'primary_method' => 'nullable|boolean',
]);

// Primary Method Counter-Measure
$isNowPrimary = $request->has('primary_method');

if ($isNowPrimary) {
// If the user checked "Primary", demote everyone else.
PaymentMethods::where('id', '!=', $id)
->where('primary_method', true)
->update(['primary_method' => false]);
} else {
// OPTIONAL: Safety check.
// If this was the ONLY primary method, you might want to prevent
// unchecking it so the system always has at least one default.
if ($paymentMethod->primary_method) {
$isNowPrimary = true;
}
}

// Sync Surcharge Logic
// If type is 'none', force value to 0 to prevent database noise
$surchargeValue = ($validated['surcharge_type'] === 'none') ? 0 : $validated['surcharge_value'];

// Update
$paymentMethod->update([
'name' => $validated['name'],
'code' => $validated['code'],
'surcharge_type' => $validated['surcharge_type'],
'surcharge_value' => $surchargeValue,
'primary_method' => $isNowPrimary,
]);

return redirect()
->route('backend.admin.payments.index')
->with('success', "{$paymentMethod->name} updated successfully!");
}

/**
* Remove the specified resource from storage.
*/
public function destroy($id)
{
// Authorization Check
abort_if(!auth()->user()->can('payment_delete'), 403);

$paymentMethod = PaymentMethods::findOrFail($id);

// Primary Method Safety Check
// You cannot disable the "Auto-selected" method
if ($paymentMethod->primary_method) {
return redirect()->back()->with(
'error',
'Cannot disable the primary payment method. Please set another method as "Primary" before proceeding.'
);
}

// The "Disable" Logic (Status Toggle)
// Instead of $paymentMethod->delete(), we update the status
$paymentMethod->update([
'active' => false
]);

return redirect()->back()->with('success', "Payment method '{$paymentMethod->name}' has been disabled.");
}

public function activate($id)
{
// Authorization Check
abort_if(!auth()->user()->can('payment_update'), 403);

// Find and Update
$paymentMethod = PaymentMethods::findOrFail($id);

$paymentMethod->update([
'active' => true
]);

// 3. Return with feedback
return redirect()
->back()
->with('success', "Payment method '{$paymentMethod->name}' has been activated successfully.");
}

public function setDefault($id)
{
abort_if(!auth()->user()->can('payment_update'), 403);

// Find the payment method
$paymentMethod = PaymentMethods::findOrFail($id);

// Crucial: We cannot set a method as default if it is currently disabled (active = false)
if (!$paymentMethod->active) {
return redirect()->back()->with(
'error',
"Cannot set '{$paymentMethod->name}' as default because it is currently disabled."
);
}

// Perform the Atomic Switch
// Wrap in a transaction to ensure we don't lose our default if the query fails midway
DB::transaction(function () use ($id) {
// Demote all existing defaults
PaymentMethods::where('primary_method', true)->update(['primary_method' => false]);

// Promote the selected one
PaymentMethods::where('id', $id)->update(['primary_method' => true]);
});

// Cache Management
// We refresh the cache so the POS frontend gets the update immediately
Cache::put('default_payment_method', $paymentMethod, now()->addDays(1));

return redirect()->back()->with('success', "'{$paymentMethod->name}' is now the default payment method.");
}
}
Loading