Skip to main content

Edit Customer Button Implementation Guide

This guide shows how to add an Edit Customer button next to the existing Add Customer button in Ultimate POS. The edit button allows users to modify customer details directly from the POS interface without leaving the current screen.

Edit Customer Button

Implementation Tree Structure

your-laravel-project/
├── app/
│ └── Http/
│ └── Controllers/
│ └── ContactController.php # 📝 MODIFY
├── public/
│ └── js/
│ └── pos.js # 📝 MODIFY
├── resources/
│ └── views/
│ ├── contact/
│ │ └── edit_customer_modal.blade.php # ✨ CREATE
│ └── sale_pos/
│ ├── create.blade.php # 📝 MODIFY
│ ├── edit.blade.php # 📝 MODIFY
│ └── partials/
│ └── pos_form.blade.php # 📝 MODIFY
└── routes/
└── web.php # ✅ VERIFY ROUTE EXISTS

Files Overview

FileActionDescription
pos_form.blade.php📝 ModifyAdd edit button next to existing add button
create.blade.php📝 ModifyAdd edit modal container for POS create page
edit.blade.php📝 ModifyAdd edit modal container for POS edit page
ContactController.php📝 ModifyAdd modal handling to existing edit method
edit_customer_modal.blade.phpCreateNew modal template for editing customers
pos.js📝 ModifyAdd JavaScript functions for edit functionality
web.phpVerifyEnsure edit route exists (usually already present)

Features

  • ✅ Edit customer details in a modal popup
  • ✅ Automatic walk-in customer protection (cannot edit default customer)
  • ✅ Real-time customer dropdown updates after editing
  • ✅ Permission-based access control
  • ✅ Seamless integration with existing POS functionality
  • ✅ No interference with existing customer selection logic

Prerequisites

  • Ultimate POS with working customer functionality
  • Laravel framework with Blade templating
  • jQuery and existing POS JavaScript files
  • User permissions system in place

Implementation Steps

Step 1: Update POS Form Template

Update your resources/views/sale_pos/partials/pos_form.blade.php file to add the edit button.

Find this section:

<span class="input-group-btn">
<button
type="button"
class="btn btn-default bg-white btn-flat add_new_customer"
data-name=""
@if(!auth()-
>
user()->can('customer.create')) disabled @endif><i
class="fa fa-plus-circle text-primary fa-lg"
></i>
</button>
</span>

Replace with:

<span class="input-group-btn">
<button
type="button"
class="btn btn-default bg-white btn-flat add_new_customer"
data-name=""
@if(!auth()-
>
user()->can('customer.create')) disabled @endif><i
class="fa fa-plus-circle text-primary fa-lg"
></i>
</button>
<button
type="button"
class="btn btn-default bg-white btn-flat edit_customer"
@if(!auth()-
>
user()->can('customer.update')) disabled @endif><i
class="fa fa-edit text-warning fa-lg"
></i>
</button>
</span>

Step 2: Add Edit Modal Container

Add the modal container to both POS pages where the edit functionality is needed.

For POS Create Page

Add this to resources/views/sale_pos/create.blade.php (usually after the existing contact modal):

<!-- Edit Customer Modal - Content loaded via AJAX -->
<div class="modal fade contact_edit_modal" tabindex="-1" role="dialog">
<!-- Content will be loaded here via AJAX -->
</div>

For POS Edit Page

Add this to resources/views/sale_pos/edit.blade.php (usually after the existing contact modal):

<!-- Edit Customer Modal - Content loaded via AJAX -->
<div class="modal fade contact_edit_modal" tabindex="-1" role="dialog">
<!-- Content will be loaded here via AJAX -->
</div>

💡 Tip: Look for existing modal containers like <div class="modal fade contact_modal"> and add the edit modal container right after it.

📋 Note: Both create and edit pages need the modal container because:

  • create.blade.php - For new sales/transactions
  • edit.blade.php - For modifying existing sales/transactions

Step 3: Create Edit Customer Modal Template

Create a new file: resources/views/contact/edit_customer_modal.blade.php

<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
@if(isset($contact) && $contact)
@php
$url = action([\App\Http\Controllers\ContactController::class, 'update'], [$contact->id]);
$sources = [];
$life_stages = [];
$lead_users = [];
$assigned_to_users = $contact->userHavingAccess ? $contact->userHavingAccess->pluck('id') : [];
@endphp

