Adding Due Collections to Cash Register
Learn how to add a comprehensive due collections display to your POS cash register that shows collected payments, pending dues, and overdue amounts.
๐ What You'll Buildโ
By the end of this tutorial, your cash register will display:
- โ Collected Today: All due payments received today (business-wide)
- โ ๏ธ Pending Due Today: Outstanding amounts from today's sales
- ๐ด Overdue Amounts: Previous days' unpaid dues (shows when applicable)
๐ฏ Featuresโ
- Business-wide visibility (not just current cashier)
- Real-time data with transaction counts
- Smart conditional display (overdue box only shows when needed)
- Beautiful responsive design with icons
- Print-friendly styling
- Works in both register details and close register modals
๐ Prerequisitesโ
- Laravel-based POS system
- Basic knowledge of PHP and Blade templates
- Access to controller files and views
- Understanding of database relationships
๐ Implementation Stepsโ
Step 1: Update the CashRegisterUtil Classโ
First, we'll add the due collections logic to your app/Utils/CashRegisterUtil.php
.
1.1 Add the Due Collections Methodโ
Add this method to your app/Utils/CashRegisterUtil.php
:
public function getTodayDueCollections($user_id, $open_time, $close_time)
{
$business_id = request()->session()->get('user.business_id');
// COLLECTED TODAY - Payments made today that reduce existing due amounts
// This includes: payments on old invoices + additional payments on today's invoices
$today_due = DB::table('transaction_payments as tp')
->join('transactions as t', 'tp.transaction_id', '=', 't.id')
->whereDate('tp.paid_on', now()->toDateString()) // Payments made today
->where('t.type', 'sell')
->where('t.status', 'final')
->where('t.business_id', $business_id)
// Exclude initial payments made at the time of sale creation
->where(function($query) {
$query->whereRaw('DATE(tp.paid_on) != DATE(t.created_at)') // Payment made on different day than sale
->orWhereRaw('tp.created_at > DATE_ADD(t.created_at, INTERVAL 5 MINUTE)'); // Or payment made more than 5 minutes after sale creation
})
->select(
DB::raw('SUM(tp.amount) as total_due_collected'),
DB::raw('COUNT(DISTINCT tp.transaction_id) as total_due_transactions')
)
->first();
// PENDING DUES TODAY - Transactions created today that still have pending amounts
$pending_dues = DB::table('transactions as t')
->whereDate('t.transaction_date', now()->toDateString()) // Transactions created today
->where('t.type', 'sell')
->where('t.status', 'final')
->where('t.business_id', $business_id)
->where('t.payment_status', '!=', 'paid') // Not fully paid
->select(
DB::raw('SUM(t.final_total - COALESCE(
(SELECT SUM(amount) FROM transaction_payments WHERE transaction_id = t.id), 0
)) as total_pending_due'),
DB::raw('COUNT(t.id) as total_pending_transactions')
)
->first();
// OVERDUE AMOUNTS - Previous days' unpaid transactions
$overdue_amounts = DB::table('transactions as t')
->whereDate('t.transaction_date', '<', now()->toDateString()) // Previous days
->where('t.type', 'sell')
->where('t.status', 'final')
->where('t.business_id', $business_id)
->where('t.payment_status', '!=', 'paid') // Not fully paid
->select(
DB::raw('SUM(t.final_total - COALESCE(
(SELECT SUM(amount) FROM transaction_payments WHERE transaction_id = t.id), 0
)) as total_overdue'),
DB::raw('COUNT(t.id) as total_overdue_transactions')
)
->first();
return [
'due_collected_today' => $today_due->total_due_collected ?? 0,
'due_transactions_count' => $today_due->total_due_transactions ?? 0,
'pending_due_today' => $pending_dues->total_pending_due ?? 0,
'pending_transactions_count' => $pending_dues->total_pending_transactions ?? 0,
'overdue_amount' => $overdue_amounts->total_overdue ?? 0,
'overdue_transactions_count' => $overdue_amounts->total_overdue_transactions ?? 0,
];
}
public function getTodayDueCashCollections($register_id, $open_time, $close_time)
{
$business_id = request()->session()->get('user.business_id');
// Get cash payments made today for due collections
$due_cash_collections = DB::table('transaction_payments as tp')
->join('transactions as t', 'tp.transaction_id', '=', 't.id')
->whereDate('tp.paid_on', now()->toDateString()) // Payments made today
->where('t.business_id', $business_id)
->where('t.type', 'sell')
->where('t.status', 'final')
->where('tp.method', 'cash') // Only cash payments
// Exclude initial payments made at time of sale creation
->where(function ($query) {
$query->whereRaw('DATE(tp.paid_on) != DATE(t.created_at)') // Different day
->orWhereRaw('tp.created_at > DATE_ADD(t.created_at, INTERVAL 5 MINUTE)'); // Or 5+ minutes later
})
->sum('tp.amount');
return $due_cash_collections ?? 0;
}
Step 2: Update the Controllerโ
Now update your app/Http/Controllers/CashRegisterController.php
to call the utility method.
2.1 Update getRegisterDetails Methodโ
Update your existing getRegisterDetails()
method in the controller:
public function getRegisterDetails()
{
if (!auth()->user()->can('view_cash_register')) {
abort(403, 'Unauthorized action.');
}
$business_id = request()->session()->get('user.business_id');
$register_details = $this->cashRegisterUtil->getRegisterDetails();
$user_id = auth()->user()->id;
$open_time = $register_details['open_time'];
$close_time = \Carbon::now()->toDateTimeString();
$is_types_of_service_enabled = $this->moduleUtil->isModuleEnabled('types_of_service');
$details = $this->cashRegisterUtil->getRegisterTransactionDetails($user_id, $open_time, $close_time, $is_types_of_service_enabled);
// Add due collections data
$due_collections = $this->cashRegisterUtil->getTodayDueCollections($user_id, $open_time, $close_time);
$details['due_collections'] = $due_collections;
$payment_types = $this->cashRegisterUtil->payment_types($register_details->location_id, true, $business_id);
return view('cash_register.register_details')
->with(compact('register_details', 'details', 'payment_types', 'close_time'));
}
2.2 Update your existing getRegisterDetails method in CashRegisterUtil.phpโ
public function getRegisterDetails($register_id = null)
{
$query = CashRegister::leftjoin(
'cash_register_transactions as ct',
'ct.cash_register_id',
'=',
'cash_registers.id'
)
->join(
'users as u',
'u.id',
'=',
'cash_registers.user_id'
)
->leftJoin(
'business_locations as bl',
'bl.id',
'=',
'cash_registers.location_id'
);
if (empty($register_id)) {
$user_id = auth()->user()->id;
$query->where('user_id', $user_id)
->where('cash_registers.status', 'open');
} else {
$query->where('cash_registers.id', $register_id);
}
$register_details = $query->select(
'cash_registers.id as register_id',
'cash_registers.created_at as open_time',
'cash_registers.closed_at as closed_at',
'cash_registers.user_id',
'cash_registers.closing_note',
'cash_registers.location_id',
'cash_registers.denominations',
DB::raw("SUM(IF(transaction_type='initial', amount, 0)) as cash_in_hand"),
DB::raw("SUM(IF(transaction_type='sell', amount, IF(transaction_type='refund', -1 * amount, 0))) as total_sale"),
DB::raw("SUM(IF(transaction_type='expense', IF(transaction_type='refund', -1 * amount, amount), 0)) as total_expense"),
DB::raw("SUM(IF(pay_method='cash', IF(transaction_type='sell', amount, 0), 0)) as total_cash"),
DB::raw("SUM(IF(pay_method='cash', IF(transaction_type='expense', amount, 0), 0)) as total_cash_expense"),
DB::raw("SUM(IF(pay_method='cheque', IF(transaction_type='sell', amount, 0), 0)) as total_cheque"),
DB::raw("SUM(IF(pay_method='cheque', IF(transaction_type='expense', amount, 0), 0)) as total_cheque_expense"),
DB::raw("SUM(IF(pay_method='card', IF(transaction_type='sell', amount, 0), 0)) as total_card"),
DB::raw("SUM(IF(pay_method='card', IF(transaction_type='expense', amount, 0), 0)) as total_card_expense"),
DB::raw("SUM(IF(pay_method='bank_transfer', IF(transaction_type='sell', amount, 0), 0)) as total_bank_transfer"),
DB::raw("SUM(IF(pay_method='bank_transfer', IF(transaction_type='expense', amount, 0), 0)) as total_bank_transfer_expense"),
DB::raw("SUM(IF(pay_method='other', IF(transaction_type='sell', amount, 0), 0)) as total_other"),
DB::raw("SUM(IF(pay_method='other', IF(transaction_type='expense', amount, 0), 0)) as total_other_expense"),
DB::raw("SUM(IF(pay_method='advance', IF(transaction_type='sell', amount, 0), 0)) as total_advance"),
DB::raw("SUM(IF(pay_method='advance', IF(transaction_type='expense', amount, 0), 0)) as total_advance_expense"),
DB::raw("SUM(IF(pay_method='custom_pay_1', IF(transaction_type='sell', amount, 0), 0)) as total_custom_pay_1"),
DB::raw("SUM(IF(pay_method='custom_pay_2', IF(transaction_type='sell', amount, 0), 0)) as total_custom_pay_2"),
DB::raw("SUM(IF(pay_method='custom_pay_3', IF(transaction_type='sell', amount, 0), 0)) as total_custom_pay_3"),
DB::raw("SUM(IF(pay_method='custom_pay_4', IF(transaction_type='sell', amount, 0), 0)) as total_custom_pay_4"),
DB::raw("SUM(IF(pay_method='custom_pay_5', IF(transaction_type='sell', amount, 0), 0)) as total_custom_pay_5"),
DB::raw("SUM(IF(pay_method='custom_pay_6', IF(transaction_type='sell', amount, 0), 0)) as total_custom_pay_6"),
DB::raw("SUM(IF(pay_method='custom_pay_7', IF(transaction_type='sell', amount, 0), 0)) as total_custom_pay_7"),
DB::raw("SUM(IF(pay_method='custom_pay_1', IF(transaction_type='expense', amount, 0), 0)) as total_custom_pay_1_expense"),
DB::raw("SUM(IF(pay_method='custom_pay_2', IF(transaction_type='expense', amount, 0), 0)) as total_custom_pay_2_expense"),
DB::raw("SUM(IF(pay_method='custom_pay_3', IF(transaction_type='expense', amount, 0), 0)) as total_custom_pay_3_expense"),
DB::raw("SUM(IF(pay_method='custom_pay_4', IF(transaction_type='expense', amount, 0), 0)) as total_custom_pay_4_expense"),
DB::raw("SUM(IF(pay_method='custom_pay_5', IF(transaction_type='expense', amount, 0), 0)) as total_custom_pay_5_expense"),
DB::raw("SUM(IF(pay_method='custom_pay_6', IF(transaction_type='expense', amount, 0), 0)) as total_custom_pay_6_expense"),
DB::raw("SUM(IF(pay_method='custom_pay_7', IF(transaction_type='expense', amount, 0), 0)) as total_custom_pay_7_expense"),
DB::raw("SUM(IF(transaction_type='refund', amount, 0)) as total_refund"),
DB::raw("SUM(IF(transaction_type='refund', IF(pay_method='cash', amount, 0), 0)) as total_cash_refund"),
DB::raw("SUM(IF(transaction_type='refund', IF(pay_method='cheque', amount, 0), 0)) as total_cheque_refund"),
DB::raw("SUM(IF(transaction_type='refund', IF(pay_method='card', amount, 0), 0)) as total_card_refund"),
DB::raw("SUM(IF(transaction_type='refund', IF(pay_method='bank_transfer', amount, 0), 0)) as total_bank_transfer_refund"),
DB::raw("SUM(IF(transaction_type='refund', IF(pay_method='other', amount, 0), 0)) as total_other_refund"),
DB::raw("SUM(IF(transaction_type='refund', IF(pay_method='advance', amount, 0), 0)) as total_advance_refund"),
DB::raw("SUM(IF(transaction_type='refund', IF(pay_method='custom_pay_1', amount, 0), 0)) as total_custom_pay_1_refund"),
DB::raw("SUM(IF(transaction_type='refund', IF(pay_method='custom_pay_2', amount, 0), 0)) as total_custom_pay_2_refund"),
DB::raw("SUM(IF(transaction_type='refund', IF(pay_method='custom_pay_3', amount, 0), 0)) as total_custom_pay_3_refund"),
DB::raw("SUM(IF(transaction_type='refund', IF(pay_method='custom_pay_4', amount, 0), 0)) as total_custom_pay_4_refund"),
DB::raw("SUM(IF(transaction_type='refund', IF(pay_method='custom_pay_5', amount, 0), 0)) as total_custom_pay_5_refund"),
DB::raw("SUM(IF(transaction_type='refund', IF(pay_method='custom_pay_6', amount, 0), 0)) as total_custom_pay_6_refund"),
DB::raw("SUM(IF(transaction_type='refund', IF(pay_method='custom_pay_7', amount, 0), 0)) as total_custom_pay_7_refund"),
DB::raw("SUM(IF(pay_method='cheque', 1, 0)) as total_cheques"),
DB::raw("SUM(IF(pay_method='card', 1, 0)) as total_card_slips"),
DB::raw("CONCAT(COALESCE(surname, ''), ' ', COALESCE(first_name, ''), ' ', COALESCE(last_name, '')) as user_name"),
'u.email',
'bl.name as location_name'
)->first();
// ADD DUE COLLECTION CASH TO TOTAL CASH
if ($register_details) {
$open_time = $register_details->open_time;
$close_time = \Carbon::now()->toDateTimeString();
// Get due collection cash payments
$due_cash_collections = $this->getTodayDueCashCollections($register_details->register_id, $open_time, $close_time);
// Add due collections to total cash
$register_details->total_cash = ($register_details->total_cash ?? 0) + $due_cash_collections;
$register_details->due_cash_collections = $due_cash_collections; // For reference
}
return $register_details;
}
2.3 Update getCloseRegister Method (Optional)โ
If you want the same feature in your close register modal, update your getCloseRegister()
method:
Now update your app/Http/Controllers/CashRegisterController.php
to call the utility method.
public function getCloseRegister($id = null)
{
if (! auth()->user()->can('close_cash_register')) {
abort(403, 'Unauthorized action.');
}
$business_id = request()->session()->get('user.business_id');
$register_details = $this->cashRegisterUtil->getRegisterDetails($id);
$user_id = $register_details->user_id;
$open_time = $register_details['open_time'];
$close_time = \Carbon::now()->toDateTimeString();
$is_types_of_service_enabled = $this->moduleUtil->isModuleEnabled('types_of_service');
$details = $this->cashRegisterUtil->getRegisterTransactionDetails($user_id, $open_time, $close_time, $is_types_of_service_enabled);
// Add due collections data for close register modal too
$due_collections = $this->cashRegisterUtil->getTodayDueCollections($user_id, $open_time, $close_time);
$details['due_collections'] = $due_collections;
$payment_types = $this->cashRegisterUtil->payment_types($register_details->location_id, true, $business_id);
$pos_settings = ! empty(request()->session()->get('business.pos_settings')) ? json_decode(request()->session()->get('business.pos_settings'), true) : [];
return view('cash_register.close_register_modal')
->with(compact('register_details', 'details', 'payment_types', 'pos_settings'));
}
Step 2: Update the Register Details Viewโ
Update your resources/views/cash_register/register_details.blade.php
file.
2.1 Add Due Collections Sectionโ
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header mini_print">
<button type="button" class="close no-print" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">×</span></button>
<h3 class="modal-title">@lang( 'cash_register.register_details' ) ( {{ \Carbon::createFromFormat('Y-m-d H:i:s',
$register_details->open_time)->format('jS M, Y h:i A') }} - {{\Carbon::createFromFormat('Y-m-d H:i:s',
$close_time)->format('jS M, Y h:i A')}} )</h3>
</div>
<div class="modal-body">
@include('cash_register.payment_details')
<!-- Add Due Collections Section -->
@if(isset($details['due_collections']))
<hr class="no-print">
<div class="row no-print">
<div class="col-md-12">
<h4><i class="fa fa-clock-o"></i> @lang('lang_v1.due_collections_today')</h4>
<div class="row">
<div class="col-md-4">
<div class="info-box bg-green due-collection-box">
<span class="info-box-icon due-collection-icon">
<i class="fa fa-check-circle"></i>
</span>
<div class="info-box-content">
<span class="info-box-text due-collection-title">@lang('lang_v1.collected_today')</span>
<span class="info-box-number due-collection-amount">
@format_currency($details['due_collections']['due_collected_today'])
</span>
<span class="progress-description due-collection-desc">
{{ $details['due_collections']['due_transactions_count'] }} @lang('lang_v1.transactions')
</span>
</div>
</div>
</div>
<div class="col-md-4">
<div class="info-box bg-yellow due-collection-box">
<span class="info-box-icon due-collection-icon">
<i class="fa fa-exclamation-triangle"></i>
</span>
<div class="info-box-content">
<span class="info-box-text due-collection-title">@lang('lang_v1.pending_due_today')</span>
<span class="info-box-number due-collection-amount">
@format_currency($details['due_collections']['pending_due_today'])
</span>
<span class="progress-description due-collection-desc">
{{ $details['due_collections']['pending_transactions_count'] }} @lang('lang_v1.transactions')
</span>
</div>
</div>
</div>
@if($details['due_collections']['overdue_amount'] > 0)
<div class="col-md-4">
<div class="info-box bg-red due-collection-box">
<span class="info-box-icon due-collection-icon">
<i class="fa fa-exclamation-circle"></i>
</span>
<div class="info-box-content">
<span class="info-box-text due-collection-title">@lang('lang_v1.overdue_amounts')</span>
<span class="info-box-number due-collection-amount">
@format_currency($details['due_collections']['overdue_amount'])
</span>
<span class="progress-description due-collection-desc">
{{ $details['due_collections']['overdue_transactions_count'] }} @lang('lang_v1.transactions')
</span>
</div>
</div>
</div>
@endif
</div>
</div>
</div>
@endif
<hr>
@if(!empty($register_details->denominations))
@php
$total = 0;
@endphp
<div class="row">
<div class="col-md-8 col-sm-12">
<h3>@lang( 'lang_v1.cash_denominations' )</h3>
<table class="table table-slim">
<thead>
<tr>
<th width="20%" class="text-right">@lang('lang_v1.denomination')</th>
<th width="20%"> </th>
<th width="20%" class="text-center">@lang('lang_v1.count')</th>
<th width="20%"> </th>
<th width="20%" class="text-left">@lang('sale.subtotal')</th>
</tr>
</thead>
<tbody>
@foreach($register_details->denominations as $key => $value)
<tr>
<td class="text-right">{{$key}}</td>
<td class="text-center">X</td>
<td class="text-center">{{$value ?? 0}}</td>
<td class="text-center">=</td>
<td class="text-left">
@format_currency($key * $value)
</td>
</tr>
@php
$total += ($key * $value);
@endphp
@endforeach
</tbody>
<tfoot>
<tr>
<th colspan="4" class="text-center">@lang('sale.total')</th>
<td>@format_currency($total)</td>
</tr>
</tfoot>
</table>
</div>
</div>
@endif
<div class="row">
<div class="col-xs-6">
<b>@lang('report.user'):</b> {{ $register_details->user_name}}<br>
<b>@lang('business.email'):</b> {{ $register_details->email}}<br>
<b>@lang('business.business_location'):</b> {{ $register_details->location_name}}<br>
</div>
@if(!empty($register_details->closing_note))
<div class="col-xs-6">
<strong>@lang('cash_register.closing_note'):</strong><br>
{{$register_details->closing_note}}
</div>
@endif
</div>
</div>
<div class="modal-footer">
<button type="button" class="tw-dw-btn tw-dw-btn-primary tw-text-white no-print print-mini-button"
aria-label="Print">
<i class="fa fa-print"></i> @lang('messages.print_mini')
</button>
<button type="button" class="tw-dw-btn tw-dw-btn-primary tw-text-white no-print" aria-label="Print"
onclick="$(this).closest('div.modal').printThis();">
<i class="fa fa-print"></i> @lang( 'messages.print_detailed' )
</button>
<button type="button" class="tw-dw-btn tw-dw-btn-neutral tw-text-white no-print" data-dismiss="modal">@lang(
'messages.cancel' )
</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
<style type="text/css">
@media print {
.modal {
position: absolute;
left: 0;
top: 0;
margin: 0;
padding: 0;
overflow: visible !important;
}
.info-box {
border: 1px solid #ddd;
margin-bottom: 10px;
padding: 10px;
}
.info-box-icon {
display: none;
}
}
/* Due Collection Styling */
.due-collection-box {
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
overflow: hidden;
position: relative;
}
.due-collection-icon {
background: rgba(255, 255, 255, 0.2) !important;
color: white !important;
display: block !important;
width: 70px !important;
height: 70px !important;
line-height: 70px !important;
text-align: center !important;
float: left !important;
font-size: 30px !important;
border-radius: 0 !important;
}
.due-collection-icon i {
color: white !important;
font-size: 30px !important;
display: inline-block !important;
vertical-align: middle !important;
line-height: normal !important;
}
.due-collection-title {
color: white !important;
font-weight: bold;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.due-collection-amount {
color: white !important;
font-weight: bold;
font-size: 24px;
}
.due-collection-desc {
color: rgba(255, 255, 255, 0.9) !important;
font-size: 12px;
}
/* Ensure proper spacing and layout */
.due-collection-box .info-box-content {
margin-left: 85px;
padding: 15px 10px;
}
</style>
<script>
$(document).ready(function () {
$(document).on('click', '.print-mini-button', function () {
$('.mini_print').printThis();
});
});
</script>
2.2 Add CSS Stylingโ
Add this CSS to your view file (before the closing </div>
tags):
<style type="text/css">
@media print {
.modal {
position: absolute;
left: 0;
top: 0;
margin: 0;
padding: 0;
overflow: visible!important;
}
.info-box {
border: 1px solid #ddd;
margin-bottom: 10px;
padding: 10px;
}
.info-box-icon {
display: none;
}
}
/* Due Collection Styling */
.due-collection-box {
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
overflow: hidden;
position: relative;
}
.due-collection-icon {
background: rgba(255,255,255,0.2) !important;
color: white !important;
display: block !important;
width: 70px !important;
height: 70px !important;
line-height: 70px !important;
text-align: center !important;
float: left !important;
font-size: 30px !important;
border-radius: 0 !important;
}
.due-collection-icon i {
color: white !important;
font-size: 30px !important;
display: inline-block !important;
vertical-align: middle !important;
line-height: normal !important;
}
.due-collection-title {
color: white !important;
font-weight: bold;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.due-collection-amount {
color: white !important;
font-weight: bold;
font-size: 24px;
}
.due-collection-desc {
color: rgba(255,255,255,0.9) !important;
font-size: 12px;
}
.due-collection-box .info-box-content {
margin-left: 85px;
padding: 15px 10px;
}
</style>
Step 3: Add Language Entriesโ
Add these entries to your resources/lang/en/lang_v1.php
file:
return [
// ... existing entries ...
'due_collections_today' => 'Today\'s Due Collections',
'collected_today' => 'Collected Today',
'pending_due_today' => 'Pending Due Today',
'overdue_amounts' => 'Overdue Amounts',
'transactions' => 'Transactions',
// ... rest of your language entries ...
];
Step 4: Update Close Register Modal (Optional)โ
If you want the same feature in your close register modal, update your resources/views/cash_register/close_register.blade.php
with the same due collections section and CSS.
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
{!! Form::open(['url' => action([\App\Http\Controllers\CashRegisterController::class, 'postCloseRegister']),
'method' => 'post' ]) !!}
{!! Form::hidden('user_id', $register_details->user_id); !!}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">×</span></button>
<h3 class="modal-title">@lang( 'cash_register.current_register' ) ( {{ \Carbon::createFromFormat('Y-m-d H:i:s',
$register_details->open_time)->format('jS M, Y h:i A') }} - {{ \Carbon::now()->format('jS M, Y h:i A') }})</h3>
</div>
<div class="modal-body">
@include('cash_register.payment_details')
<!-- Add Due Collections Section -->
@if(isset($details['due_collections']))
<hr class="no-print">
<div class="row no-print">
<div class="col-md-12">
<h4><i class="fa fa-clock-o"></i> @lang('lang_v1.due_collections_today')</h4>
<div class="row">
<div class="col-md-4">
<div class="info-box bg-green due-collection-box">
<span class="info-box-icon due-collection-icon">
<i class="fa fa-check-circle"></i>
</span>
<div class="info-box-content">
<span class="info-box-text due-collection-title">@lang('lang_v1.collected_today')</span>
<span class="info-box-number due-collection-amount">
@format_currency($details['due_collections']['due_collected_today'])
</span>
<span class="progress-description due-collection-desc">
{{ $details['due_collections']['due_transactions_count'] }} @lang('lang_v1.transactions')
</span>
</div>
</div>
</div>
<div class="col-md-4">
<div class="info-box bg-yellow due-collection-box">
<span class="info-box-icon due-collection-icon">
<i class="fa fa-exclamation-triangle"></i>
</span>
<div class="info-box-content">
<span class="info-box-text due-collection-title">@lang('lang_v1.pending_due_today')</span>
<span class="info-box-number due-collection-amount">
@format_currency($details['due_collections']['pending_due_today'])
</span>
<span class="progress-description due-collection-desc">
{{ $details['due_collections']['pending_transactions_count'] }} @lang('lang_v1.transactions')
</span>
</div>
</div>
</div>
@if($details['due_collections']['overdue_amount'] > 0)
<div class="col-md-4">
<div class="info-box bg-red due-collection-box">
<span class="info-box-icon due-collection-icon">
<i class="fa fa-exclamation-circle"></i>
</span>
<div class="info-box-content">
<span class="info-box-text due-collection-title">@lang('lang_v1.overdue_amounts')</span>
<span class="info-box-number due-collection-amount">
@format_currency($details['due_collections']['overdue_amount'])
</span>
<span class="progress-description due-collection-desc">
{{ $details['due_collections']['overdue_transactions_count'] }} @lang('lang_v1.transactions')
</span>
</div>
</div>
</div>
@endif
</div>
</div>
</div>
@endif
<hr>
<div class="row">
<div class="col-sm-4">
<div class="form-group">
{!! Form::label('closing_amount', __( 'cash_register.total_cash' ) . ':*') !!}
{!! Form::text('closing_amount', @num_format($register_details->cash_in_hand + $register_details->total_cash
- $register_details->total_cash_refund - $register_details->total_cash_expense), ['class' => 'form-control
input_number', 'required', 'placeholder' => __( 'cash_register.total_cash' ) ]); !!}
</div>
</div>
<div class="col-sm-4">
<div class="form-group">
{!! Form::label('total_card_slips', __( 'cash_register.total_card_slips' ) . ':*') !!}
@show_tooltip(__('tooltip.total_card_slips'))
{!! Form::number('total_card_slips', $register_details->total_card_slips, ['class' => 'form-control',
'required', 'placeholder' => __( 'cash_register.total_card_slips' ), 'min' => 0 ]); !!}
</div>
</div>
<div class="col-sm-4">
<div class="form-group">
{!! Form::label('total_cheques', __( 'cash_register.total_cheques' ) . ':*') !!}
@show_tooltip(__('tooltip.total_cheques'))
{!! Form::number('total_cheques', $register_details->total_cheques, ['class' => 'form-control', 'required',
'placeholder' => __( 'cash_register.total_cheques' ), 'min' => 0 ]); !!}
</div>
</div>
<hr>
<div class="col-md-8 col-sm-12">
<h3>@lang( 'lang_v1.cash_denominations' )</h3>
@if(!empty($pos_settings['cash_denominations']))
<table class="table table-slim">
<thead>
<tr>
<th width="20%" class="text-right">@lang('lang_v1.denomination')</th>
<th width="20%"> </th>
<th width="20%" class="text-center">@lang('lang_v1.count')</th>
<th width="20%"> </th>
<th width="20%" class="text-left">@lang('sale.subtotal')</th>
</tr>
</thead>
<tbody>
@foreach(explode(',', $pos_settings['cash_denominations']) as $dnm)
<tr>
<td class="text-right">{{$dnm}}</td>
<td class="text-center">X</td>
<td>{!! Form::number("denominations[$dnm]", null, ['class' => 'form-control cash_denomination input-sm',
'min' => 0, 'data-denomination' => $dnm, 'style' => 'width: 100px; margin:auto;' ]); !!}</td>
<td class="text-center">=</td>
<td class="text-left">
<span class="denomination_subtotal">0</span>
</td>
</tr>
@endforeach
</tbody>
<tfoot>
<tr>
<th colspan="4" class="text-center">@lang('sale.total')</th>
<td><span class="denomination_total">0</span></td>
</tr>
</tfoot>
</table>
@else
<p class="help-block">@lang('lang_v1.denomination_add_help_text')</p>
@endif
</div>
<hr>
<div class="col-sm-12">
<div class="form-group">
{!! Form::label('closing_note', __( 'cash_register.closing_note' ) . ':') !!}
{!! Form::textarea('closing_note', null, ['class' => 'form-control', 'placeholder' => __(
'cash_register.closing_note' ), 'rows' => 3 ]); !!}
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<b>@lang('report.user'):</b> {{ $register_details->user_name}}<br>
<b>@lang('business.email'):</b> {{ $register_details->email}}<br>
<b>@lang('business.business_location'):</b> {{ $register_details->location_name}}<br>
</div>
@if(!empty($register_details->closing_note))
<div class="col-xs-6">
<strong>@lang('cash_register.closing_note'):</strong><br>
{{$register_details->closing_note}}
</div>
@endif
</div>
</div>
<div class="modal-footer">
<button type="button" class="tw-dw-btn tw-dw-btn-neutral tw-text-white" data-dismiss="modal">@lang(
'messages.cancel' )</button>
<button type="submit" class="tw-dw-btn tw-dw-btn-primary tw-text-white">@lang( 'cash_register.close_register'
)</button>
</div>
{!! Form::close() !!}
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
<style type="text/css">
@media print {
.modal {
position: absolute;
left: 0;
top: 0;
margin: 0;
padding: 0;
overflow: visible !important;
}
.info-box {
border: 1px solid #ddd;
margin-bottom: 10px;
padding: 10px;
}
.info-box-icon {
display: none;
}
}
/* Due Collection Styling for Close Register Modal */
.due-collection-box {
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
overflow: hidden;
position: relative;
}
.due-collection-icon {
background: rgba(255, 255, 255, 0.2) !important;
color: white !important;
display: block !important;
width: 70px !important;
height: 70px !important;
line-height: 70px !important;
text-align: center !important;
float: left !important;
font-size: 30px !important;
border-radius: 0 !important;
}
.due-collection-icon i {
color: white !important;
font-size: 30px !important;
display: inline-block !important;
vertical-align: middle !important;
line-height: normal !important;
}
.due-collection-title {
color: white !important;
font-weight: bold;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.due-collection-amount {
color: white !important;
font-weight: bold;
font-size: 24px;
}
.due-collection-desc {
color: rgba(255, 255, 255, 0.9) !important;
font-size: 12px;
}
/* Ensure proper spacing and layout */
.due-collection-box .info-box-content {
margin-left: 85px;
padding: 15px 10px;
}
</style>
๐งช Testingโ
Test Scenariosโ
- Create a credit sale: Make a sale with partial payment
- Collect due payment: Pay the remaining amount today
- Check register details: Verify "Collected Today" shows the payment
- Create overdue transactions: Make sales from previous days with unpaid amounts
- Verify overdue display: Check that red overdue box appears when applicable
Expected Resultsโ
- โ Collected Today: Shows all due payments received today
- โ Pending Due Today: Shows unpaid amounts from today's sales
- โ Overdue Amounts: Shows only when there are actually overdue transactions
- โ Transaction Counts: Accurate count of affected transactions
- โ Responsive Design: Works on mobile and desktop
- โ Print Friendly: Looks good when printed
๐จ Customizationโ
Changing Colorsโ
You can customize the box colors by modifying the Bootstrap classes:
<!-- Green for collected -->
<div class="info-box bg-green due-collection-box">
<!-- Yellow/Orange for pending -->
<div class="info-box bg-yellow due-collection-box">
<!-- Red for overdue -->
<div class="info-box bg-red due-collection-box">
Adding More Iconsโ
Replace the Font Awesome icons with your preferred ones:
<!-- Available alternatives -->
<i class="fa fa-money"></i> <!-- Money icon -->
<i class="fa fa-clock-o"></i> <!-- Clock icon -->
<i class="fa fa-warning"></i> <!-- Warning icon -->
<i class="fa fa-calendar"></i> <!-- Calendar icon -->
Modifying Layoutโ
Change from 3 boxes to 2 boxes by removing the overdue section or adjust column sizes:
<!-- For 2 equal boxes -->
<div class="col-md-6">
<!-- For 3 equal boxes -->
<div class="col-md-4">
๐ง Troubleshootingโ
Common Issuesโ
Issue: Icons not showing
- Solution: Ensure Font Awesome is loaded in your layout
- Alternative: Use text symbols or different icon libraries
Issue: Data not appearing
- Solution: Check that
$details['due_collections']
is being passed to the view - Debug: Add
{{ dd($details) }}
to see what data is available
Issue: Incorrect amounts
- Solution: Verify your database relationships match the query structure
- Check: Ensure
business_id
is correctly set in session
Issue: Styling conflicts
- Solution: Use more specific CSS selectors or
!important
declarations - Alternative: Move CSS to a separate file
Database Requirementsโ
Ensure your database has these tables and relationships:
transactions
table withbusiness_id
,payment_status
,type
,status
columnstransaction_payments
table withtransaction_id
,amount
,paid_on
columns- Proper foreign key relationships between tables
๐ Summaryโ
You've successfully implemented a comprehensive due collections display that provides:
- Real-time visibility into payment collections
- Business-wide data for better decision making
- Professional UI with responsive design
- Smart conditional display for optimal user experience
This feature will help your business track due collections more effectively and improve cash flow management.