Commission Agent Implementation Guide
This guide walks you through implementing a commission agent column and filter in the sells list DataTable.
Overview​
We'll add:
- Commission agent filter dropdown
- Commission agent column in the DataTable
- Backend logic to handle commission agent data
Step 1: Update the Controller (SellController.php)​
1.1 Update Commission Agent Logic in index()
Method​
Since the filter partial expects $is_cmsn_agent_enabled
and $commission_agents
, update your controller:
public function index()
{
// ... existing code ...
$business_id = request()->session()->get('user.business_id');
// Update this section to match the partial expectations
$business_details = $this->businessUtil->getDetails($business_id);
$is_cmsn_agent_enabled = !empty($business_details->sales_cmsn_agnt);
$commission_agents = [];
if ($is_cmsn_agent_enabled) {
$commsn_agnt_setting = $business_details->sales_cmsn_agnt;
if ($commsn_agnt_setting == 'user') {
$commission_agents = User::forDropdown($business_id);
} elseif ($commsn_agnt_setting == 'cmsn_agnt') {
$commission_agents = User::saleCommissionAgentsDropdown($business_id);
}
}
// ... rest of existing code ...
}
1.2 Add Commission Agent Filter in AJAX Section​
In the AJAX section where filters are applied, add:
if (request()->ajax()) {
// ... existing filters ...
// Add commission agent filter
if (!empty(request()->input('sales_cmsn_agnt'))) {
$sells->where('transactions.commission_agent', request()->input('sales_cmsn_agnt'));
}
// ... rest of the AJAX logic ...
}
1.3 Add Commission Agent to DataTable Columns​
In the DataTable configuration, add the commission agent column:
$datatable = Datatables::of($sells)
// ... existing columns ...
->addColumn('commission_agent_name', function ($row) {
return $row->commission_agent_name ?? '';
})
// ... rest of columns ...
1.4 Update the Return Statement​
return view('sell.index')
->with(compact(
'business_locations',
'customers',
'is_woocommerce',
'sales_representative',
'is_cmsn_agent_enabled', // This variable is expected by the partial
'commission_agents', // This too
'service_staffs',
'is_tables_enabled',
'is_service_staff_enabled',
'is_types_service_enabled',
'shipping_statuses',
'sources',
'payment_types'
));
Step 2: Update the Query to Include Commission Agent Data​
2.1 Modify the getListSells()
Method​
In your TransactionUtil
class, add the commission agent join and select to the existing query:
public function getListSells($business_id, $sale_type = 'sell')
{
$sells = Transaction::leftJoin('contacts', 'transactions.contact_id', '=', 'contacts.id')
// ->leftJoin('transaction_payments as tp', 'transactions.id', '=', 'tp.transaction_id')
->leftJoin('transaction_sell_lines as tsl', function ($join) {
$join->on('transactions.id', '=', 'tsl.transaction_id')
->whereNull('tsl.parent_sell_line_id');
})
->leftJoin('users as u', 'transactions.created_by', '=', 'u.id')
->leftJoin('users as ss', 'transactions.res_waiter_id', '=', 'ss.id')
->leftJoin('users as dp', 'transactions.delivery_person', '=', 'dp.id')
// ADD THIS LINE: Join with commission agent
->leftJoin('users as ca', 'transactions.commission_agent', '=', 'ca.id')
->leftJoin('res_tables as tables', 'transactions.res_table_id', '=', 'tables.id')
->join(
'business_locations AS bl',
'transactions.location_id',
'=',
'bl.id'
)
->leftJoin(
'transactions AS SR',
'transactions.id',
'=',
'SR.return_parent_id'
)
->leftJoin(
'types_of_services AS tos',
'transactions.types_of_service_id',
'=',
'tos.id'
)
->where('transactions.business_id', $business_id)
->where('transactions.type', $sale_type)
->select(
'transactions.id',
'transactions.transaction_date',
'transactions.type',
'transactions.is_direct_sale',
'transactions.invoice_no',
'transactions.invoice_no as invoice_no_text',
'contacts.name',
'contacts.mobile',
'contacts.contact_id',
'contacts.supplier_business_name',
'transactions.status',
'transactions.payment_status',
'transactions.final_total',
'transactions.tax_amount',
'transactions.discount_amount',
'transactions.discount_type',
'transactions.total_before_tax',
'transactions.rp_redeemed',
'transactions.rp_redeemed_amount',
'transactions.rp_earned',
'transactions.types_of_service_id',
'transactions.shipping_status',
'transactions.pay_term_number',
'transactions.pay_term_type',
'transactions.additional_notes',
'transactions.staff_note',
'transactions.shipping_details',
'transactions.document',
'transactions.shipping_custom_field_1',
'transactions.shipping_custom_field_2',
'transactions.shipping_custom_field_3',
'transactions.shipping_custom_field_4',
'transactions.shipping_custom_field_5',
'transactions.custom_field_1',
'transactions.custom_field_2',
'transactions.custom_field_3',
'transactions.custom_field_4',
DB::raw('DATE_FORMAT(transactions.transaction_date, "%Y/%m/%d") as sale_date'),
DB::raw("CONCAT(COALESCE(u.surname, ''),' ',COALESCE(u.first_name, ''),' ',COALESCE(u.last_name,'')) as added_by"),
DB::raw('(SELECT SUM(IF(TP.is_return = 1,-1*TP.amount,TP.amount)) FROM transaction_payments AS TP WHERE
TP.transaction_id=transactions.id) as total_paid'),
'bl.name as business_location',
DB::raw('COUNT(SR.id) as return_exists'),
DB::raw('(SELECT SUM(TP2.amount) FROM transaction_payments AS TP2 WHERE
TP2.transaction_id=SR.id ) as return_paid'),
DB::raw('COALESCE(SR.final_total, 0) as amount_return'),
'SR.id as return_transaction_id',
'tos.name as types_of_service_name',
'transactions.service_custom_field_1',
DB::raw('COUNT( DISTINCT tsl.id) as total_items'),
DB::raw("CONCAT(COALESCE(ss.surname, ''),' ',COALESCE(ss.first_name, ''),' ',COALESCE(ss.last_name,'')) as waiter"),
'tables.name as table_name',
DB::raw('SUM(tsl.quantity - tsl.so_quantity_invoiced) as so_qty_remaining'),
'transactions.is_export',
DB::raw("CONCAT(COALESCE(dp.surname, ''),' ',COALESCE(dp.first_name, ''),' ',COALESCE(dp.last_name,'')) as delivery_person"),
// ADD THIS LINE: Select commission agent name
DB::raw("CONCAT(COALESCE(ca.surname, ''),' ',COALESCE(ca.first_name, ''),' ',COALESCE(ca.last_name,'')) as commission_agent_name")
);
if ($sale_type == 'sell') {
$sells->where('transactions.status', 'final');
}
return $sells;
}
Key Changes:
- Added
->leftJoin('users as ca', 'transactions.commission_agent', '=', 'ca.id')
after the other user joins - Added commission agent name to the select statement at the end
## Step 3: Update the Blade Template (sell/index.blade.php)
### 3.1 Commission Agent Filter (Already Implemented)
✅ **Good news!** The commission agent filter is already implemented in your `sell_list_filters.blade.php` partial:
```blade
@if(empty($only) || in_array('sales_cmsn_agnt', $only))
@if(!empty($is_cmsn_agent_enabled))
<div class="col-md-3">
<div class="form-group">
{!! Form::label('sales_cmsn_agnt', __('lang_v1.sales_commission_agent') . ':') !!}
{!! Form::select('sales_cmsn_agnt', $commission_agents, null, ['class' => 'form-control select2', 'style' => 'width:100%']); !!}
</div>
</div>
@endif
@endif
Note: The filter uses $is_cmsn_agent_enabled
instead of checking $commission_agents
directly. Make sure this variable is passed from the controller.
3.2 Add Commission Agent Column to Table Header​
<table class="table table-bordered table-striped ajax_view" id="sell_table">
<thead>
<tr>
<th>@lang('messages.action')</th>
<th>@lang('messages.date')</th>
<th>@lang('sale.invoice_no')</th>
<th>@lang('sale.customer_name')</th>
<th>@lang('lang_v1.contact_no')</th>
<th>@lang('sale.location')</th>
<th>@lang('sale.payment_status')</th>
<th>@lang('lang_v1.payment_method')</th>
<th>@lang('sale.total_amount')</th>
<th>@lang('sale.total_paid')</th>
<th>@lang('lang_v1.sell_due')</th>
<th>@lang('lang_v1.sell_return_due')</th>
<th>@lang('lang_v1.shipping_status')</th>
<th>@lang('lang_v1.total_items')</th>
{{-- Add commission agent column --}}
<th>@lang('lang_v1.commission_agent')</th>
<th>@lang('lang_v1.types_of_service')</th>
{{-- ... rest of columns ... --}}
</tr>
</thead>
</table>
Step 4: Update JavaScript DataTable Configuration​
4.1 Add Commission Agent Column to DataTable​
sell_table = $('#sell_table').DataTable({
processing: true,
serverSide: true,
fixedHeader: false,
aaSorting: [[1, 'desc']],
"ajax": {
"url": "/sells",
"data": function(d) {
// ... existing filters ...
// Add commission agent filter
d.sales_cmsn_agnt = $('#sales_cmsn_agnt').val();
// ... rest of data function ...
}
},
columns: [
{ data: 'action', name: 'action', orderable: false, "searchable": false },
{ data: 'transaction_date', name: 'transaction_date' },
{ data: 'invoice_no', name: 'invoice_no' },
{ data: 'conatct_name', name: 'conatct_name' },
{ data: 'mobile', name: 'contacts.mobile' },
{ data: 'business_location', name: 'bl.name' },
{ data: 'payment_status', name: 'payment_status' },
{ data: 'payment_methods', orderable: false, "searchable": false },
{ data: 'final_total', name: 'final_total' },
{ data: 'total_paid', name: 'total_paid', "searchable": false },
{ data: 'total_remaining', name: 'total_remaining' },
{ data: 'return_due', orderable: false, "searchable": false },
{ data: 'shipping_status', name: 'shipping_status' },
{ data: 'total_items', name: 'total_items', "searchable": false },
// Add commission agent column
{
data: 'commission_agent_name',
name: 'ca.first_name',
@if (empty($commission_agents))
visible: false
@endif
},
// ... rest of columns ...
],
// ... rest of configuration ...
});
4.2 Add Filter Change Event Handler​
$(document).on('change',
'#sell_list_filter_location_id, #sell_list_filter_customer_id, #sell_list_filter_payment_status, #created_by, #sales_cmsn_agnt, #service_staffs, #shipping_status, #sell_list_filter_source, #payment_method',
function() {
sell_table.ajax.reload();
}
);
Step 5: Update Language Files (Optional)​
Add translation keys if they don't exist:
// In resources/lang/en/lang_v1.php
'commission_agent' => 'Commission Agent',
Step 6: Verify User Model Method​
Ensure the saleCommissionAgentsDropdown
method exists in your User model:
/**
* Return list of sales commission agents dropdown for a business
*
* @param $business_id int
* @param $prepend_none = true (boolean)
* @return array users
*/
public static function saleCommissionAgentsDropdown($business_id, $prepend_none = true)
{
$all_cmmsn_agnts = User::where('business_id', $business_id)
->where('is_cmmsn_agnt', 1)
->select('id', DB::raw("CONCAT(COALESCE(surname, ''),' ',COALESCE(first_name, ''),' ',COALESCE(last_name,'')) as full_name"));
$users = $all_cmmsn_agnts->pluck('full_name', 'id');
//Prepend none
if ($prepend_none) {
$users = $users->prepend(__('lang_v1.none'), '');
}
return $users;
}
Step 7: Add Commission Agent to POS Sells List​
7.1 POS Controller Setup (Already Complete)​
✅ Good news! Your POS controller already has the commission agent logic implemented:
public function index()
{
// ... existing code ...
$is_cmsn_agent_enabled = request()->session()->get('business.sales_cmsn_agnt');
$commission_agents = [];
if (!empty($is_cmsn_agent_enabled)) {
$commission_agents = User::forDropdown($business_id, false, true, true);
}
// ... rest of code ...
return view('sale_pos.index')->with(compact(
'business_locations',
'customers',
'sales_representative',
'is_cmsn_agent_enabled', // ✅ Already passed
'commission_agents', // ✅ Already passed
'service_staffs',
'is_tables_enabled',
'is_service_staff_enabled',
'is_types_service_enabled',
'shipping_statuses'
));
}
7.2 Update POS Sales Table Header​
In resources/views/sale_pos/partials/sales_table.blade.php
, add the commission agent column:
<table class="table table-bordered table-striped ajax_view" id="sell_table">
<thead>
<tr>
<th>@lang('messages.action')</th>
<th>@lang('messages.date')</th>
<th>@lang('sale.invoice_no')</th>
<th>@lang('sale.customer_name')</th>
<th>@lang('lang_v1.contact_no')</th>
<th>@lang('sale.location')</th>
<th>@lang('sale.payment_status')</th>
<th>@lang('lang_v1.payment_method')</th>
<th>@lang('sale.total_amount')</th>
<th>@lang('sale.total_paid')</th>
<th>@lang('lang_v1.sell_due')</th>
<th>@lang('lang_v1.sell_return_due')</th>
<th>@lang('lang_v1.shipping_status')</th>
<th>@lang('lang_v1.total_items')</th>
<th>@lang('lang_v1.types_of_service')</th>
<th>{{ $custom_labels['types_of_service']['custom_field_1'] ?? __('lang_v1.service_custom_field_1' )}}</th>
{{-- ADD THIS LINE: Commission Agent Column --}}
<th>@lang('lang_v1.sales_commission_agent')</th>
<th>@lang('lang_v1.added_by')</th>
<th>@lang('sale.sell_note')</th>
<th>@lang('sale.staff_note')</th>
<th>@lang('sale.shipping_details')</th>
<th>@lang('restaurant.table')</th>
<th>@lang('restaurant.service_staff')</th>
</tr>
</thead>
<tfoot>
<tr class="bg-gray font-17 footer-total text-center">
<td colspan="6"><strong>@lang('sale.total'):</strong></td>
<td class="footer_payment_status_count"></td>
<td class="payment_method_count"></td>
<td class="footer_sale_total"></td>
<td class="footer_total_paid"></td>
<td class="footer_total_remaining"></td>
<td class="footer_total_sell_return_due"></td>
<td colspan="2"></td>
<td class="service_type_count"></td>
{{-- UPDATE THIS LINE: Increase colspan from 7 to 8 --}}
<td colspan="8"></td>
</tr>
</tfoot>
</table>
7.3 Update POS DataTable JavaScript Configuration​
In resources/views/sale_pos/partials/sale_table_javascript.blade.php
, add the commission agent column:
columns: [
{ data: 'action', name: 'action', orderable: false, "searchable": false},
{ data: 'transaction_date', name: 'transaction_date' },
{ data: 'invoice_no', name: 'invoice_no'},
{ data: 'conatct_name', name: 'conatct_name'},
{ data: 'mobile', name: 'contacts.mobile'},
{ data: 'business_location', name: 'bl.name'},
{ data: 'payment_status', name: 'payment_status'},
{ data: 'payment_methods', orderable: false, "searchable": false},
{ data: 'final_total', name: 'final_total'},
{ data: 'total_paid', name: 'total_paid', "searchable": false},
{ data: 'total_remaining', name: 'total_remaining'},
{ data: 'return_due', orderable: false, "searchable": false},
{ data: 'shipping_status', name: 'shipping_status'},
{ data: 'total_items', name: 'total_items', "searchable": false},
{ data: 'types_of_service_name', name: 'tos.name', @if(empty($is_types_service_enabled)) visible: false @endif},
{ data: 'service_custom_field_1', name: 'service_custom_field_1', @if(empty($is_types_service_enabled)) visible: false @endif},
// ADD THIS LINE: Commission Agent Column
{ data: 'commission_agent_name', name: 'ca.first_name', @if(empty($is_cmsn_agent_enabled)) visible: false @endif},
{ data: 'added_by', name: 'u.first_name'},
{ data: 'additional_notes', name: 'additional_notes'},
{ data: 'staff_note', name: 'staff_note'},
{ data: 'shipping_details', name: 'shipping_details'},
{ data: 'table_name', name: 'tables.name', @if(empty($is_tables_enabled)) visible: false @endif },
{ data: 'waiter', name: 'ss.first_name', @if(empty($is_service_staff_enabled)) visible: false @endif }
],
7.4 Why POS Implementation is Simple​
The POS implementation is straightforward because:
- ✅ Filter Already Works: POS uses the same filter partial (
sell_list_filters.blade.php
) - ✅ Same AJAX Endpoint: POS uses the same
/sells
endpoint you already updated - ✅ Commission Agent Data Available: The query changes you made apply to both regular and POS sells
- ✅ Controller Variables Set: The POS controller already passes required variables
- ✅ Filter JavaScript Ready: The change event handler already includes
#sales_cmsn_agnt
7.5 Testing POS Implementation​
- Navigate to POS Sells List: Go to
/pos
- Check Filter: The commission agent filter should appear in the filters section
- Verify Column: The commission agent column should show/hide based on business settings
- Test Filtering: Select a commission agent and verify the table filters correctly
- Check Responsiveness: Ensure the table remains responsive with the new column
7.6 Notes​
- The commission agent column will automatically show/hide based on
$is_cmsn_agent_enabled
- No additional backend changes needed since POS uses the same data source
- The filter functionality works immediately since it uses the same backend logic
💛 Support this project
Binance ID:
478036326