{!! Form::open(['url' => $url, 'method' => 'PUT', 'id' => 'contact_edit_form']) !!}

<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title">@lang('contact.edit_contact')</h4>
</div>

<div class="modal-body">
<div class="row">
<div class="col-md-4">
<div class="form-group">
{!! Form::label('type', __('contact.contact_type') . ':*' ) !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-user"></i>
</span>
{!! Form::select('type', $types, $contact->type, ['class' => 'form-control', 'id' =>
'contact_type','placeholder' => __('messages.please_select'), 'required']); !!}
</div>
</div>
</div>
<div class="col-md-4 mt-15">
<label class="radio-inline">
<input type="radio" name="contact_type_radio" @if($contact->contact_type == 'individual')
checked @endif id="inlineRadio1" value="individual">
@lang('lang_v1.individual')
</label>
<label class="radio-inline">
<input type="radio" name="contact_type_radio" @if($contact->contact_type == 'business') checked
@endif id="inlineRadio2" value="business">
@lang('business.business')
</label>
</div>
<div class="col-md-4">
<div class="form-group">
{!! Form::label('contact_id', __('lang_v1.contact_id') . ':') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-id-badge"></i>
</span>
<input type="hidden" id="hidden_id" value="{{$contact->id}}">
{!! Form::text('contact_id', $contact->contact_id, ['class' => 'form-control','placeholder'
=> __('lang_v1.contact_id')]); !!}
</div>
<p class="help-block">
@lang('lang_v1.leave_empty_to_autogenerate')
</p>
</div>
</div>
<div class="col-md-4 customer_fields">
<div class="form-group">
{!! Form::label('customer_group_id', __('lang_v1.customer_group') . ':') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-users"></i>
</span>
{!! Form::select('customer_group_id', $customer_groups, $contact->customer_group_id,
['class' => 'form-control']); !!}
</div>
</div>
</div>
<div class="clearfix customer_fields"></div>
<div class="col-md-4 business" @if($contact->contact_type == 'individual' ||
empty($contact->contact_type)) style="display: none;" @endif>
<div class="form-group">
{!! Form::label('supplier_business_name', __('business.business_name') . ':') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-briefcase"></i>
</span>
{!! Form::text('supplier_business_name',
$contact->supplier_business_name, ['class' => 'form-control', 'placeholder' =>
__('business.business_name')]); !!}
</div>
</div>
</div>

<div class="clearfix"></div>

<div class="col-md-3 individual" @if($contact->contact_type == 'business' ||
empty($contact->contact_type)) style="display: none;" @endif>
<div class="form-group">
{!! Form::label('prefix', __( 'business.prefix' ) . ':') !!}
{!! Form::text('prefix', $contact->prefix, ['class' => 'form-control', 'placeholder' => __(
'business.prefix_placeholder' ) ]); !!}
</div>
</div>
<div class="col-md-3 individual" @if($contact->contact_type == 'business' ||
empty($contact->contact_type)) style="display: none;" @endif>
<div class="form-group">
{!! Form::label('first_name', __( 'business.first_name' ) . ':*') !!}
{!! Form::text('first_name', $contact->first_name, ['class' => 'form-control', 'required',
'placeholder' => __( 'business.first_name' ) ]); !!}
</div>
</div>
<div class="col-md-3 individual" @if($contact->contact_type == 'business' ||
empty($contact->contact_type)) style="display: none;" @endif>
<div class="form-group">
{!! Form::label('middle_name', __( 'lang_v1.middle_name' ) . ':') !!}
{!! Form::text('middle_name', $contact->middle_name, ['class' => 'form-control', 'placeholder'
=> __( 'lang_v1.middle_name' ) ]); !!}
</div>
</div>
<div class="col-md-3 individual" @if($contact->contact_type == 'business' ||
empty($contact->contact_type)) style="display: none;" @endif>
<div class="form-group">
{!! Form::label('last_name', __( 'business.last_name' ) . ':') !!}
{!! Form::text('last_name', $contact->last_name, ['class' => 'form-control', 'placeholder' =>
__( 'business.last_name' ) ]); !!}
</div>
</div>
<div class="clearfix"></div>

<div class="col-md-3">
<div class="form-group">
{!! Form::label('mobile', __('contact.mobile') . ':*') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-mobile"></i>
</span>
{!! Form::text('mobile', $contact->mobile, ['class' => 'form-control', 'required',
'placeholder' => __('contact.mobile')]); !!}
</div>
</div>
</div>

<div class="col-md-3">
<div class="form-group">
{!! Form::label('alternate_number', __('contact.alternate_contact_number') . ':') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-phone"></i>
</span>
{!! Form::text('alternate_number', $contact->alternate_number, ['class' => 'form-control',
'placeholder' => __('contact.alternate_contact_number')]); !!}
</div>
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('landline', __('contact.landline') . ':') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-phone"></i>
</span>
{!! Form::text('landline', $contact->landline, ['class' => 'form-control', 'placeholder' =>
__('contact.landline')]); !!}
</div>
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('email', __('business.email') . ':') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-envelope"></i>
</span>
{!! Form::email('email', $contact->email, ['class' => 'form-control','placeholder' =>
__('business.email')]); !!}
</div>
</div>
</div>
<div class="clearfix"></div>


@if(config('constants.enable_contact_assign') && $contact->type !== 'lead')
<!-- User in create customer & supplier -->
<div class="col-md-6">
<div class="form-group">
{!! Form::label('assigned_to_users', __('lang_v1.assigned_to') . ':' ) !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-user"></i>
</span>
{!! Form::select('assigned_to_users[]', $users, $assigned_to_users ?? [] , ['class' =>
'form-control select2', 'id' => 'assigned_to_users', 'multiple', 'style' => 'width:
100%;']); !!}
</div>
</div>
</div>
@endif

<div class="clearfix"></div>
</div>
<div class="row">
<div class="col-md-12">
<button type="button"
class="tw-dw-btn tw-dw-btn-primary tw-text-white tw-dw-btn-sm center-block more_btn"
data-target="#more_div">@lang('lang_v1.more_info') <i class="fa fa-chevron-down"></i></button>
</div>

<div id="more_div" class="hide">
{!! Form::hidden('position', $contact->position, ['id' => 'position']); !!}
<div class="col-md-12">
<hr />
</div>

<div class="col-md-4">
<div class="form-group">
{!! Form::label('tax_number', __('contact.tax_no') . ':') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-info"></i>
</span>
{!! Form::text('tax_number', $contact->tax_number, ['class' => 'form-control',
'placeholder' => __('contact.tax_no')]); !!}
</div>
</div>
</div>

<div class="col-md-4 opening_balance">
<div class="form-group">
{!! Form::label('opening_balance', __('lang_v1.opening_balance') . ':') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fas fa-money-bill-alt"></i>
</span>
{!! Form::text('opening_balance', $opening_balance, ['class' => 'form-control input_number']); !!}
</div>
</div>
</div>

<div class="col-md-4 pay_term">
<div class="form-group">
<div class="multi-input">
{!! Form::label('pay_term_number', __('contact.pay_term') . ':') !!}
@show_tooltip(__('tooltip.pay_term'))
<br />
{!! Form::number('pay_term_number', $contact->pay_term_number, ['class' => 'form-control
width-40 pull-left', 'placeholder' => __('contact.pay_term')]); !!}

{!! Form::select('pay_term_type', ['months' => __('lang_v1.months'), 'days' =>
__('lang_v1.days')], $contact->pay_term_type, ['class' => 'form-control width-60
pull-left','placeholder' => __('messages.please_select')]); !!}
</div>
</div>
</div>
<div class="clearfix"></div>

<div class="col-md-4 customer_fields">
<div class="form-group">
{!! Form::label('credit_limit', __('lang_v1.credit_limit') . ':') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fas fa-money-bill-alt"></i>
</span>
{!! Form::text('credit_limit', $contact->credit_limit != null ?
@num_format($contact->credit_limit) : null, ['class' => 'form-control input_number']);
!!}
</div>
<p class="help-block">@lang('lang_v1.credit_limit_help')</p>
</div>
</div>

<div class="col-md-12">
<hr />
</div>
<div class="clearfix"></div>

<div class="col-md-6">
<div class="form-group">
{!! Form::label('address_line_1', __('lang_v1.address_line_1') . ':') !!}
{!! Form::text('address_line_1', $contact->address_line_1, ['class' => 'form-control',
'placeholder' => __('lang_v1.address_line_1'), 'rows' => 3]); !!}
</div>
</div>
<div class="col-md-6">
<div class="form-group">
{!! Form::label('address_line_2', __('lang_v1.address_line_2') . ':') !!}
{!! Form::text('address_line_2', $contact->address_line_2, ['class' => 'form-control',
'placeholder' => __('lang_v1.address_line_2'), 'rows' => 3]); !!}
</div>
</div>
<div class="clearfix"></div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('city', __('business.city') . ':') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-map-marker"></i>
</span>
{!! Form::text('city', $contact->city, ['class' => 'form-control', 'placeholder' =>
__('business.city')]); !!}
</div>
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('state', __('business.state') . ':') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-map-marker"></i>
</span>
{!! Form::text('state', $contact->state, ['class' => 'form-control', 'placeholder' =>
__('business.state')]); !!}
</div>
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('country', __('business.country') . ':') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-globe"></i>
</span>
{!! Form::text('country', $contact->country, ['class' => 'form-control', 'placeholder'
=> __('business.country')]); !!}
</div>
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('zip_code', __('business.zip_code') . ':') !!}
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-map-marker"></i>
</span>
{!! Form::text('zip_code', $contact->zip_code, ['class' => 'form-control',
'placeholder' => __('business.zip_code_placeholder')]); !!}
</div>
</div>
</div>

<div class="clearfix"></div>
<div class="col-md-12">
<hr />
</div>
@php
$custom_labels = json_decode(session('business.custom_labels'), true);
$contact_custom_field1 = !empty($custom_labels['contact']['custom_field_1']) ?
$custom_labels['contact']['custom_field_1'] : __('lang_v1.contact_custom_field1');
$contact_custom_field2 = !empty($custom_labels['contact']['custom_field_2']) ?
$custom_labels['contact']['custom_field_2'] : __('lang_v1.contact_custom_field2');
$contact_custom_field3 = !empty($custom_labels['contact']['custom_field_3']) ?
$custom_labels['contact']['custom_field_3'] : __('lang_v1.contact_custom_field3');
$contact_custom_field4 = !empty($custom_labels['contact']['custom_field_4']) ?
$custom_labels['contact']['custom_field_4'] : __('lang_v1.contact_custom_field4');
$contact_custom_field5 = !empty($custom_labels['contact']['custom_field_5']) ?
$custom_labels['contact']['custom_field_5'] : __('lang_v1.custom_field', ['number' => 5]);
$contact_custom_field6 = !empty($custom_labels['contact']['custom_field_6']) ?
$custom_labels['contact']['custom_field_6'] : __('lang_v1.custom_field', ['number' => 6]);
$contact_custom_field7 = !empty($custom_labels['contact']['custom_field_7']) ?
$custom_labels['contact']['custom_field_7'] : __('lang_v1.custom_field', ['number' => 7]);
$contact_custom_field8 = !empty($custom_labels['contact']['custom_field_8']) ?
$custom_labels['contact']['custom_field_8'] : __('lang_v1.custom_field', ['number' => 8]);
$contact_custom_field9 = !empty($custom_labels['contact']['custom_field_9']) ?
$custom_labels['contact']['custom_field_9'] : __('lang_v1.custom_field', ['number' => 9]);
$contact_custom_field10 = !empty($custom_labels['contact']['custom_field_10']) ?
$custom_labels['contact']['custom_field_10'] : __('lang_v1.custom_field', ['number' => 10]);
@endphp
<div class="col-md-3">
<div class="form-group">
{!! Form::label('custom_field1', $contact_custom_field1 . ':') !!}
{!! Form::text('custom_field1', $contact->custom_field1, ['class' => 'form-control',
'placeholder' => $contact_custom_field1]); !!}
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('custom_field2', $contact_custom_field2 . ':') !!}
{!! Form::text('custom_field2', $contact->custom_field2, ['class' => 'form-control',
'placeholder' => $contact_custom_field2]); !!}
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('custom_field3', $contact_custom_field3 . ':') !!}
{!! Form::text('custom_field3', $contact->custom_field3, ['class' => 'form-control',
'placeholder' => $contact_custom_field3]); !!}
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('custom_field4', $contact_custom_field4 . ':') !!}
{!! Form::text('custom_field4', $contact->custom_field4, ['class' => 'form-control',
'placeholder' => $contact_custom_field4]); !!}
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('custom_field5', $contact_custom_field5 . ':') !!}
{!! Form::text('custom_field5', $contact->custom_field5, ['class' => 'form-control',
'placeholder' => $contact_custom_field5]); !!}
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('custom_field6', $contact_custom_field6 . ':') !!}
{!! Form::text('custom_field6', $contact->custom_field6, ['class' => 'form-control',
'placeholder' => $contact_custom_field6]); !!}
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('custom_field7', $contact_custom_field7 . ':') !!}
{!! Form::text('custom_field7', $contact->custom_field7, ['class' => 'form-control',
'placeholder' => $contact_custom_field7]); !!}
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('custom_field8', $contact_custom_field8 . ':') !!}
{!! Form::text('custom_field8', $contact->custom_field8, ['class' => 'form-control',
'placeholder' => $contact_custom_field8]); !!}
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('custom_field9', $contact_custom_field9 . ':') !!}
{!! Form::text('custom_field9', $contact->custom_field9, ['class' => 'form-control',
'placeholder' => $contact_custom_field9]); !!}
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{!! Form::label('custom_field10', $contact_custom_field10 . ':') !!}
{!! Form::text('custom_field10', $contact->custom_field10, ['class' => 'form-control',
'placeholder' => $contact_custom_field10]); !!}
</div>
</div>
<div class="col-md-12 shipping_addr_div">
<hr>
</div>

<div class="col-md-8 col-md-offset-2 shipping_addr_div mb-10">
<strong>{{__('lang_v1.shipping_address')}}</strong><br>
{!! Form::text('shipping_address', $contact->shipping_address, ['class' => 'form-control',
'placeholder' => __('lang_v1.search_address'), 'id' => 'shipping_address']); !!}
<div class="mb-10" id="map"></div>
</div>
@php
$shipping_custom_label_1 = !empty($custom_labels['shipping']['custom_field_1']) ?
$custom_labels['shipping']['custom_field_1'] : '';

$shipping_custom_label_2 = !empty($custom_labels['shipping']['custom_field_2']) ?
$custom_labels['shipping']['custom_field_2'] : '';

$shipping_custom_label_3 = !empty($custom_labels['shipping']['custom_field_3']) ?
$custom_labels['shipping']['custom_field_3'] : '';

$shipping_custom_label_4 = !empty($custom_labels['shipping']['custom_field_4']) ?
$custom_labels['shipping']['custom_field_4'] : '';

$shipping_custom_label_5 = !empty($custom_labels['shipping']['custom_field_5']) ?
$custom_labels['shipping']['custom_field_5'] : '';
@endphp

@if(!empty($custom_labels['shipping']['is_custom_field_1_contact_default']) &&
!empty($shipping_custom_label_1))
@php
$label_1 = $shipping_custom_label_1 . ':';
@endphp

<div class="col-md-4">
<div class="form-group">
{!! Form::label('shipping_custom_field_1', $label_1 ) !!}
{!! Form::text('shipping_custom_field_details[shipping_custom_field_1]',
!empty($contact->shipping_custom_field_details['shipping_custom_field_1']) ?
$contact->shipping_custom_field_details['shipping_custom_field_1'] : null, ['class' =>
'form-control','placeholder' => $shipping_custom_label_1]); !!}
</div>
</div>
@endif
@if(!empty($custom_labels['shipping']['is_custom_field_2_contact_default']) &&
!empty($shipping_custom_label_2))
@php
$label_2 = $shipping_custom_label_2 . ':';
@endphp

<div class="col-md-4">
<div class="form-group">
{!! Form::label('shipping_custom_field_2', $label_2 ) !!}
{!! Form::text('shipping_custom_field_details[shipping_custom_field_2]',
!empty($contact->shipping_custom_field_details['shipping_custom_field_2']) ?
$contact->shipping_custom_field_details['shipping_custom_field_2'] : null, ['class' =>
'form-control','placeholder' => $shipping_custom_label_2]); !!}
</div>
</div>
@endif
@if(!empty($custom_labels['shipping']['is_custom_field_3_contact_default']) &&
!empty($shipping_custom_label_3))
@php
$label_3 = $shipping_custom_label_3 . ':';
@endphp

<div class="col-md-4">
<div class="form-group">
{!! Form::label('shipping_custom_field_3', $label_3 ) !!}
{!! Form::text('shipping_custom_field_details[shipping_custom_field_3]',
!empty($contact->shipping_custom_field_details['shipping_custom_field_3']) ?
$contact->shipping_custom_field_details['shipping_custom_field_3'] : null, ['class' =>
'form-control','placeholder' => $shipping_custom_label_3]); !!}
</div>
</div>
@endif
@if(!empty($custom_labels['shipping']['is_custom_field_4_contact_default']) &&
!empty($shipping_custom_label_4))
@php
$label_4 = $shipping_custom_label_4 . ':';
@endphp

<div class="col-md-4">
<div class="form-group">
{!! Form::label('shipping_custom_field_4', $label_4 ) !!}
{!! Form::text('shipping_custom_field_details[shipping_custom_field_4]',
!empty($contact->shipping_custom_field_details['shipping_custom_field_4']) ?
$contact->shipping_custom_field_details['shipping_custom_field_4'] : null, ['class' =>
'form-control','placeholder' => $shipping_custom_label_4]); !!}
</div>
</div>
@endif
@if(!empty($custom_labels['shipping']['is_custom_field_5_contact_default']) &&
!empty($shipping_custom_label_5))
@php
$label_5 = $shipping_custom_label_5 . ':';
@endphp

<div class="col-md-4">
<div class="form-group">
{!! Form::label('shipping_custom_field_5', $label_5 ) !!}
{!! Form::text('shipping_custom_field_details[shipping_custom_field_5]',
!empty($contact->shipping_custom_field_details['shipping_custom_field_5']) ?
$contact->shipping_custom_field_details['shipping_custom_field_5'] : null, ['class' =>
'form-control','placeholder' => $shipping_custom_label_5]); !!}
</div>
</div>
@endif
@php
$common_settings = session()->get('business.common_settings');
@endphp
@if(!empty($common_settings['is_enabled_export']))
<div class="col-md-12 mb-12">
<div class="form-check">
<input type="checkbox" name="is_export" class="form-check-input" id="is_customer_export"
@if(!empty($contact->is_export)) checked @endif>
<label class="form-check-label" for="is_customer_export">@lang('lang_v1.is_export')</label>
</div>
</div>
@php
$i = 1;
@endphp
@for($i; $i <= 6 ; $i++)
<div class="col-md-4 export_div" style="display: none;">
<div class="form-group">
{!! Form::label('export_custom_field_'.$i, __('lang_v1.export_custom_field'.$i).':' ) !!}
{!! Form::text('export_custom_field_'.$i, !empty($contact['export_custom_field_'.$i]) ?
$contact['export_custom_field_'.$i] : null, ['class' => 'form-control','placeholder' =>
__('lang_v1.export_custom_field'.$i)]); !!}
</div>
</div>
@endfor
@endif
</div>
</div>
@include('layouts.partials.module_form_part')
</div>

<div class="modal-footer">
<button type="submit" class="tw-dw-btn tw-dw-btn-primary tw-text-white">@lang( 'messages.update' )</button>
<button type="button" class="tw-dw-btn tw-dw-btn-neutral tw-text-white" data-dismiss="modal">@lang(
'messages.close' )</button>
</div>

{!! Form::close() !!}

@else
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Error</h4>
</div>
<div class="modal-body">
<div class="alert alert-danger">
Contact data not available. Please try again.
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
@endif

</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->

Step 4: Update ContactController

Add modal handling to your existing edit method in app/Http/Controllers/ContactController.php:

public function edit($id)
{
if (! auth()->user()->can('supplier.update') && ! auth()->user()->can('customer.update') && ! auth()->user()->can('customer.view_own') && ! auth()->user()->can('supplier.view_own')) {
abort(403, 'Unauthorized action.');
}

if (request()->ajax()) {
$business_id = request()->session()->get('user.business_id');
$contact = Contact::where('business_id', $business_id)->with('userHavingAccess')->find($id);

// Check if contact exists
if (!$contact) {
if (request()->has('modal')) {
return response()->json([
'success' => false,
'msg' => 'Customer not found'
]);
}
abort(404, 'Contact not found');
}

if (! $this->moduleUtil->isSubscribed($business_id)) {
return $this->moduleUtil->expiredResponse();
}

$types = [];
if (auth()->user()->can('supplier.create')) {
$types['supplier'] = __('report.supplier');
}
if (auth()->user()->can('customer.create')) {
$types['customer'] = __('report.customer');
}
if (auth()->user()->can('supplier.create') && auth()->user()->can('customer.create')) {
$types['both'] = __('lang_v1.both_supplier_customer');
}

$customer_groups = CustomerGroup::forDropdown($business_id);

$ob_transaction = Transaction::where('contact_id', $id)
->where('type', 'opening_balance')
->first();
$opening_balance = ! empty($ob_transaction->final_total) ? $ob_transaction->final_total : 0;

//Deduct paid amount from opening balance.
if (! empty($opening_balance)) {
$opening_balance_paid = $this->transactionUtil->getTotalAmountPaid($ob_transaction->id);
if (! empty($opening_balance_paid)) {
$opening_balance = $opening_balance - $opening_balance_paid;
}

$opening_balance = $this->commonUtil->num_f($opening_balance);
}

//Added check because $users is of no use if enable_contact_assign if false
$users = config('constants.enable_contact_assign') ? User::forDropdown($business_id, false, false, false, true) : [];

// Check if this is a modal request
if (request()->has('modal')) {
try {
$view = view('contact.edit_customer_modal', compact('contact', 'types', 'customer_groups', 'opening_balance', 'users'))->render();
return response()->json([
'success' => true,
'html' => $view
]);
} catch (\Exception $e) {
\Log::error('Error loading edit customer modal: ' . $e->getMessage());
return response()->json([
'success' => false,
'msg' => 'Error loading customer data: ' . $e->getMessage()
]);
}
}

return view('contact.edit')
->with(compact('contact', 'types', 'customer_groups', 'opening_balance', 'users'));
}
}

Step 5: Add JavaScript to pos.js

Add this JavaScript code to the end of your public/js/pos.js file:

// Edit customer functionality - Add this to your pos.js file

// Edit customer button click handler
$(document).on('click', '.edit_customer', function () {
var customerId = $('#customer_id').val();
var defaultCustomerId = $('#default_customer_id').val();

// Basic validation
if (!customerId) {
toastr.error('Please select a customer to edit');
return;
}

// Prevent editing walk-in customer
if (defaultCustomerId && customerId === defaultCustomerId) {
toastr.error('Cannot edit walk-in customer');
return;
}

// Show modal with loading
$('.contact_edit_modal').html(
'<div class="modal-dialog modal-lg">' +
'<div class="modal-content">' +
'<div class="modal-body text-center">' +
'<i class="fa fa-spinner fa-spin fa-2x"></i><br>Loading customer data...' +
'</div></div></div>'
);
$('.contact_edit_modal').modal('show');

// Load customer data
$.get(base_path + '/contacts/' + customerId + '/edit?modal=1')
.done(function (result) {
if (result.success) {
$('.contact_edit_modal').html(result.html);
initializeEditCustomerForm();
} else {
toastr.error(result.msg || 'Error loading customer data');
$('.contact_edit_modal').modal('hide');
}
})
.fail(function () {
toastr.error('Error loading customer data');
$('.contact_edit_modal').modal('hide');
});
});

// Initialize edit customer form after loading
function initializeEditCustomerForm() {
// Initialize form validation (similar to existing quick_add_contact)
$('form#contact_edit_form').validate({
rules: {
contact_id: {
remote: {
url: '/contacts/check-contacts-id',
type: 'post',
data: {
contact_id: function () {
return $('form#contact_edit_form')
.find('#contact_id')
.val();
},
hidden_id: function () {
return (
$('form#contact_edit_form')
.find('#hidden_id')
.val() || ''
);
},
},
},
},
},
messages: {
contact_id: {
remote: LANG.contact_id_already_exists,
},
},
submitHandler: function (form) {
submitEditCustomerForm(form);
},
});

// Initialize select2 if exists
if ($('.contact_edit_modal .select2').length) {
$('.contact_edit_modal .select2').select2({
dropdownParent: $('.contact_edit_modal'),
});
}

// Handle contact type radio buttons
$('.contact_edit_modal input[name="contact_type_radio"]').change(
function () {
var contactType = $(this).val();
if (contactType === 'individual') {
$('.contact_edit_modal .individual').show();
$('.contact_edit_modal .business').hide();
} else {
$('.contact_edit_modal .individual').hide();
$('.contact_edit_modal .business').show();
}
}
);

// Handle more info button
$('.contact_edit_modal .more_btn').click(function () {
var target = $(this).data('target');
$('.contact_edit_modal ' + target).removeClass('hide');
$(this).hide();
});
}

// Submit edit customer form (similar to existing submitQuickContactForm)
function submitEditCustomerForm(form) {
var data = $(form).serialize();
$.ajax({
method: 'PUT',
url: $(form).attr('action'),
dataType: 'json',
data: data,
beforeSend: function (xhr) {
__disable_submit_button($(form).find('button[type="submit"]'));
},
success: function (result) {
if (result.success == true) {
var name = result.data.name;
if (result.data.supplier_business_name) {
name += ' - ' + result.data.supplier_business_name;
}

// Update the select option text (similar to existing functionality)
$(
'select#customer_id option[value="' + result.data.id + '"]'
).text(name);

// Trigger change to update all related data
$('select#customer_id').trigger('change');

$('.contact_edit_modal').modal('hide');
toastr.success(result.msg);

// Update shipping address (reuse existing function)
update_shipping_address(result.data);
} else {
toastr.error(result.msg);
}
},
error: function () {
toastr.error('Error updating customer');
},
complete: function () {
$(form).find('button[type="submit"]').removeAttr('disabled');
},
});
}

// Handle edit modal close (similar to existing contact_modal)
$('.contact_edit_modal').on('hidden.bs.modal', function () {
$('form#contact_edit_form')
.find('button[type="submit"]')
.removeAttr('disabled');
});

Verification Steps

After implementation, verify that:

  1. Edit button appears next to the add customer button
  2. Button is disabled for users without customer.update permission
  3. Click validation works - shows error if no customer selected
  4. Walk-in customer protection - cannot edit default customer
  5. Modal loads correctly with customer data
  6. Form validation works including contact ID uniqueness
  7. Customer dropdown updates after successful edit
  8. Shipping address updates automatically

Troubleshooting

Common Issues

Issue: Edit button not appearing

Solution: Check that you have the correct permissions and the button HTML is properly placed.

Issue: Modal shows "Contact data not available"

Solution: Verify that the ContactController::edit method includes the modal handling code and the route exists.

Issue: Customer dropdown not updating after edit

Solution: Ensure the success callback includes $('select#customer_id').trigger('change');

Issue: Form validation not working

Solution: Check that all required JavaScript libraries (jQuery Validation) are loaded.

Debugging Steps

  1. Check browser console for JavaScript errors
  2. Check Laravel logs in storage/logs/laravel.log
  3. Verify route exists using php artisan route:list | grep contacts
  4. Test direct URL access to /contacts/{id}/edit?modal=1

Security Considerations

  • ✅ Permission checks prevent unauthorized access
  • ✅ Walk-in customer protection prevents editing system default
  • ✅ CSRF protection through Laravel forms
  • ✅ Input validation and sanitization
  • ✅ Business ID isolation prevents cross-tenant data access

Performance Notes

  • Modal content loads only when needed (AJAX)
  • Reuses existing validation and utility functions
  • Minimal impact on page load time
  • Efficient customer dropdown updates

Customization Options

Adding Custom Fields

To add custom fields to the edit modal, modify the edit_customer_modal.blade.php template and add the corresponding fields.

Changing Button Icons

Update the <i> tag class in the button HTML:

<i class="fa fa-pencil text-warning fa-lg"></i>
<!-- Alternative edit icon -->

Custom Validation Rules

Add validation rules in the initializeEditCustomerForm() function:

rules: {
mobile: {
required: true,
minlength: 10
}
}

Conclusion

This implementation provides a seamless edit customer experience that integrates perfectly with Ultimate POS's existing functionality while maintaining security, performance, and user experience standards.

💬 Discussion & Questions

Please sign in to join the discussion.

Loading comments...

💛 Support this project

Binance ID:

478036326
Premium Login