// ---------------- Connector Documents ----------------
function fino_lm_user_has_lead_access($lead_id, $user_id){
global $wpdb;
$leads_table = $wpdb->prefix . 'fino_leads';
$lead = $wpdb->get_row($wpdb->prepare("SELECT * FROM $leads_table WHERE id=%d", $lead_id));
if(!$lead) return false;
if(current_user_can('manager') || current_user_can('submanager') || current_user_can('administrator')){
return true;
}
if(current_user_can('connector')){
return intval($lead->created_by) === intval($user_id);
}
if(current_user_can('employee')){
return intval($lead->assigned_employee_id) === intval($user_id);
}
if(current_user_can('banker')){
return intval($lead->assigned_banker_id) === intval($user_id);
}
return false;
}
function fino_lm_handle_doc_upload(){
if(!is_user_logged_in()) wp_die('Not logged in');
if(!(current_user_can('connector') || current_user_can('employee') || current_user_can('banker'))) wp_die('Access denied');
check_admin_referer('fino_doc_upload');
$lead_id = isset($_POST['lead_id']) ? intval($_POST['lead_id']) : 0;
$doc_type = isset($_POST['doc_type']) ? sanitize_text_field($_POST['doc_type']) : '';
$notes = isset($_POST['notes']) ? sanitize_textarea_field($_POST['notes']) : '';
if(!$lead_id || !$doc_type){
wp_redirect(add_query_arg(['fino_msg'=>'missing'], wp_get_referer()));
exit;
}
$user_id = get_current_user_id();
if(!fino_lm_user_has_lead_access($lead_id, $user_id)){
wp_redirect(add_query_arg(['fino_msg'=>'noaccess'], wp_get_referer()));
exit;
}
if(empty($_FILES['lead_document']['name'])){
wp_redirect(add_query_arg(['fino_msg'=>'nofile'], wp_get_referer()));
exit;
}
require_once ABSPATH . 'wp-admin/includes/file.php';
$allowed = ['application/pdf','image/jpeg','image/png'];
$filetype = wp_check_filetype_and_ext($_FILES['lead_document']['tmp_name'], $_FILES['lead_document']['name']);
if(!$filetype['type'] || !in_array($filetype['type'], $allowed)){
wp_redirect(add_query_arg(['fino_msg'=>'badtype'], wp_get_referer()));
exit;
}
$upload = wp_handle_upload($_FILES['lead_document'], ['test_form' => false]);
if(isset($upload['error'])){
wp_redirect(add_query_arg(['fino_msg'=>'uploaderr'], wp_get_referer()));
exit;
}
global $wpdb;
$docs_table = $wpdb->prefix . 'fino_lead_documents';
$wpdb->insert($docs_table, [
'lead_id' => $lead_id,
'uploaded_by' => $user_id,
'uploaded_role' => (current_user_can('employee') ? 'employee' : (current_user_can('banker') ? 'banker' : 'connector')),
'doc_type' => $doc_type,
'file_url' => $upload['url'],
'file_name' => basename($upload['file']),
'notes' => $notes,
'status' => 'pending'
]);
wp_redirect(add_query_arg(['fino_msg'=>'uploaded'], remove_query_arg('fino_msg', wp_get_referer())));
exit;
}
add_action('admin_post_fino_doc_upload', 'fino_lm_handle_doc_upload');
add_action('admin_post_nopriv_fino_doc_upload', 'fino_lm_handle_doc_upload');
add_shortcode('fino_connector_upload_docs', function(){
if(!is_user_logged_in()) return '
Please login.
';
if(!(current_user_can('connector') || current_user_can('employee') || current_user_can('banker'))) return 'Access denied.
';
$msg = isset($_GET['fino_msg']) ? sanitize_text_field($_GET['fino_msg']) : '';
$notice = '';
if($msg==='uploaded') $notice = 'Document uploaded successfully.
';
if($msg==='missing') $notice = 'Please fill Lead ID and Document Type.
';
if($msg==='nofile') $notice = 'Please choose a file.
';
if($msg==='badtype') $notice = 'Invalid file type. Allowed: PDF, JPG, PNG.
';
if($msg==='noaccess') $notice = 'You can upload documents only for your own leads.
';
$action = esc_url(admin_url('admin-post.php'));
$nonce = wp_nonce_field('fino_doc_upload','_wpnonce', true, false);
return $notice . '
';
});
add_shortcode('fino_connector_docs_history', function(){
if(!is_user_logged_in()) return 'Please login.
';
if(!(current_user_can('connector') || current_user_can('employee') || current_user_can('banker'))) return 'Access denied.
';
global $wpdb;
$docs_table = $wpdb->prefix . 'fino_lead_documents';
$user_id = get_current_user_id();
$rows = $wpdb->get_results($wpdb->prepare("SELECT * FROM $docs_table WHERE uploaded_by=%d ORDER BY id DESC LIMIT 50", $user_id));
if(!$rows) return 'No documents uploaded yet.
';
$out = 'Lead ID Doc Type File Status Date ';
foreach($rows as $r){
$file = esc_url($r->file_url);
$out .= '
#'.intval($r->lead_id).'
'.esc_html($r->doc_type).'
View
'.esc_html(strtoupper($r->status)).'
'.esc_html($r->created_at).'
';
}
$out .= '
';
return $out;
});
add_shortcode('fino_connector_my_leads', function(){
if(!is_user_logged_in()) return 'Please login.
';
if(!(current_user_can('connector') || current_user_can('employee') || current_user_can('banker'))) return 'Access denied.
';
global $wpdb;
$leads_table = $wpdb->prefix . 'fino_leads';
$user_id = get_current_user_id();
$rows = $wpdb->get_results($wpdb->prepare("SELECT * FROM $leads_table WHERE created_by=%d ORDER BY id DESC LIMIT 50", $user_id));
if(!$rows) return 'No leads found.
';
$base = get_permalink(); // current dashboard page
$out = 'Lead ID Loan Amount City Status Documents ';
foreach($rows as $r){
$lead_id = intval($r->id);
$url = add_query_arg(['lead_id'=>$lead_id], $base) . '#uploadDocs';
$out .= '
#'.$lead_id.'
'.esc_html($r->loan_type).'
INR '.number_format_i18n(floatval($r->loan_amount)).'
'.esc_html($r->city).'
'.esc_html(strtoupper($r->status)).'
Upload Documents
';
}
$out .= '
';
return $out;
});
add_shortcode('fino_employee_assigned_leads', function(){
if(!is_user_logged_in()) return 'Please login.
';
if(!current_user_can('employee')) return 'Access denied.
';
global $wpdb;
$leads_table = $wpdb->prefix . 'fino_leads';
$user_id = get_current_user_id();
$rows = $wpdb->get_results($wpdb->prepare("SELECT * FROM $leads_table WHERE assigned_employee_id=%d ORDER BY id DESC LIMIT 50", $user_id));
if(!$rows) return 'No assigned leads found.
';
$base = get_permalink();
$out = 'Lead ID Name Mobile Loan Amount Status Documents ';
foreach($rows as $r){
$lead_id = intval($r->id);
$url = add_query_arg(['lead_id'=>$lead_id], $base) . '#uploadDocs';
$out .= '
#'.$lead_id.'
'.esc_html($r->name).'
'.esc_html($r->mobile).'
'.esc_html($r->loan_type).'
INR '.number_format_i18n(floatval($r->loan_amount)).'
'.esc_html(strtoupper($r->status)).'
Upload Documents
';
}
$out .= '
';
return $out;
});
add_shortcode('fino_banker_assigned_leads_v2', function(){
if(!is_user_logged_in()) return 'Please login.
';
if(!current_user_can('banker')) return 'Access denied.
';
global $wpdb;
$leads_table = $wpdb->prefix . 'fino_leads';
$user_id = get_current_user_id();
$rows = $wpdb->get_results($wpdb->prepare("SELECT * FROM $leads_table WHERE assigned_banker_id=%d ORDER BY id DESC LIMIT 50", $user_id));
if(!$rows) return 'No assigned leads found.
';
$base = get_permalink();
$out = 'Lead ID Name Mobile Loan Amount Status Documents ';
foreach($rows as $r){
$lead_id = intval($r->id);
$url = add_query_arg(['lead_id'=>$lead_id], $base) . '#uploadDocs';
$out .= '
#'.$lead_id.'
'.esc_html($r->name).'
'.esc_html($r->mobile).'
'.esc_html($r->loan_type).'
INR '.number_format_i18n(floatval($r->loan_amount)).'
'.esc_html(strtoupper($r->status)).'
Upload Documents
';
}
$out .= '
';
return $out;
});
function fino_lm_handle_doc_status_update(){
if(!is_user_logged_in()) wp_die('Not logged in');
if(!(current_user_can('manager') || current_user_can('submanager') || current_user_can('administrator'))) wp_die('Access denied');
check_admin_referer('fino_doc_status');
$doc_id = isset($_POST['doc_id']) ? intval($_POST['doc_id']) : 0;
$new_status = isset($_POST['new_status']) ? sanitize_text_field($_POST['new_status']) : '';
if(!$doc_id || !in_array($new_status, ['verified','rejected'], true)){
wp_redirect(add_query_arg(['fino_doc_msg'=>'invalid'], wp_get_referer()));
exit;
}
global $wpdb;
$docs_table = $wpdb->prefix . 'fino_lead_documents';
$wpdb->update($docs_table, ['status'=>$new_status], ['id'=>$doc_id]);
$doc = $wpdb->get_row($wpdb->prepare("SELECT * FROM $docs_table WHERE id=%d", $doc_id));
if($doc){
$title = ($new_status==='verified') ? 'Document Approved' : 'Document Rejected';
$msg = 'Lead #'.intval($doc->lead_id).' • '.sanitize_text_field($doc->doc_type);
fino_lm_add_notification(intval($doc->uploaded_by), $title, $msg, '');
}
wp_redirect(add_query_arg(['fino_doc_msg'=>'updated'], remove_query_arg('fino_doc_msg', wp_get_referer())));
exit;
}
add_action('admin_post_fino_doc_status_update', 'fino_lm_handle_doc_status_update');
add_shortcode('fino_manager_documents_review', function(){
if(!is_user_logged_in()) return 'Please login.
';
if(!(current_user_can('manager') || current_user_can('submanager') || current_user_can('administrator'))) return 'Access denied.
';
$msg = isset($_GET['fino_doc_msg']) ? sanitize_text_field($_GET['fino_doc_msg']) : '';
$notice = '';
if($msg==='updated') $notice = 'Document status updated.
';
if($msg==='invalid') $notice = 'Invalid request.
';
$filter_lead = isset($_GET['fino_lead_id']) ? intval($_GET['fino_lead_id']) : 0;
$filter_status = isset($_GET['fino_status']) ? sanitize_text_field($_GET['fino_status']) : '';
$filter_role = isset($_GET['fino_role']) ? sanitize_text_field($_GET['fino_role']) : '';
$allowed_status = ['pending','verified','rejected'];
$allowed_roles = ['connector','employee','banker'];
global $wpdb;
$docs_table = $wpdb->prefix . 'fino_lead_documents';
$where = "1=1";
$params = [];
if($filter_lead > 0){
$where .= " AND lead_id=%d";
$params[] = $filter_lead;
}
if($filter_status && in_array($filter_status, $allowed_status, true)){
$where .= " AND status=%s";
$params[] = $filter_status;
}
if($filter_role && in_array($filter_role, $allowed_roles, true)){
$where .= " AND uploaded_role=%s";
$params[] = $filter_role;
}
$sql = "SELECT * FROM $docs_table WHERE $where ORDER BY id DESC LIMIT 120";
$rows = $params ? $wpdb->get_results($wpdb->prepare($sql, $params)) : $wpdb->get_results($sql);
$base = esc_url(remove_query_arg(['fino_lead_id','fino_status','fino_role'], get_permalink()));
$form = '
Lead ID
Status
All
Pending
Verified
Rejected
Uploaded Role
All
Connector
Employee
Banker
';
if(!$rows) return $notice . $form . 'No documents found for selected filters.
';
$action = esc_url(admin_url('admin-post.php'));
$out = $notice . $form . 'Doc ID Lead ID Type File Uploaded By Status Action Date ';
foreach($rows as $r){
$doc_id = intval($r->id);
$file = esc_url($r->file_url);
$status = esc_html(strtoupper($r->status));
$badge = $r->status==='verified' ? 'appv' : ($r->status==='rejected' ? 'rej' : 'proc');
$approve = wp_nonce_field('fino_doc_status','_wpnonce', true, false);
$reject = $approve;
$approveBtn = '
'.$approve.'
Approve
';
$rejectBtn = '
'.$reject.'
Reject
';
$out .= '
#'.$doc_id.'
#'.intval($r->lead_id).'
'.esc_html($r->doc_type).'
View
'.esc_html($r->uploaded_role).' • #'.intval($r->uploaded_by).'
'.$status.'
'.$approveBtn.$rejectBtn.'
'.esc_html($r->created_at).'
';
}
$out .= '
';
return $out;
});
// ---------------- Profile Photo Upload (All Roles) ----------------
function fino_lm_handle_profile_photo_upload(){
if(!is_user_logged_in()) wp_die('Not logged in');
check_admin_referer('fino_profile_photo');
if(empty($_FILES['profile_photo']['name'])){
wp_redirect(add_query_arg(['fino_pmsg'=>'nofile'], wp_get_referer()));
exit;
}
// Validate type + size (2MB)
$allowed = ['image/jpeg','image/png'];
$max_bytes = 2 * 1024 * 1024;
if($_FILES['profile_photo']['size'] > $max_bytes){
wp_redirect(add_query_arg(['fino_pmsg'=>'toolarge'], wp_get_referer()));
exit;
}
$filetype = wp_check_filetype_and_ext($_FILES['profile_photo']['tmp_name'], $_FILES['profile_photo']['name']);
if(!$filetype['type'] || !in_array($filetype['type'], $allowed, true)){
wp_redirect(add_query_arg(['fino_pmsg'=>'badtype'], wp_get_referer()));
exit;
}
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
$upload = wp_handle_upload($_FILES['profile_photo'], ['test_form' => false]);
if(isset($upload['error'])){
wp_redirect(add_query_arg(['fino_pmsg'=>'uploaderr'], wp_get_referer()));
exit;
}
$attachment = [
'post_mime_type' => $upload['type'],
'post_title' => sanitize_file_name(basename($upload['file'])),
'post_content' => '',
'post_status' => 'inherit'
];
$attach_id = wp_insert_attachment($attachment, $upload['file']);
$attach_data = wp_generate_attachment_metadata($attach_id, $upload['file']);
wp_update_attachment_metadata($attach_id, $attach_data);
$user_id = get_current_user_id();
update_user_meta($user_id, 'fino_profile_photo_id', $attach_id);
wp_redirect(add_query_arg(['fino_pmsg'=>'updated'], remove_query_arg('fino_pmsg', wp_get_referer())));
exit;
}
add_action('admin_post_fino_profile_photo_upload', 'fino_lm_handle_profile_photo_upload');
function fino_lm_get_profile_photo_url($user_id){
$id = intval(get_user_meta($user_id, 'fino_profile_photo_id', true));
if($id){
$url = wp_get_attachment_image_url($id, 'thumbnail');
if($url) return $url;
}
return '';
}
add_shortcode('fino_profile_photo_uploader', function(){
if(!is_user_logged_in()) return '';
$user_id = get_current_user_id();
$user = wp_get_current_user();
$msg = isset($_GET['fino_pmsg']) ? sanitize_text_field($_GET['fino_pmsg']) : '';
$notice = '';
if($msg==='updated') $notice = 'Profile photo updated.
';
if($msg==='nofile') $notice = 'Please choose a photo.
';
if($msg==='toolarge') $notice = 'File too large. Max 2MB.
';
if($msg==='badtype') $notice = 'Invalid type. Only JPG/PNG allowed.
';
if($msg==='uploaderr') $notice = 'Upload failed. Try again.
';
$photo = fino_lm_get_profile_photo_url($user_id);
$photo_html = $photo ? ' ' :
'U
';
$action = esc_url(admin_url('admin-post.php'));
$nonce = wp_nonce_field('fino_profile_photo','_wpnonce', true, false);
return $notice . '
'.$photo_html.'
'.esc_html($user->display_name).'
'.esc_html($user->user_email).'
'.$nonce.'
Upload Profile Photo (JPG/PNG, Max 2MB)
Update Photo
';
});
// ---------------- Notifications ----------------
function fino_lm_add_notification($user_id, $title, $message='', $link=''){
global $wpdb;
$table = $wpdb->prefix . 'fino_notifications';
$wpdb->insert($table, [
'user_id' => intval($user_id),
'title' => sanitize_text_field($title),
'message' => sanitize_textarea_field($message),
'link' => esc_url_raw($link),
'is_read' => 0
]);
}
function fino_lm_get_unread_count($user_id){
global $wpdb;
$table = $wpdb->prefix . 'fino_notifications';
return intval($wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $table WHERE user_id=%d AND is_read=0", $user_id)));
}
function fino_lm_mark_all_read(){
if(!is_user_logged_in()) wp_die('Not logged in');
check_admin_referer('fino_mark_read');
global $wpdb;
$table = $wpdb->prefix . 'fino_notifications';
$wpdb->update($table, ['is_read'=>1], ['user_id'=>get_current_user_id()]);
wp_redirect(remove_query_arg(['fino_nmsg'], wp_get_referer()));
exit;
}
add_action('admin_post_fino_mark_all_read', 'fino_lm_mark_all_read');
add_shortcode('fino_notifications_count', function(){
if(!is_user_logged_in()) return '0';
return strval(fino_lm_get_unread_count(get_current_user_id()));
});
add_shortcode('fino_notifications_list', function(){
if(!is_user_logged_in()) return '';
global $wpdb;
$table = $wpdb->prefix . 'fino_notifications';
$user_id = get_current_user_id();
$rows = $wpdb->get_results($wpdb->prepare("SELECT * FROM $table WHERE user_id=%d ORDER BY id DESC LIMIT 10", $user_id));
$action = esc_url(admin_url('admin-post.php'));
$nonce = wp_nonce_field('fino_mark_read','_wpnonce', true, false);
$out = '
Notifications
'.$nonce.'
Mark all read
';
if(!$rows){
return $out . 'No notifications
';
}
foreach($rows as $r){
$dot = intval($r->is_read)===0 ? ' ' : ' ';
$link = $r->link ? esc_url($r->link) : '#';
$out .= '
'.$dot.'
'.esc_html($r->title).'
'.esc_html($r->message).'
'.esc_html($r->created_at).'
';
$out .= '
';
}
return $out;
});
function fino_lm_notify_lead_assigned($lead_id, $assignee_user_id, $assignee_role){
$title = 'New Lead Assigned';
$message = 'Lead #'.intval($lead_id).' assigned to you ('.sanitize_text_field($assignee_role).')';
fino_lm_add_notification(intval($assignee_user_id), $title, $message, '');
}